@skeletonlabs/skeleton-svelte 1.0.0-next.8 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/components/Accordion/Accordion.svelte +49 -52
- package/dist/components/Accordion/Accordion.svelte.d.ts +2 -14
- package/dist/components/Accordion/AccordionItem.svelte +43 -37
- package/dist/components/Accordion/AccordionItem.svelte.d.ts +2 -14
- package/dist/components/Accordion/context.js +2 -1
- package/dist/components/Accordion/index.d.ts +4 -0
- package/dist/components/Accordion/index.js +1 -1
- package/dist/components/Accordion/types.d.ts +7 -9
- package/dist/components/AppBar/AppBar.svelte +43 -40
- package/dist/components/AppBar/AppBar.svelte.d.ts +2 -14
- package/dist/components/Avatar/Avatar.svelte +56 -44
- package/dist/components/Avatar/Avatar.svelte.d.ts +2 -14
- package/dist/components/Avatar/types.d.ts +3 -3
- package/dist/components/Combobox/Combobox.svelte +144 -0
- package/dist/components/Combobox/Combobox.svelte.d.ts +18 -0
- package/dist/components/Combobox/types.d.ts +64 -0
- package/dist/components/Combobox/types.js +1 -0
- package/dist/components/FileUpload/FileUpload.svelte +70 -63
- package/dist/components/FileUpload/FileUpload.svelte.d.ts +2 -14
- package/dist/components/FileUpload/types.d.ts +3 -4
- package/dist/components/Modal/Modal.svelte +87 -0
- package/dist/components/Modal/Modal.svelte.d.ts +4 -0
- package/dist/components/Modal/types.d.ts +57 -0
- package/dist/components/Modal/types.js +1 -0
- package/dist/components/Navigation/NavBar.svelte +48 -0
- package/dist/components/Navigation/NavBar.svelte.d.ts +5 -0
- package/dist/components/Navigation/NavRail.svelte +90 -0
- package/dist/components/Navigation/NavRail.svelte.d.ts +5 -0
- package/dist/components/Navigation/NavTile.svelte +87 -0
- package/dist/components/Navigation/NavTile.svelte.d.ts +5 -0
- package/dist/components/Navigation/context.js +7 -0
- package/dist/components/Navigation/index.d.ts +6 -0
- package/dist/components/{Nav → Navigation}/index.js +1 -1
- package/dist/components/{Nav → Navigation}/types.d.ts +5 -3
- package/dist/components/Pagination/Pagination.svelte +58 -67
- package/dist/components/Pagination/Pagination.svelte.d.ts +2 -14
- package/dist/components/Pagination/types.d.ts +15 -15
- package/dist/components/Popover/Popover.svelte +78 -0
- package/dist/components/Popover/Popover.svelte.d.ts +4 -0
- package/dist/components/Popover/types.d.ts +42 -0
- package/dist/components/Popover/types.js +1 -0
- package/dist/components/Progress/Progress.svelte +44 -38
- package/dist/components/Progress/Progress.svelte.d.ts +2 -14
- package/dist/components/Progress/types.d.ts +1 -1
- package/dist/components/ProgressRing/ProgressRing.svelte +58 -46
- package/dist/components/ProgressRing/ProgressRing.svelte.d.ts +2 -14
- package/dist/components/ProgressRing/types.d.ts +3 -1
- package/dist/components/Rating/Rating.svelte +101 -57
- package/dist/components/Rating/Rating.svelte.d.ts +2 -14
- package/dist/components/Rating/types.d.ts +1 -5
- package/dist/components/Segment/Segment.svelte +59 -67
- package/dist/components/Segment/Segment.svelte.d.ts +3 -15
- package/dist/components/Segment/SegmentItem.svelte +28 -21
- package/dist/components/Segment/SegmentItem.svelte.d.ts +2 -14
- package/dist/components/Segment/context.js +3 -2
- package/dist/components/Segment/index.d.ts +4 -0
- package/dist/components/Segment/index.js +1 -1
- package/dist/components/Segment/types.d.ts +8 -10
- package/dist/components/Slider/Slider.svelte +67 -72
- package/dist/components/Slider/Slider.svelte.d.ts +2 -14
- package/dist/components/Slider/types.d.ts +5 -9
- package/dist/components/Switch/Switch.svelte +75 -90
- package/dist/components/Switch/Switch.svelte.d.ts +2 -14
- package/dist/components/Switch/types.d.ts +2 -8
- package/dist/components/Tabs/Tabs.svelte +59 -0
- package/dist/components/Tabs/Tabs.svelte.d.ts +5 -0
- package/dist/components/Tabs/TabsControl.svelte +51 -0
- package/dist/components/Tabs/TabsControl.svelte.d.ts +5 -0
- package/dist/components/Tabs/TabsPanel.svelte +23 -0
- package/dist/components/Tabs/TabsPanel.svelte.d.ts +5 -0
- package/dist/components/{Tab → Tabs}/context.js +3 -2
- package/dist/components/Tabs/index.d.ts +5 -0
- package/dist/components/{Tab → Tabs}/index.js +1 -1
- package/dist/components/{Tab → Tabs}/types.d.ts +1 -3
- package/dist/components/TagsInput/TagsInput.svelte +48 -54
- package/dist/components/TagsInput/TagsInput.svelte.d.ts +2 -14
- package/dist/components/TagsInput/types.d.ts +3 -7
- package/dist/components/Toast/ToastProvider.svelte +133 -0
- package/dist/components/Toast/ToastProvider.svelte.d.ts +4 -0
- package/dist/components/Toast/types.d.ts +87 -0
- package/dist/components/Tooltip/Tooltip.svelte +79 -0
- package/dist/components/Tooltip/Tooltip.svelte.d.ts +4 -0
- package/dist/components/Tooltip/types.d.ts +44 -0
- package/dist/components/Tooltip/types.js +1 -0
- package/dist/index.d.ts +8 -2
- package/dist/index.js +11 -2
- package/dist/internal/create-context.d.ts +6 -0
- package/dist/internal/create-context.js +3 -3
- package/dist/internal/test-utils.d.ts +3 -0
- package/dist/internal/test-utils.js +9 -0
- package/package.json +43 -54
- package/dist/components/Accordion/Accordion.svelte.spec.js +0 -4
- package/dist/components/Nav/NavBar.svelte +0 -45
- package/dist/components/Nav/NavBar.svelte.d.ts +0 -17
- package/dist/components/Nav/NavRail.svelte +0 -79
- package/dist/components/Nav/NavRail.svelte.d.ts +0 -17
- package/dist/components/Nav/NavTile.svelte +0 -76
- package/dist/components/Nav/NavTile.svelte.d.ts +0 -17
- package/dist/components/Nav/context.js +0 -7
- package/dist/components/Tab/Tabs.svelte +0 -65
- package/dist/components/Tab/Tabs.svelte.d.ts +0 -17
- package/dist/components/Tab/TabsControl.svelte +0 -42
- package/dist/components/Tab/TabsControl.svelte.d.ts +0 -17
- package/dist/components/Tab/TabsPanel.svelte +0 -18
- package/dist/components/Tab/TabsPanel.svelte.d.ts +0 -17
- package/dist/internal/noop.d.ts +0 -1
- package/dist/internal/noop.js +0 -2
- package/dist/internal/snippets.d.ts +0 -3
- package/dist/internal/snippets.js +0 -45
- package/dist/internal/use-id.d.ts +0 -2
- package/dist/internal/use-id.js +0 -5
- /package/dist/components/{Nav → Navigation}/context.d.ts +0 -0
- /package/dist/components/{Nav → Navigation}/types.js +0 -0
- /package/dist/components/{Tab → Tabs}/context.d.ts +0 -0
- /package/dist/components/{Tab → Tabs}/types.js +0 -0
- /package/dist/components/{Accordion/Accordion.svelte.spec.d.ts → Toast/types.js} +0 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import * as tabs from '@zag-js/tabs';
|
|
3
|
+
import { useMachine, normalizeProps } from '@zag-js/svelte';
|
|
4
|
+
import type { TabsProps } from './types.js';
|
|
5
|
+
import { setTabContext } from './context.js';
|
|
6
|
+
|
|
7
|
+
const {
|
|
8
|
+
fluid = false,
|
|
9
|
+
// Root
|
|
10
|
+
base = 'w-full',
|
|
11
|
+
classes = '',
|
|
12
|
+
// List
|
|
13
|
+
listBase = 'flex',
|
|
14
|
+
listJustify = 'justify-start',
|
|
15
|
+
listBorder = 'border-b-[1px] border-surface-200-800',
|
|
16
|
+
listMargin = 'mb-4',
|
|
17
|
+
listGap = 'gap-2',
|
|
18
|
+
listClasses = '',
|
|
19
|
+
// Content
|
|
20
|
+
contentBase = '',
|
|
21
|
+
contentClasses = '',
|
|
22
|
+
// Snippets
|
|
23
|
+
list,
|
|
24
|
+
content,
|
|
25
|
+
// Zag
|
|
26
|
+
...zagProps
|
|
27
|
+
}: TabsProps = $props();
|
|
28
|
+
|
|
29
|
+
// Zag
|
|
30
|
+
const id = $props.id();
|
|
31
|
+
const service = useMachine(tabs.machine, () => ({
|
|
32
|
+
id: id,
|
|
33
|
+
...zagProps
|
|
34
|
+
}));
|
|
35
|
+
const api = $derived(tabs.connect(service, normalizeProps));
|
|
36
|
+
|
|
37
|
+
// Set Context
|
|
38
|
+
setTabContext({
|
|
39
|
+
get api() {
|
|
40
|
+
return api;
|
|
41
|
+
},
|
|
42
|
+
get fluid() {
|
|
43
|
+
return fluid;
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
</script>
|
|
47
|
+
|
|
48
|
+
<!-- @component Use tabs to quickly switch between different views and pages. -->
|
|
49
|
+
|
|
50
|
+
<div {...api.getRootProps()} class="{base} {classes}" data-testid="tabs">
|
|
51
|
+
<!-- List -->
|
|
52
|
+
<div {...api.getListProps()} class="{listBase} {listJustify} {listBorder} {listMargin} {listGap} {listClasses}" data-testid="tabs-list">
|
|
53
|
+
{@render list?.()}
|
|
54
|
+
</div>
|
|
55
|
+
<!-- Content -->
|
|
56
|
+
<div class="{contentBase} {contentClasses}" data-testid="tabs-content">
|
|
57
|
+
{@render content?.()}
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { getTabContext } from './context.js';
|
|
3
|
+
import type { TabsControlProps } from './types.js';
|
|
4
|
+
|
|
5
|
+
const {
|
|
6
|
+
// Root
|
|
7
|
+
base = 'border-b-[1px] border-transparent',
|
|
8
|
+
padding = 'pb-2',
|
|
9
|
+
translateX = 'translate-y-[1px]',
|
|
10
|
+
classes = '',
|
|
11
|
+
// Label
|
|
12
|
+
labelBase = 'btn hover:preset-tonal-primary',
|
|
13
|
+
labelClasses = '',
|
|
14
|
+
// State
|
|
15
|
+
stateInactive = '[&:not(:hover)]:opacity-50',
|
|
16
|
+
stateActive = 'border-b-surface-950-50 opacity-100',
|
|
17
|
+
stateLabelInactive = '',
|
|
18
|
+
stateLabelActive = '',
|
|
19
|
+
// Snippets
|
|
20
|
+
lead,
|
|
21
|
+
children,
|
|
22
|
+
// Zag
|
|
23
|
+
...zagProps
|
|
24
|
+
}: TabsControlProps = $props();
|
|
25
|
+
|
|
26
|
+
// Get Context
|
|
27
|
+
const ctx = getTabContext();
|
|
28
|
+
const state = $derived(ctx.api.getTriggerState(zagProps));
|
|
29
|
+
|
|
30
|
+
// Reactive
|
|
31
|
+
const rxActive = $derived(state.selected ? stateActive : stateInactive);
|
|
32
|
+
const rxLabelActive = $derived(state.selected ? stateLabelActive : stateLabelInactive);
|
|
33
|
+
|
|
34
|
+
// Styles
|
|
35
|
+
const commonWidth = $derived(ctx.fluid ? '100%' : '');
|
|
36
|
+
</script>
|
|
37
|
+
|
|
38
|
+
<!-- @component A individual tab trigger element. -->
|
|
39
|
+
|
|
40
|
+
<button
|
|
41
|
+
{...ctx.api.getTriggerProps(zagProps)}
|
|
42
|
+
class="{base} {padding} {translateX} {rxActive} {classes}"
|
|
43
|
+
style:width={commonWidth}
|
|
44
|
+
data-testid="tabs-control"
|
|
45
|
+
>
|
|
46
|
+
<!-- Label -->
|
|
47
|
+
<div class="{labelBase} {rxLabelActive} {labelClasses}" style:width={commonWidth} data-testid="tabs-control-label">
|
|
48
|
+
{#if lead}<span>{@render lead()}</span>{/if}
|
|
49
|
+
<span>{@render children?.()}</span>
|
|
50
|
+
</div>
|
|
51
|
+
</button>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { getTabContext } from './context.js';
|
|
3
|
+
import type { TabsPanelProps } from './types.js';
|
|
4
|
+
|
|
5
|
+
const {
|
|
6
|
+
// Root
|
|
7
|
+
base = '',
|
|
8
|
+
classes = '',
|
|
9
|
+
// Children
|
|
10
|
+
children,
|
|
11
|
+
// Zag
|
|
12
|
+
...zagProps
|
|
13
|
+
}: TabsPanelProps = $props();
|
|
14
|
+
|
|
15
|
+
// Get Context
|
|
16
|
+
const ctx = getTabContext();
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<!-- @component A individual tab panel of content. -->
|
|
20
|
+
|
|
21
|
+
<div {...ctx.api.getContentProps(zagProps)} class="{base} {classes}" data-testid="tabs-panel">
|
|
22
|
+
{@render children?.()}
|
|
23
|
+
</div>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
var _a;
|
|
1
2
|
import * as tabs from '@zag-js/tabs';
|
|
2
3
|
import { createContext } from '../../internal/create-context.js';
|
|
3
|
-
export
|
|
4
|
+
export var setTabContext = (_a = createContext({
|
|
4
5
|
fluid: false,
|
|
5
6
|
api: {}
|
|
6
|
-
});
|
|
7
|
+
}), _a[0]), getTabContext = _a[1], key = _a[2];
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
declare const _default: import("svelte").Component<import("./types").TabsProps, {}, ""> & {
|
|
2
|
+
Control: import("svelte").Component<import("./types").TabsControlProps, {}, "">;
|
|
3
|
+
Panel: import("svelte").Component<import("./types").TabsPanelProps, {}, "">;
|
|
4
|
+
};
|
|
5
|
+
export default _default;
|
|
@@ -4,9 +4,7 @@ export interface TabsContextState {
|
|
|
4
4
|
fluid: boolean;
|
|
5
5
|
api: ReturnType<typeof tabs.connect>;
|
|
6
6
|
}
|
|
7
|
-
export interface TabsProps extends Omit<tabs.
|
|
8
|
-
/** Set the active value. */
|
|
9
|
-
value?: string;
|
|
7
|
+
export interface TabsProps extends Omit<tabs.Props, 'id' | 'orientation'> {
|
|
10
8
|
/** Set tabs to stretch to fill the available width. */
|
|
11
9
|
fluid?: boolean;
|
|
12
10
|
/** Set base classes for the root element. */
|
|
@@ -1,56 +1,50 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
);
|
|
52
|
-
const api = $derived(tagsInput.connect(snapshot, send, normalizeProps));
|
|
53
|
-
const rxDisabled = $derived(snapshot.context.disabled ? stateDisabled : "");
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import * as tagsInput from '@zag-js/tags-input';
|
|
3
|
+
import { useMachine, normalizeProps } from '@zag-js/svelte';
|
|
4
|
+
import type { TagsInputProps } from './types.js';
|
|
5
|
+
|
|
6
|
+
// Props
|
|
7
|
+
const {
|
|
8
|
+
placeholder = '',
|
|
9
|
+
// Root
|
|
10
|
+
base = 'grid input !h-auto',
|
|
11
|
+
gap = 'gap-2',
|
|
12
|
+
padding = 'p-3',
|
|
13
|
+
classes = '',
|
|
14
|
+
// Input: Add
|
|
15
|
+
inputBase = 'input-ghost',
|
|
16
|
+
inputClasses = '',
|
|
17
|
+
// Tag List
|
|
18
|
+
tagListBase = 'flex flex-wrap gap-1',
|
|
19
|
+
tagListClasses = '',
|
|
20
|
+
// Tag
|
|
21
|
+
tagBase = 'chip',
|
|
22
|
+
tagBackground = 'preset-filled',
|
|
23
|
+
tagClasses = '',
|
|
24
|
+
// Input: Edit
|
|
25
|
+
tagEditInputBase = 'input',
|
|
26
|
+
tagEditInputClasses = '',
|
|
27
|
+
// Delete Button
|
|
28
|
+
buttonDeleteBase = '',
|
|
29
|
+
buttonDeleteClasses = '',
|
|
30
|
+
// State
|
|
31
|
+
stateDisabled = 'disabled',
|
|
32
|
+
// Snippets
|
|
33
|
+
buttonDelete,
|
|
34
|
+
// Zag
|
|
35
|
+
...zagProps
|
|
36
|
+
}: TagsInputProps = $props();
|
|
37
|
+
|
|
38
|
+
// Zag
|
|
39
|
+
const id = $props.id();
|
|
40
|
+
const service = useMachine(tagsInput.machine, () => ({
|
|
41
|
+
id: id,
|
|
42
|
+
...zagProps
|
|
43
|
+
}));
|
|
44
|
+
const api = $derived(tagsInput.connect(service, normalizeProps));
|
|
45
|
+
|
|
46
|
+
// Reactive
|
|
47
|
+
const rxDisabled = $derived(service.prop('disabled') ? stateDisabled : '');
|
|
54
48
|
</script>
|
|
55
49
|
|
|
56
50
|
<!-- @component Capture a set of values from users via input and suggestions. -->
|
|
@@ -89,7 +83,7 @@ const rxDisabled = $derived(snapshot.context.disabled ? stateDisabled : "");
|
|
|
89
83
|
<!-- Editing -->
|
|
90
84
|
<input
|
|
91
85
|
{...api.getItemInputProps({ index, value })}
|
|
92
|
-
class="{
|
|
86
|
+
class="{tagEditInputBase} {tagEditInputClasses}"
|
|
93
87
|
style:display={itemState.editing ? '' : 'none'}
|
|
94
88
|
data-testid="tags-input-edit"
|
|
95
89
|
/>
|
|
@@ -1,17 +1,5 @@
|
|
|
1
1
|
import type { TagsInputProps } from './types.js';
|
|
2
|
-
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
3
|
-
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
4
|
-
$$bindings?: Bindings;
|
|
5
|
-
} & Exports;
|
|
6
|
-
(internal: unknown, props: Props & {
|
|
7
|
-
$$events?: Events;
|
|
8
|
-
$$slots?: Slots;
|
|
9
|
-
}): Exports;
|
|
10
|
-
z_$$bindings?: Bindings;
|
|
11
|
-
}
|
|
12
2
|
/** Capture a set of values from users via input and suggestions. */
|
|
13
|
-
declare const TagsInput:
|
|
14
|
-
|
|
15
|
-
}, {}, {}, "value">;
|
|
16
|
-
type TagsInput = InstanceType<typeof TagsInput>;
|
|
3
|
+
declare const TagsInput: import("svelte").Component<TagsInputProps, {}, "">;
|
|
4
|
+
type TagsInput = ReturnType<typeof TagsInput>;
|
|
17
5
|
export default TagsInput;
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import * as tagsInput from '@zag-js/tags-input';
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
|
-
export interface TagsInputProps extends Omit<tagsInput.
|
|
4
|
-
/** Set the tag values. */
|
|
5
|
-
value?: tagsInput.Context['value'];
|
|
3
|
+
export interface TagsInputProps extends Omit<tagsInput.Props, 'id'> {
|
|
6
4
|
/** Set the add tag input placeholder. */
|
|
7
5
|
placeholder?: string;
|
|
8
6
|
/** Set base classes for the root. */
|
|
@@ -28,11 +26,9 @@ export interface TagsInputProps extends Omit<tagsInput.Context, 'id' | 'value'>
|
|
|
28
26
|
/** Provide arbitrary classes to each tag. */
|
|
29
27
|
tagClasses?: string;
|
|
30
28
|
/** Set base classes for the edit tag input. */
|
|
31
|
-
|
|
32
|
-
/** Set background classes for the edit tag input. */
|
|
33
|
-
tagEditBackground?: string;
|
|
29
|
+
tagEditInputBase?: string;
|
|
34
30
|
/** Provide arbitrary classes to the edit tag input. */
|
|
35
|
-
|
|
31
|
+
tagEditInputClasses?: string;
|
|
36
32
|
/** Set base classes for the delete button. */
|
|
37
33
|
buttonDeleteBase?: string;
|
|
38
34
|
/** Provide arbitrary classes to the delete button. */
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { setContext } from 'svelte';
|
|
3
|
+
import { flip } from 'svelte/animate';
|
|
4
|
+
import { fade } from 'svelte/transition';
|
|
5
|
+
|
|
6
|
+
import type { PlacementStyles, Toast, ToastProviderProps } from './types.js';
|
|
7
|
+
|
|
8
|
+
const {
|
|
9
|
+
placement = 'bottom-end',
|
|
10
|
+
offset = '16px',
|
|
11
|
+
dismissLabel = '',
|
|
12
|
+
// Group
|
|
13
|
+
base = 'fixed flex flex-col items-end',
|
|
14
|
+
gap = 'gap-4',
|
|
15
|
+
zIndex = 'z-[888]',
|
|
16
|
+
classes = '',
|
|
17
|
+
// Toast
|
|
18
|
+
toastBase = 'card py-2 px-3 grid grid-cols-[1fr_auto] items-center',
|
|
19
|
+
toastPadding = 'py-2 px-3',
|
|
20
|
+
toastGap = 'gap-4',
|
|
21
|
+
toastShadow = 'shadow-xl',
|
|
22
|
+
toastClasses = '',
|
|
23
|
+
// Message
|
|
24
|
+
messageBase = 'grid grid-cols-1 max-w-xs text-xs',
|
|
25
|
+
messageTitle = 'font-bold',
|
|
26
|
+
messageDescription = '',
|
|
27
|
+
messageClasses = '',
|
|
28
|
+
// Dismiss Button
|
|
29
|
+
buttonDismissBase = 'btn-icon btn-icon-sm text-base',
|
|
30
|
+
buttonDimissPreset = '',
|
|
31
|
+
buttonDismissHover = 'hover:preset-tonal',
|
|
32
|
+
buttonDismissClasses = '',
|
|
33
|
+
// State
|
|
34
|
+
stateInfo = 'preset-filled',
|
|
35
|
+
stateError = 'preset-filled-error-500',
|
|
36
|
+
stateSuccess = 'preset-filled-success-500',
|
|
37
|
+
// Snippets
|
|
38
|
+
children
|
|
39
|
+
}: ToastProviderProps = $props();
|
|
40
|
+
|
|
41
|
+
// Local
|
|
42
|
+
const defaults: Record<string, Toast> = {
|
|
43
|
+
info: { duration: 5000 },
|
|
44
|
+
error: { duration: 5000 },
|
|
45
|
+
success: { duration: 2000 }
|
|
46
|
+
};
|
|
47
|
+
const placementOptions: Record<string, PlacementStyles> = {
|
|
48
|
+
'top-start': { top: offset, left: offset, 'align-items': 'flex-start' },
|
|
49
|
+
'top-end': { top: offset, right: offset, 'align-items': 'flex-end' },
|
|
50
|
+
'bottom-start': { bottom: offset, left: offset, 'align-items': 'flex-start' },
|
|
51
|
+
'bottom-end': { bottom: offset, right: offset, 'align-items': 'flex-end' }
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
// State
|
|
55
|
+
let toastQueue: Toast[] = $state([]);
|
|
56
|
+
|
|
57
|
+
// Context
|
|
58
|
+
const id = $props.id();
|
|
59
|
+
setContext('toast', {
|
|
60
|
+
create: (toast: Toast) => {
|
|
61
|
+
// Set default settings
|
|
62
|
+
toast = {
|
|
63
|
+
...defaults[String(toast.type || 'info')],
|
|
64
|
+
...toast,
|
|
65
|
+
id: id
|
|
66
|
+
};
|
|
67
|
+
// Push to Queue
|
|
68
|
+
toastQueue.push(toast);
|
|
69
|
+
// Set duration timeout
|
|
70
|
+
setTimeout(() => {
|
|
71
|
+
dismiss(toast.id);
|
|
72
|
+
}, toast.duration);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
function formatStyleAttr(style: PlacementStyles) {
|
|
77
|
+
return Object.entries(style)
|
|
78
|
+
.map(([k, v]) => `${k}:${v}`)
|
|
79
|
+
.join(';');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function dismiss(id: string | undefined) {
|
|
83
|
+
if (!id) return;
|
|
84
|
+
toastQueue = toastQueue.filter((t) => t.id !== id);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function getStateClasses(type?: string) {
|
|
88
|
+
// prettier-ignore
|
|
89
|
+
switch (type) {
|
|
90
|
+
case 'error': return stateError;
|
|
91
|
+
case 'success': return stateSuccess;
|
|
92
|
+
default: return stateInfo;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
</script>
|
|
96
|
+
|
|
97
|
+
<!-- Toast Group -->
|
|
98
|
+
{#if toastQueue.length}
|
|
99
|
+
<div
|
|
100
|
+
class="{base} {gap} {zIndex} {classes}"
|
|
101
|
+
style={formatStyleAttr(placementOptions[placement])}
|
|
102
|
+
data-part="root"
|
|
103
|
+
data-testid="toast-provider"
|
|
104
|
+
>
|
|
105
|
+
{#each toastQueue as toast, i (toast)}
|
|
106
|
+
{@const stateClasses = getStateClasses(toast.type)}
|
|
107
|
+
<!-- Toast -->
|
|
108
|
+
<div
|
|
109
|
+
data-index={i}
|
|
110
|
+
data-type={toast.type}
|
|
111
|
+
class="{toastBase} {toastPadding} {toastGap} {toastShadow} {toastClasses} {stateClasses}"
|
|
112
|
+
animate:flip={{ duration: 200 }}
|
|
113
|
+
transition:fade={{ duration: 200 }}
|
|
114
|
+
>
|
|
115
|
+
<!-- Message -->
|
|
116
|
+
<div class="{messageBase} {messageClasses}">
|
|
117
|
+
{#if toast.title}<div class={messageTitle}>{toast.title}</div>{/if}
|
|
118
|
+
<div class={messageDescription}>{toast.description}</div>
|
|
119
|
+
</div>
|
|
120
|
+
<!-- Dismiss -->
|
|
121
|
+
<button
|
|
122
|
+
type="button"
|
|
123
|
+
class="{buttonDismissBase} {buttonDimissPreset} {buttonDismissHover} {buttonDismissClasses}"
|
|
124
|
+
onclick={() => dismiss(toast.id)}
|
|
125
|
+
>
|
|
126
|
+
{#if dismissLabel}{dismissLabel}{:else}×{/if}
|
|
127
|
+
</button>
|
|
128
|
+
</div>
|
|
129
|
+
{/each}
|
|
130
|
+
</div>
|
|
131
|
+
{/if}
|
|
132
|
+
|
|
133
|
+
{@render children?.()}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
export interface PlacementStyles {
|
|
3
|
+
top?: string;
|
|
4
|
+
bottom?: string;
|
|
5
|
+
left?: string;
|
|
6
|
+
right?: string;
|
|
7
|
+
'align-items'?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface Toast {
|
|
10
|
+
/** The unique toast ID. */
|
|
11
|
+
id?: string;
|
|
12
|
+
/** The unique toast title text. */
|
|
13
|
+
title?: string;
|
|
14
|
+
/** The unique toast description text. */
|
|
15
|
+
description?: string;
|
|
16
|
+
/**
|
|
17
|
+
* Define the toast type.
|
|
18
|
+
* @default info
|
|
19
|
+
*/
|
|
20
|
+
type?: 'info' | 'error' | 'success';
|
|
21
|
+
/** The duration of the toast. Default varies by type. */
|
|
22
|
+
duration?: number;
|
|
23
|
+
}
|
|
24
|
+
/** Provides access to the Toast Context API. */
|
|
25
|
+
export interface ToastContext {
|
|
26
|
+
/** Used to create display a new Toast instance. */
|
|
27
|
+
create: (toast: Toast) => void;
|
|
28
|
+
}
|
|
29
|
+
export interface ToastProviderProps {
|
|
30
|
+
/**
|
|
31
|
+
* Offset from the viewport edge.
|
|
32
|
+
* @default bottom-end
|
|
33
|
+
*/
|
|
34
|
+
placement?: 'top-start' | 'top-end' | 'bottom-start' | 'bottom-end';
|
|
35
|
+
/**
|
|
36
|
+
* Offset from the viewport edge.
|
|
37
|
+
* @default 16px
|
|
38
|
+
*/
|
|
39
|
+
offset?: string;
|
|
40
|
+
/**
|
|
41
|
+
* The dismiss button label text.
|
|
42
|
+
* @default ×
|
|
43
|
+
*/
|
|
44
|
+
dismissLabel?: string;
|
|
45
|
+
/** Provide base classes for the root element. */
|
|
46
|
+
base?: string;
|
|
47
|
+
/** Provide gap classes for the root element. */
|
|
48
|
+
gap?: string;
|
|
49
|
+
/** Provide z-index classes for the root element. */
|
|
50
|
+
zIndex?: string;
|
|
51
|
+
/** Provide arbitrary classes for the root element. */
|
|
52
|
+
classes?: string;
|
|
53
|
+
/** Provide base classes for the toast cards. */
|
|
54
|
+
toastBase?: string;
|
|
55
|
+
/** Provide padding classes for the toast cards. */
|
|
56
|
+
toastPadding?: string;
|
|
57
|
+
/** Provide gap classes for the toast cards. */
|
|
58
|
+
toastGap?: string;
|
|
59
|
+
/** Provide shadow classes for the toast cards. */
|
|
60
|
+
toastShadow?: string;
|
|
61
|
+
/** Provide arbitrary classes for the toast cards. */
|
|
62
|
+
toastClasses?: string;
|
|
63
|
+
/** Provide base classes for the message region. */
|
|
64
|
+
messageBase?: string;
|
|
65
|
+
/** Provide classes for the message title text. */
|
|
66
|
+
messageTitle?: string;
|
|
67
|
+
/** Provide classes for the message description text. */
|
|
68
|
+
messageDescription?: string;
|
|
69
|
+
/** Provide arbitrary classes for the message region. */
|
|
70
|
+
messageClasses?: string;
|
|
71
|
+
/** Provide base classes for the dismiss button. */
|
|
72
|
+
buttonDismissBase?: string;
|
|
73
|
+
/** Provide preset classes for the dismiss button. */
|
|
74
|
+
buttonDimissPreset?: string;
|
|
75
|
+
/** Provide hover classes for the dismiss button. */
|
|
76
|
+
buttonDismissHover?: string;
|
|
77
|
+
/** Provide arbitrary classes for the dismiss button. */
|
|
78
|
+
buttonDismissClasses?: string;
|
|
79
|
+
/** Provide base classes for info toasts. */
|
|
80
|
+
stateInfo?: string;
|
|
81
|
+
/** Provide base classes for error toasts. */
|
|
82
|
+
stateError?: string;
|
|
83
|
+
/** Provide base classes for success toasts. */
|
|
84
|
+
stateSuccess?: string;
|
|
85
|
+
/** The default child slot for the toast provider. */
|
|
86
|
+
children?: Snippet;
|
|
87
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { fade } from 'svelte/transition';
|
|
3
|
+
|
|
4
|
+
import * as tooltip from '@zag-js/tooltip';
|
|
5
|
+
import { useMachine, normalizeProps, mergeProps } from '@zag-js/svelte';
|
|
6
|
+
import type { TooltipProps } from './types.js';
|
|
7
|
+
|
|
8
|
+
const {
|
|
9
|
+
arrow = false,
|
|
10
|
+
zIndex = 'auto',
|
|
11
|
+
// Base
|
|
12
|
+
base = '',
|
|
13
|
+
classes = '',
|
|
14
|
+
// Trigger
|
|
15
|
+
triggerBase = '',
|
|
16
|
+
triggerBackground = '',
|
|
17
|
+
triggerClasses = '',
|
|
18
|
+
triggerAriaLabel = '',
|
|
19
|
+
// Positioner
|
|
20
|
+
positionerBase = '',
|
|
21
|
+
positionerClasses = '',
|
|
22
|
+
// Content
|
|
23
|
+
contentBase = '',
|
|
24
|
+
contentBackground = '',
|
|
25
|
+
contentClasses = '',
|
|
26
|
+
// Arrow
|
|
27
|
+
arrowBase = '',
|
|
28
|
+
arrowBackground = '!bg-white',
|
|
29
|
+
arrowClasses = '',
|
|
30
|
+
// Snippets
|
|
31
|
+
trigger,
|
|
32
|
+
content,
|
|
33
|
+
// Events
|
|
34
|
+
onmouseover,
|
|
35
|
+
onclick,
|
|
36
|
+
// Zag ---
|
|
37
|
+
...zagProps
|
|
38
|
+
}: TooltipProps = $props();
|
|
39
|
+
|
|
40
|
+
// Zag
|
|
41
|
+
const id = $props.id();
|
|
42
|
+
const service = useMachine(tooltip.machine, () => ({
|
|
43
|
+
id: id,
|
|
44
|
+
...zagProps
|
|
45
|
+
}));
|
|
46
|
+
const api = $derived(tooltip.connect(service, normalizeProps));
|
|
47
|
+
const triggerProps = $derived(mergeProps(api.getTriggerProps(), { onmouseover, onclick }));
|
|
48
|
+
</script>
|
|
49
|
+
|
|
50
|
+
<span class="{base} {classes}" data-testid="tooltip">
|
|
51
|
+
<!-- Snippet: Trigger -->
|
|
52
|
+
{#if trigger}
|
|
53
|
+
<button {...triggerProps} class="{triggerBase} {triggerBackground} {triggerClasses}" type="button" aria-label={triggerAriaLabel}>
|
|
54
|
+
{@render trigger()}
|
|
55
|
+
</button>
|
|
56
|
+
{/if}
|
|
57
|
+
<!-- Tooltip Content -->
|
|
58
|
+
{#if api.open}
|
|
59
|
+
<div {...api.getPositionerProps()} transition:fade={{ duration: 100 }} class="{positionerBase} {positionerClasses}">
|
|
60
|
+
<!-- Arrow -->
|
|
61
|
+
{#if arrow}
|
|
62
|
+
<div {...api.getArrowProps()}>
|
|
63
|
+
<div {...api.getArrowTipProps()} class="{arrowBase} {arrowBackground} {arrowClasses}"></div>
|
|
64
|
+
</div>
|
|
65
|
+
{/if}
|
|
66
|
+
<!-- Snippet Content -->
|
|
67
|
+
<div {...api.getContentProps()} class="{contentBase} {contentBackground} {contentClasses}" style="z-index: {zIndex};">
|
|
68
|
+
{@render content?.()}
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
{/if}
|
|
72
|
+
</span>
|
|
73
|
+
|
|
74
|
+
<style>
|
|
75
|
+
:global([data-part='arrow']) {
|
|
76
|
+
--arrow-size: 10px;
|
|
77
|
+
--arrow-background: white;
|
|
78
|
+
}
|
|
79
|
+
</style>
|