@ims360/svelte-ivory 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/LICENCE +23 -0
  2. package/README.md +15 -0
  3. package/dist/components/ai/AiMessage.svelte +115 -0
  4. package/dist/components/ai/AiMessage.svelte.d.ts +18 -0
  5. package/dist/components/ai/AttachedFile.svelte +28 -0
  6. package/dist/components/ai/AttachedFile.svelte.d.ts +9 -0
  7. package/dist/components/ai/Chat.svelte +150 -0
  8. package/dist/components/ai/Chat.svelte.d.ts +40 -0
  9. package/dist/components/ai/Markdown.svelte +59 -0
  10. package/dist/components/ai/Markdown.svelte.d.ts +16 -0
  11. package/dist/components/ai/UserMessage.svelte +53 -0
  12. package/dist/components/ai/UserMessage.svelte.d.ts +16 -0
  13. package/dist/components/ai/index.d.ts +5 -0
  14. package/dist/components/ai/index.js +5 -0
  15. package/dist/components/basic/checkbox/Checkbox.svelte +79 -0
  16. package/dist/components/basic/checkbox/Checkbox.svelte.d.ts +18 -0
  17. package/dist/components/basic/index.d.ts +2 -0
  18. package/dist/components/basic/index.js +2 -0
  19. package/dist/components/basic/toggle/Toggle.svelte +47 -0
  20. package/dist/components/basic/toggle/Toggle.svelte.d.ts +12 -0
  21. package/dist/components/buttons/CopyToClipboardButton.svelte +33 -0
  22. package/dist/components/buttons/CopyToClipboardButton.svelte.d.ts +9 -0
  23. package/dist/components/index.d.ts +0 -0
  24. package/dist/components/index.js +1 -0
  25. package/dist/components/layout/heading/Heading.svelte +33 -0
  26. package/dist/components/layout/heading/Heading.svelte.d.ts +16 -0
  27. package/dist/components/layout/heading/index.d.ts +5 -0
  28. package/dist/components/layout/heading/index.js +5 -0
  29. package/dist/components/layout/hiddenBackground/HiddenBackground.svelte +48 -0
  30. package/dist/components/layout/hiddenBackground/HiddenBackground.svelte.d.ts +13 -0
  31. package/dist/components/layout/hiddenBackground/index.js +6 -0
  32. package/dist/components/layout/index.d.ts +7 -0
  33. package/dist/components/layout/index.js +7 -0
  34. package/dist/components/layout/modal/Modal.svelte +114 -0
  35. package/dist/components/layout/modal/Modal.svelte.d.ts +30 -0
  36. package/dist/components/layout/modal/ModalTest.svelte +16 -0
  37. package/dist/components/layout/modal/ModalTest.svelte.d.ts +9 -0
  38. package/dist/components/layout/popover/Popover.svelte +108 -0
  39. package/dist/components/layout/popover/Popover.svelte.d.ts +36 -0
  40. package/dist/components/layout/portal/Portal.svelte +23 -0
  41. package/dist/components/layout/portal/Portal.svelte.d.ts +15 -0
  42. package/dist/components/layout/tabs/Tab.svelte +80 -0
  43. package/dist/components/layout/tabs/Tab.svelte.d.ts +21 -0
  44. package/dist/components/layout/tabs/TabPanel.svelte +23 -0
  45. package/dist/components/layout/tabs/TabPanel.svelte.d.ts +10 -0
  46. package/dist/components/layout/tabs/Tabs.svelte +86 -0
  47. package/dist/components/layout/tabs/Tabs.svelte.d.ts +21 -0
  48. package/dist/components/layout/tabs/index.d.ts +26 -0
  49. package/dist/components/layout/tabs/index.js +8 -0
  50. package/dist/components/layout/tooltip/Tooltip.svelte +111 -0
  51. package/dist/components/layout/tooltip/Tooltip.svelte.d.ts +32 -0
  52. package/dist/components/toast/Toast.svelte +100 -0
  53. package/dist/components/toast/Toast.svelte.d.ts +16 -0
  54. package/dist/components/toast/index.d.ts +2 -0
  55. package/dist/components/toast/index.js +2 -0
  56. package/dist/components/toast/toasts.svelte.d.ts +26 -0
  57. package/dist/components/toast/toasts.svelte.js +67 -0
  58. package/dist/index.d.ts +0 -0
  59. package/dist/index.js +2 -0
  60. package/dist/utils/actions/clickOutside.d.ts +11 -0
  61. package/dist/utils/actions/clickOutside.js +23 -0
  62. package/dist/utils/actions/focusTrap.d.ts +4 -0
  63. package/dist/utils/actions/focusTrap.js +64 -0
  64. package/dist/utils/actions/index.d.ts +5 -0
  65. package/dist/utils/actions/index.js +5 -0
  66. package/dist/utils/actions/portal.d.ts +9 -0
  67. package/dist/utils/actions/portal.js +39 -0
  68. package/dist/utils/actions/shortcut.d.ts +10 -0
  69. package/dist/utils/actions/shortcut.js +25 -0
  70. package/dist/utils/actions/visible.d.ts +5 -0
  71. package/dist/utils/actions/visible.js +14 -0
  72. package/dist/utils/functions/cookie.d.ts +12 -0
  73. package/dist/utils/functions/cookie.js +36 -0
  74. package/dist/utils/functions/index.d.ts +3 -0
  75. package/dist/utils/functions/index.js +3 -0
  76. package/dist/utils/functions/pseudoRandomId.d.ts +1 -0
  77. package/dist/utils/functions/pseudoRandomId.js +3 -0
  78. package/dist/utils/functions/queryParams.d.ts +1 -0
  79. package/dist/utils/functions/queryParams.js +14 -0
  80. package/package.json +107 -0
  81. package/src/lib/components/ai/AiMessage.svelte +115 -0
  82. package/src/lib/components/ai/AttachedFile.svelte +28 -0
  83. package/src/lib/components/ai/Chat.svelte +150 -0
  84. package/src/lib/components/ai/Markdown.svelte +59 -0
  85. package/src/lib/components/ai/UserMessage.svelte +53 -0
  86. package/src/lib/components/ai/index.ts +5 -0
  87. package/src/lib/components/basic/checkbox/Checkbox.svelte +79 -0
  88. package/src/lib/components/basic/checkbox/checkbox.svelte.spec.ts +39 -0
  89. package/src/lib/components/basic/index.ts +2 -0
  90. package/src/lib/components/basic/toggle/Toggle.svelte +47 -0
  91. package/src/lib/components/basic/toggle/toggle.svelte.spec.ts +19 -0
  92. package/src/lib/components/buttons/CopyToClipboardButton.svelte +33 -0
  93. package/src/lib/components/index.ts +0 -0
  94. package/src/lib/components/layout/heading/Heading.svelte +33 -0
  95. package/src/lib/components/layout/heading/index.ts +7 -0
  96. package/src/lib/components/layout/hiddenBackground/HiddenBackground.svelte +48 -0
  97. package/src/lib/components/layout/hiddenBackground/index.ts +8 -0
  98. package/src/lib/components/layout/index.ts +7 -0
  99. package/src/lib/components/layout/modal/Modal.svelte +114 -0
  100. package/src/lib/components/layout/modal/ModalTest.svelte +16 -0
  101. package/src/lib/components/layout/modal/modal.svelte.spec.ts +39 -0
  102. package/src/lib/components/layout/popover/Popover.svelte +108 -0
  103. package/src/lib/components/layout/portal/Portal.svelte +23 -0
  104. package/src/lib/components/layout/tabs/Tab.svelte +80 -0
  105. package/src/lib/components/layout/tabs/TabPanel.svelte +23 -0
  106. package/src/lib/components/layout/tabs/Tabs.svelte +86 -0
  107. package/src/lib/components/layout/tabs/Tabs.test.svelte +5 -0
  108. package/src/lib/components/layout/tabs/index.ts +10 -0
  109. package/src/lib/components/layout/tooltip/Tooltip.svelte +111 -0
  110. package/src/lib/components/toast/Toast.svelte +100 -0
  111. package/src/lib/components/toast/index.ts +2 -0
  112. package/src/lib/components/toast/toasts.svelte.ts +89 -0
  113. package/src/lib/index.ts +1 -0
  114. package/src/lib/utils/actions/clickOutside.svelte.spec.ts +67 -0
  115. package/src/lib/utils/actions/clickOutside.ts +38 -0
  116. package/src/lib/utils/actions/focusTrap.ts +65 -0
  117. package/src/lib/utils/actions/index.ts +5 -0
  118. package/src/lib/utils/actions/portal.ts +43 -0
  119. package/src/lib/utils/actions/shortcut.svelte.spec.ts +19 -0
  120. package/src/lib/utils/actions/shortcut.ts +35 -0
  121. package/src/lib/utils/actions/visible.ts +28 -0
  122. package/src/lib/utils/functions/cookie.svelte.spec.ts +55 -0
  123. package/src/lib/utils/functions/cookie.ts +46 -0
  124. package/src/lib/utils/functions/index.ts +3 -0
  125. package/src/lib/utils/functions/pseudoRandomId.spec.ts +19 -0
  126. package/src/lib/utils/functions/pseudoRandomId.ts +4 -0
  127. package/src/lib/utils/functions/queryParams.spec.ts +25 -0
  128. package/src/lib/utils/functions/queryParams.ts +15 -0
@@ -0,0 +1,80 @@
1
+ <script lang="ts">
2
+ import { page } from '$app/state';
3
+ import { pseudoRandomId } from '../../../utils/functions/index';
4
+ import clsx from 'clsx';
5
+ import { onMount, type Snippet } from 'svelte';
6
+ import type { ClassValue } from 'svelte/elements';
7
+ import { twMerge } from 'tailwind-merge';
8
+ import { getTabContext } from './Tabs.svelte';
9
+
10
+ type Props = {
11
+ class?: (selected: boolean) => ClassValue;
12
+ id?: string | undefined;
13
+ /**
14
+ * If this is set the element will be a link.
15
+ *
16
+ * This is useful if your tabs are in a `+layout.svelte` and the Panels are seperate pages.
17
+ */
18
+ href?: string | undefined;
19
+ children: Snippet<[{ selected: boolean }]>;
20
+ testId?: string;
21
+ /** If `href` is set, this can be used to highlight an active tab */
22
+ active?: boolean;
23
+ };
24
+
25
+ let {
26
+ class: clazz = (selected: boolean) => [selected && 'text-primary-500 underline'],
27
+ id,
28
+ href,
29
+ children,
30
+ testId,
31
+ active
32
+ }: Props = $props();
33
+
34
+ const tab = pseudoRandomId('tab-');
35
+ const tabs = getTabContext();
36
+
37
+ const tabId = id || tab;
38
+
39
+ const selected = $derived.by(() => {
40
+ if (typeof active === 'boolean') {
41
+ return active;
42
+ } else if (href) {
43
+ return page.url.pathname.startsWith(href);
44
+ } else if (tabs && tabs.selectedTab === tabId) {
45
+ return true;
46
+ } else {
47
+ return false;
48
+ }
49
+ });
50
+
51
+ onMount(() => {
52
+ if (href) return;
53
+ tabs.registerTab(tabId);
54
+ });
55
+ </script>
56
+
57
+ <svelte:element
58
+ this={href ? 'a' : 'button'}
59
+ class={twMerge(
60
+ clsx(
61
+ 'btn flex h-fit w-fit items-center justify-center px-0 text-xl font-bold',
62
+ clazz(selected)
63
+ )
64
+ )}
65
+ onclick={href
66
+ ? undefined
67
+ : () => {
68
+ tabs.selectedTab = tabId;
69
+ }}
70
+ type={href ? undefined : 'button'}
71
+ {href}
72
+ data-testid={testId}
73
+ role="tab"
74
+ tabindex="0"
75
+ aria-selected={selected}
76
+ >
77
+ {@render children({
78
+ selected
79
+ })}
80
+ </svelte:element>
@@ -0,0 +1,21 @@
1
+ import { type Snippet } from 'svelte';
2
+ import type { ClassValue } from 'svelte/elements';
3
+ type Props = {
4
+ class?: (selected: boolean) => ClassValue;
5
+ id?: string | undefined;
6
+ /**
7
+ * If this is set the element will be a link.
8
+ *
9
+ * This is useful if your tabs are in a `+layout.svelte` and the Panels are seperate pages.
10
+ */
11
+ href?: string | undefined;
12
+ children: Snippet<[{
13
+ selected: boolean;
14
+ }]>;
15
+ testId?: string;
16
+ /** If `href` is set, this can be used to highlight an active tab */
17
+ active?: boolean;
18
+ };
19
+ declare const Tab: import("svelte").Component<Props, {}, "">;
20
+ type Tab = ReturnType<typeof Tab>;
21
+ export default Tab;
@@ -0,0 +1,23 @@
1
+ <script lang="ts">
2
+ import { pseudoRandomId } from '../../../utils/functions/index';
3
+ import { type Snippet } from 'svelte';
4
+ import { getTabContext } from './Tabs.svelte';
5
+
6
+ type Props = {
7
+ keepMounted?: boolean;
8
+ children: Snippet<[{ visible: boolean }]>;
9
+ };
10
+
11
+ let { keepMounted = false, children }: Props = $props();
12
+
13
+ const panel = pseudoRandomId('tab-panel-');
14
+ const tabs = getTabContext();
15
+
16
+ tabs.registerPanel(panel);
17
+ </script>
18
+
19
+ {#if keepMounted}
20
+ {@render children({ visible: tabs.selectedPanel === panel })}
21
+ {:else if tabs.selectedPanel === panel}
22
+ {@render children({ visible: true })}
23
+ {/if}
@@ -0,0 +1,10 @@
1
+ import { type Snippet } from 'svelte';
2
+ type Props = {
3
+ keepMounted?: boolean;
4
+ children: Snippet<[{
5
+ visible: boolean;
6
+ }]>;
7
+ };
8
+ declare const TabPanel: import("svelte").Component<Props, {}, "">;
9
+ type TabPanel = ReturnType<typeof TabPanel>;
10
+ export default TabPanel;
@@ -0,0 +1,86 @@
1
+ <script lang="ts" module>
2
+ import { getContext, onDestroy, setContext, type Snippet } from 'svelte';
3
+ import type { ClassValue } from 'svelte/elements';
4
+
5
+ interface TabContext {
6
+ registerTab: (tab: string) => void;
7
+ registerPanel: (panel: string) => void;
8
+ selectedTab: string | undefined;
9
+ tabs: string[];
10
+ selectedPanel: string | undefined;
11
+ }
12
+ const TABS = {};
13
+
14
+ function setTabContext(context: TabContext) {
15
+ setContext<TabContext>(TABS, context);
16
+ }
17
+
18
+ export function getTabContext() {
19
+ return getContext<TabContext>(TABS);
20
+ }
21
+ </script>
22
+
23
+ <script lang="ts">
24
+ type Props = {
25
+ class?: ClassValue;
26
+ children: Snippet;
27
+ b_index?: number;
28
+ };
29
+
30
+ let { class: clazz = '', children, b_index = $bindable(0) }: Props = $props();
31
+
32
+ let allTabs: string[] = $state([]);
33
+ let panels: string[] = $state([]);
34
+
35
+ export const forward = () => {
36
+ if (b_index >= panels.length - 1) {
37
+ b_index = 0;
38
+ } else {
39
+ b_index++;
40
+ }
41
+ };
42
+
43
+ export const back = () => {
44
+ if (b_index === 0) {
45
+ b_index = panels.length - 1;
46
+ } else {
47
+ b_index--;
48
+ }
49
+ };
50
+
51
+ setTabContext({
52
+ registerTab: (tab: string) => {
53
+ allTabs.push(tab);
54
+ onDestroy(() => {
55
+ const i = allTabs.indexOf(tab);
56
+ allTabs.splice(i, 1);
57
+ });
58
+ },
59
+
60
+ registerPanel: (panel: string) => {
61
+ panels.push(panel);
62
+ b_index = b_index;
63
+ onDestroy(() => {
64
+ panels.filter((p) => p !== panel);
65
+ });
66
+ },
67
+
68
+ get selectedTab() {
69
+ return allTabs[b_index];
70
+ },
71
+ set selectedTab(tab: string) {
72
+ b_index = allTabs.indexOf(tab);
73
+ },
74
+ get selectedPanel() {
75
+ return panels[b_index];
76
+ },
77
+ set selectedPanel(panel: string) {
78
+ b_index = panels.indexOf(panel);
79
+ },
80
+ tabs: allTabs
81
+ });
82
+ </script>
83
+
84
+ <div class={[clazz]}>
85
+ {@render children()}
86
+ </div>
@@ -0,0 +1,21 @@
1
+ import { type Snippet } from 'svelte';
2
+ import type { ClassValue } from 'svelte/elements';
3
+ interface TabContext {
4
+ registerTab: (tab: string) => void;
5
+ registerPanel: (panel: string) => void;
6
+ selectedTab: string | undefined;
7
+ tabs: string[];
8
+ selectedPanel: string | undefined;
9
+ }
10
+ export declare function getTabContext(): TabContext;
11
+ type Props = {
12
+ class?: ClassValue;
13
+ children: Snippet;
14
+ b_index?: number;
15
+ };
16
+ declare const Tabs: import("svelte").Component<Props, {
17
+ forward: () => void;
18
+ back: () => void;
19
+ }, "b_index">;
20
+ type Tabs = ReturnType<typeof Tabs>;
21
+ export default Tabs;
@@ -0,0 +1,26 @@
1
+ declare const Tabs: import("svelte").Component<{
2
+ class?: import("svelte/elements").ClassValue;
3
+ children: import("svelte").Snippet;
4
+ b_index?: number;
5
+ }, {
6
+ forward: () => void;
7
+ back: () => void;
8
+ }, "b_index"> & {
9
+ Tab: import("svelte").Component<{
10
+ class?: (selected: boolean) => import("svelte/elements").ClassValue;
11
+ id?: string | undefined;
12
+ href?: string | undefined;
13
+ children: import("svelte").Snippet<[{
14
+ selected: boolean;
15
+ }]>;
16
+ testId?: string;
17
+ active?: boolean;
18
+ }, {}, "">;
19
+ Panel: import("svelte").Component<{
20
+ keepMounted?: boolean;
21
+ children: import("svelte").Snippet<[{
22
+ visible: boolean;
23
+ }]>;
24
+ }, {}, "">;
25
+ };
26
+ export default Tabs;
@@ -0,0 +1,8 @@
1
+ import Tab from './Tab.svelte';
2
+ import TabPanel from './TabPanel.svelte';
3
+ import { default as TabsComponent } from './Tabs.svelte';
4
+ const Tabs = Object.assign(TabsComponent, {
5
+ Tab: Tab,
6
+ Panel: TabPanel
7
+ });
8
+ export default Tabs;
@@ -0,0 +1,111 @@
1
+ <script lang="ts" module>
2
+ import clsx from 'clsx';
3
+ import type { Snippet } from 'svelte';
4
+ import type { ClassValue } from 'svelte/elements';
5
+ import { twMerge } from 'tailwind-merge';
6
+ import Popover, { type PopoverPlacement } from '../popover/Popover.svelte';
7
+ import Portal from '../portal/Portal.svelte';
8
+
9
+ export interface Props {
10
+ children?: Snippet;
11
+ /** The content of the tooltip */
12
+ tooltip: string | Snippet;
13
+ /** The class of the element that triggers the tooltip */
14
+ class?: ClassValue;
15
+ /** The class of the tooltip itself */
16
+ tooltipClass?: ClassValue;
17
+ style?: string;
18
+ onclick?: (e: Event) => void;
19
+ /** If the href is set, the resulting element will be a link to the href */
20
+ href?: string;
21
+ /**
22
+ * The delay before the tooltip is shown in ms.
23
+ *
24
+ * default: `500`
25
+ */
26
+ timeout?: number;
27
+ /**
28
+ * Where the tooltip should be placed
29
+ *
30
+ * default: `top`
31
+ */
32
+ placement?: PopoverPlacement;
33
+ }
34
+ </script>
35
+
36
+ <script lang="ts">
37
+ let {
38
+ children,
39
+ tooltip,
40
+ class: clazz,
41
+ style,
42
+ onclick,
43
+ href,
44
+ timeout = 500,
45
+ tooltipClass
46
+ }: Props = $props();
47
+
48
+ let target = $state<HTMLElement>();
49
+
50
+ let open = $state(false);
51
+
52
+ let showTimeout: number;
53
+ function onpointerenter() {
54
+ clearTimeout(timeout);
55
+ if (timeout === 0) {
56
+ open = true;
57
+ } else {
58
+ showTimeout = setTimeout(() => {
59
+ open = true;
60
+ }, timeout) as unknown as number;
61
+ }
62
+ }
63
+
64
+ function onpointerleave() {
65
+ clearTimeout(timeout);
66
+ open = false;
67
+ }
68
+ </script>
69
+
70
+ <!--
71
+ @component
72
+ Shows additional information when hovering over an element.
73
+ -->
74
+
75
+ <!-- Ignoring this error is fine since it's a false positive -->
76
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
77
+ <svelte:element
78
+ this={href ? 'a' : onclick ? 'button' : 'div'}
79
+ {href}
80
+ type={onclick ? 'button' : undefined}
81
+ class={clazz}
82
+ bind:this={target}
83
+ {onpointerenter}
84
+ {onpointerleave}
85
+ {style}
86
+ {onclick}
87
+ >
88
+ {@render children?.()}
89
+ </svelte:element>
90
+
91
+ {#if open}
92
+ <Portal>
93
+ <Popover
94
+ bind:b_open={open}
95
+ {target}
96
+ placement="top"
97
+ class={twMerge(
98
+ clsx(
99
+ 'bg-surface-100-800-token max-w-96 -translate-y-0.5 rounded px-4 py-1 shadow-lg',
100
+ tooltipClass
101
+ )
102
+ )}
103
+ >
104
+ {#if typeof tooltip === 'string'}
105
+ {tooltip}
106
+ {:else}
107
+ {@render tooltip()}
108
+ {/if}
109
+ </Popover>
110
+ </Portal>
111
+ {/if}
@@ -0,0 +1,32 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { ClassValue } from 'svelte/elements';
3
+ import { type PopoverPlacement } from '../popover/Popover.svelte';
4
+ export interface Props {
5
+ children?: Snippet;
6
+ /** The content of the tooltip */
7
+ tooltip: string | Snippet;
8
+ /** The class of the element that triggers the tooltip */
9
+ class?: ClassValue;
10
+ /** The class of the tooltip itself */
11
+ tooltipClass?: ClassValue;
12
+ style?: string;
13
+ onclick?: (e: Event) => void;
14
+ /** If the href is set, the resulting element will be a link to the href */
15
+ href?: string;
16
+ /**
17
+ * The delay before the tooltip is shown in ms.
18
+ *
19
+ * default: `500`
20
+ */
21
+ timeout?: number;
22
+ /**
23
+ * Where the tooltip should be placed
24
+ *
25
+ * default: `top`
26
+ */
27
+ placement?: PopoverPlacement;
28
+ }
29
+ /** Shows additional information when hovering over an element. */
30
+ declare const Tooltip: import("svelte").Component<Props, {}, "">;
31
+ type Tooltip = ReturnType<typeof Tooltip>;
32
+ export default Tooltip;
@@ -0,0 +1,100 @@
1
+ <!--
2
+ @component
3
+ Renders the toasts that have been triggered by the `Toasts` store.
4
+ Make sure to include this component in your root `+layout.svelte` file.
5
+ -->
6
+ <script lang="ts">
7
+ import type { Icon } from '@lucide/svelte';
8
+ import { Check, CircleAlert, Info, TriangleAlert, X } from '@lucide/svelte';
9
+ import type { Snippet } from 'svelte';
10
+ import { flip } from 'svelte/animate';
11
+ import type { ClassValue } from 'svelte/elements';
12
+ import { fly, scale } from 'svelte/transition';
13
+ import { Toasts, type ToastSettings } from './toasts.svelte';
14
+
15
+ type Props = {
16
+ class?: ClassValue;
17
+ children?: Snippet<[toast: ToastSettings & { close: () => void }]>;
18
+ };
19
+
20
+ let { class: clazz = 'px-2 pb-2', children }: Props = $props();
21
+
22
+ function getIcon(
23
+ variant: 'info' | 'success' | 'warning' | 'error',
24
+ icon?: typeof Icon
25
+ ): typeof Icon {
26
+ if (icon) return icon;
27
+ switch (variant) {
28
+ case 'info':
29
+ return Info;
30
+ case 'success':
31
+ return Check;
32
+ case 'warning':
33
+ return CircleAlert;
34
+ case 'error':
35
+ return TriangleAlert;
36
+ }
37
+ }
38
+ </script>
39
+
40
+ <div
41
+ class="pointer-events-none absolute top-0 left-0 z-50 flex h-full w-full flex-col items-center justify-start"
42
+ >
43
+ <div
44
+ class={[
45
+ 'flex h-full max-h-full flex-col-reverse items-center justify-end gap-2 overflow-hidden',
46
+ clazz
47
+ ]}
48
+ >
49
+ {#each Toasts.toasts as toast (toast.id)}
50
+ {@const VariantIcon = getIcon(toast.variant, toast.icon)}
51
+
52
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
53
+ <div
54
+ in:fly={{ y: '-100%', duration: 300 }}
55
+ out:scale={{ duration: 300 }}
56
+ animate:flip={{ duration: 300 }}
57
+ onpointerenter={() => {
58
+ Toasts.freeze(toast.id);
59
+ }}
60
+ onpointerleave={() => {
61
+ Toasts.unfreeze(toast.id);
62
+ }}
63
+ class="group pointer-events-auto flex h-fit w-fit flex-row items-center"
64
+ >
65
+ {#if children}
66
+ {@render children({
67
+ ...toast,
68
+ close: () => Toasts.close(toast.id)
69
+ })}
70
+ {:else}
71
+ <div
72
+ class={[
73
+ 'bg-opacity-85 flex flex-row items-center gap-4 rounded px-4 py-2 shadow-lg group-last:rounded-t-none',
74
+ toast.variant === 'info' && 'preset-filled-primary-500',
75
+ toast.variant === 'success' && 'preset-filled-success-500',
76
+ toast.variant === 'warning' && 'preset-filled-warning-500',
77
+ toast.variant === 'error' && 'preset-filled-error-500'
78
+ ]}
79
+ >
80
+ <VariantIcon />
81
+ <p class="font-bold">
82
+ {toast.message}
83
+ </p>
84
+ {#if !toast.hideDismiss}
85
+ <button
86
+ type="button"
87
+ onclick={() => {
88
+ Toasts.close(toast.id);
89
+ }}
90
+ class="transition-transform hover:rotate-90"
91
+ >
92
+ <X />
93
+ </button>
94
+ {/if}
95
+ </div>
96
+ {/if}
97
+ </div>
98
+ {/each}
99
+ </div>
100
+ </div>
@@ -0,0 +1,16 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { ClassValue } from 'svelte/elements';
3
+ import { type ToastSettings } from './toasts.svelte';
4
+ type Props = {
5
+ class?: ClassValue;
6
+ children?: Snippet<[toast: ToastSettings & {
7
+ close: () => void;
8
+ }]>;
9
+ };
10
+ /**
11
+ * Renders the toasts that have been triggered by the `Toasts` store.
12
+ * Make sure to include this component in your root `+layout.svelte` file.
13
+ */
14
+ declare const Toast: import("svelte").Component<Props, {}, "">;
15
+ type Toast = ReturnType<typeof Toast>;
16
+ export default Toast;
@@ -0,0 +1,2 @@
1
+ export { default as ToastUI } from './Toast.svelte';
2
+ export { Toasts } from './toasts.svelte';
@@ -0,0 +1,2 @@
1
+ export { default as ToastUI } from './Toast.svelte';
2
+ export { Toasts } from './toasts.svelte';
@@ -0,0 +1,26 @@
1
+ import type { Icon } from '@lucide/svelte';
2
+ export type ToastSettings = {
3
+ message: string;
4
+ autohide?: boolean;
5
+ timeout?: number;
6
+ hideDismiss?: boolean;
7
+ icon?: typeof Icon;
8
+ variant: 'info' | 'success' | 'warning' | 'error';
9
+ };
10
+ type Toast = ToastSettings & {
11
+ id: string;
12
+ timeoutId?: ReturnType<typeof setTimeout>;
13
+ };
14
+ declare class ToastStore {
15
+ toasts: Toast[];
16
+ trigger(toast: ToastSettings, id?: string): string;
17
+ close(id: string): void;
18
+ update(id: string, toast: ToastSettings): void;
19
+ freeze(id: string): void;
20
+ unfreeze(id: string): void;
21
+ private startAutoHide;
22
+ private stopAutoHide;
23
+ }
24
+ /** Exposes functions to manage toasts, contains currently active toasts */
25
+ export declare const Toasts: ToastStore;
26
+ export {};
@@ -0,0 +1,67 @@
1
+ const TOAST_DEFAULTS = {
2
+ message: 'Missing Toast Message',
3
+ autohide: true,
4
+ timeout: 3000,
5
+ variant: 'info'
6
+ };
7
+ class ToastStore {
8
+ toasts = $state([]);
9
+ trigger(toast, id = crypto.randomUUID()) {
10
+ const mergedToasts = { ...TOAST_DEFAULTS, ...toast, id };
11
+ // start the autohide timeout
12
+ this.startAutoHide(mergedToasts);
13
+ // add the toasts to the list
14
+ this.toasts.push(mergedToasts);
15
+ return id;
16
+ }
17
+ close(id) {
18
+ const toast = this.toasts.find((t) => t.id === id);
19
+ if (!toast)
20
+ return;
21
+ this.stopAutoHide(toast);
22
+ this.toasts = this.toasts.filter((t) => t.id !== id);
23
+ }
24
+ update(id, toast) {
25
+ const existingToast = this.toasts.find((t) => t.id === id);
26
+ if (!existingToast) {
27
+ this.trigger(toast, id);
28
+ return;
29
+ }
30
+ const mergedToast = {
31
+ ...TOAST_DEFAULTS,
32
+ ...existingToast,
33
+ ...toast
34
+ };
35
+ // clear the existing timeout and restart the autohide
36
+ this.stopAutoHide(existingToast);
37
+ this.startAutoHide(mergedToast);
38
+ this.toasts.splice(this.toasts.indexOf(existingToast), 1, mergedToast);
39
+ }
40
+ freeze(id) {
41
+ const toast = this.toasts.find((t) => t.id === id);
42
+ if (!toast)
43
+ return;
44
+ this.stopAutoHide(toast);
45
+ }
46
+ unfreeze(id) {
47
+ const toast = this.toasts.find((t) => t.id === id);
48
+ if (!toast)
49
+ return;
50
+ this.startAutoHide(toast);
51
+ }
52
+ startAutoHide(toast) {
53
+ if (!toast.autohide)
54
+ return;
55
+ toast.timeoutId = setTimeout(() => {
56
+ this.close(toast.id);
57
+ }, toast.timeout);
58
+ }
59
+ stopAutoHide(toast) {
60
+ if (!toast.timeoutId)
61
+ return;
62
+ clearTimeout(toast.timeoutId);
63
+ delete toast.timeoutId;
64
+ }
65
+ }
66
+ /** Exposes functions to manage toasts, contains currently active toasts */
67
+ export const Toasts = new ToastStore();
File without changes
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ // Reexport your entry components here
@@ -0,0 +1,11 @@
1
+ interface ClickOutsideParams {
2
+ /** Callback to be called when clicking outside of node */
3
+ callback: (e: MouseEvent) => void;
4
+ /** Callback is also not fired if the click target is inside this element */
5
+ target?: Element;
6
+ }
7
+ /** Dispatch event on click outside of node */
8
+ export declare function clickOutside(node: Element, params: ((e: MouseEvent) => void) | ClickOutsideParams): {
9
+ destroy(): void;
10
+ };
11
+ export {};