@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.
- package/LICENCE +23 -0
- package/README.md +15 -0
- package/dist/components/ai/AiMessage.svelte +115 -0
- package/dist/components/ai/AiMessage.svelte.d.ts +18 -0
- package/dist/components/ai/AttachedFile.svelte +28 -0
- package/dist/components/ai/AttachedFile.svelte.d.ts +9 -0
- package/dist/components/ai/Chat.svelte +150 -0
- package/dist/components/ai/Chat.svelte.d.ts +40 -0
- package/dist/components/ai/Markdown.svelte +59 -0
- package/dist/components/ai/Markdown.svelte.d.ts +16 -0
- package/dist/components/ai/UserMessage.svelte +53 -0
- package/dist/components/ai/UserMessage.svelte.d.ts +16 -0
- package/dist/components/ai/index.d.ts +5 -0
- package/dist/components/ai/index.js +5 -0
- package/dist/components/basic/checkbox/Checkbox.svelte +79 -0
- package/dist/components/basic/checkbox/Checkbox.svelte.d.ts +18 -0
- package/dist/components/basic/index.d.ts +2 -0
- package/dist/components/basic/index.js +2 -0
- package/dist/components/basic/toggle/Toggle.svelte +47 -0
- package/dist/components/basic/toggle/Toggle.svelte.d.ts +12 -0
- package/dist/components/buttons/CopyToClipboardButton.svelte +33 -0
- package/dist/components/buttons/CopyToClipboardButton.svelte.d.ts +9 -0
- package/dist/components/index.d.ts +0 -0
- package/dist/components/index.js +1 -0
- package/dist/components/layout/heading/Heading.svelte +33 -0
- package/dist/components/layout/heading/Heading.svelte.d.ts +16 -0
- package/dist/components/layout/heading/index.d.ts +5 -0
- package/dist/components/layout/heading/index.js +5 -0
- package/dist/components/layout/hiddenBackground/HiddenBackground.svelte +48 -0
- package/dist/components/layout/hiddenBackground/HiddenBackground.svelte.d.ts +13 -0
- package/dist/components/layout/hiddenBackground/index.js +6 -0
- package/dist/components/layout/index.d.ts +7 -0
- package/dist/components/layout/index.js +7 -0
- package/dist/components/layout/modal/Modal.svelte +114 -0
- package/dist/components/layout/modal/Modal.svelte.d.ts +30 -0
- package/dist/components/layout/modal/ModalTest.svelte +16 -0
- package/dist/components/layout/modal/ModalTest.svelte.d.ts +9 -0
- package/dist/components/layout/popover/Popover.svelte +108 -0
- package/dist/components/layout/popover/Popover.svelte.d.ts +36 -0
- package/dist/components/layout/portal/Portal.svelte +23 -0
- package/dist/components/layout/portal/Portal.svelte.d.ts +15 -0
- package/dist/components/layout/tabs/Tab.svelte +80 -0
- package/dist/components/layout/tabs/Tab.svelte.d.ts +21 -0
- package/dist/components/layout/tabs/TabPanel.svelte +23 -0
- package/dist/components/layout/tabs/TabPanel.svelte.d.ts +10 -0
- package/dist/components/layout/tabs/Tabs.svelte +86 -0
- package/dist/components/layout/tabs/Tabs.svelte.d.ts +21 -0
- package/dist/components/layout/tabs/index.d.ts +26 -0
- package/dist/components/layout/tabs/index.js +8 -0
- package/dist/components/layout/tooltip/Tooltip.svelte +111 -0
- package/dist/components/layout/tooltip/Tooltip.svelte.d.ts +32 -0
- package/dist/components/toast/Toast.svelte +100 -0
- package/dist/components/toast/Toast.svelte.d.ts +16 -0
- package/dist/components/toast/index.d.ts +2 -0
- package/dist/components/toast/index.js +2 -0
- package/dist/components/toast/toasts.svelte.d.ts +26 -0
- package/dist/components/toast/toasts.svelte.js +67 -0
- package/dist/index.d.ts +0 -0
- package/dist/index.js +2 -0
- package/dist/utils/actions/clickOutside.d.ts +11 -0
- package/dist/utils/actions/clickOutside.js +23 -0
- package/dist/utils/actions/focusTrap.d.ts +4 -0
- package/dist/utils/actions/focusTrap.js +64 -0
- package/dist/utils/actions/index.d.ts +5 -0
- package/dist/utils/actions/index.js +5 -0
- package/dist/utils/actions/portal.d.ts +9 -0
- package/dist/utils/actions/portal.js +39 -0
- package/dist/utils/actions/shortcut.d.ts +10 -0
- package/dist/utils/actions/shortcut.js +25 -0
- package/dist/utils/actions/visible.d.ts +5 -0
- package/dist/utils/actions/visible.js +14 -0
- package/dist/utils/functions/cookie.d.ts +12 -0
- package/dist/utils/functions/cookie.js +36 -0
- package/dist/utils/functions/index.d.ts +3 -0
- package/dist/utils/functions/index.js +3 -0
- package/dist/utils/functions/pseudoRandomId.d.ts +1 -0
- package/dist/utils/functions/pseudoRandomId.js +3 -0
- package/dist/utils/functions/queryParams.d.ts +1 -0
- package/dist/utils/functions/queryParams.js +14 -0
- package/package.json +107 -0
- package/src/lib/components/ai/AiMessage.svelte +115 -0
- package/src/lib/components/ai/AttachedFile.svelte +28 -0
- package/src/lib/components/ai/Chat.svelte +150 -0
- package/src/lib/components/ai/Markdown.svelte +59 -0
- package/src/lib/components/ai/UserMessage.svelte +53 -0
- package/src/lib/components/ai/index.ts +5 -0
- package/src/lib/components/basic/checkbox/Checkbox.svelte +79 -0
- package/src/lib/components/basic/checkbox/checkbox.svelte.spec.ts +39 -0
- package/src/lib/components/basic/index.ts +2 -0
- package/src/lib/components/basic/toggle/Toggle.svelte +47 -0
- package/src/lib/components/basic/toggle/toggle.svelte.spec.ts +19 -0
- package/src/lib/components/buttons/CopyToClipboardButton.svelte +33 -0
- package/src/lib/components/index.ts +0 -0
- package/src/lib/components/layout/heading/Heading.svelte +33 -0
- package/src/lib/components/layout/heading/index.ts +7 -0
- package/src/lib/components/layout/hiddenBackground/HiddenBackground.svelte +48 -0
- package/src/lib/components/layout/hiddenBackground/index.ts +8 -0
- package/src/lib/components/layout/index.ts +7 -0
- package/src/lib/components/layout/modal/Modal.svelte +114 -0
- package/src/lib/components/layout/modal/ModalTest.svelte +16 -0
- package/src/lib/components/layout/modal/modal.svelte.spec.ts +39 -0
- package/src/lib/components/layout/popover/Popover.svelte +108 -0
- package/src/lib/components/layout/portal/Portal.svelte +23 -0
- package/src/lib/components/layout/tabs/Tab.svelte +80 -0
- package/src/lib/components/layout/tabs/TabPanel.svelte +23 -0
- package/src/lib/components/layout/tabs/Tabs.svelte +86 -0
- package/src/lib/components/layout/tabs/Tabs.test.svelte +5 -0
- package/src/lib/components/layout/tabs/index.ts +10 -0
- package/src/lib/components/layout/tooltip/Tooltip.svelte +111 -0
- package/src/lib/components/toast/Toast.svelte +100 -0
- package/src/lib/components/toast/index.ts +2 -0
- package/src/lib/components/toast/toasts.svelte.ts +89 -0
- package/src/lib/index.ts +1 -0
- package/src/lib/utils/actions/clickOutside.svelte.spec.ts +67 -0
- package/src/lib/utils/actions/clickOutside.ts +38 -0
- package/src/lib/utils/actions/focusTrap.ts +65 -0
- package/src/lib/utils/actions/index.ts +5 -0
- package/src/lib/utils/actions/portal.ts +43 -0
- package/src/lib/utils/actions/shortcut.svelte.spec.ts +19 -0
- package/src/lib/utils/actions/shortcut.ts +35 -0
- package/src/lib/utils/actions/visible.ts +28 -0
- package/src/lib/utils/functions/cookie.svelte.spec.ts +55 -0
- package/src/lib/utils/functions/cookie.ts +46 -0
- package/src/lib/utils/functions/index.ts +3 -0
- package/src/lib/utils/functions/pseudoRandomId.spec.ts +19 -0
- package/src/lib/utils/functions/pseudoRandomId.ts +4 -0
- package/src/lib/utils/functions/queryParams.spec.ts +25 -0
- package/src/lib/utils/functions/queryParams.ts +15 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
<script lang="ts">
|
|
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
|
+
|
|
7
|
+
type Props = {
|
|
8
|
+
value?: boolean;
|
|
9
|
+
class?: ClassValue;
|
|
10
|
+
onclick?: () => void;
|
|
11
|
+
children?: Snippet;
|
|
12
|
+
testId?: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
let { value, class: clazz, onclick, children, testId }: Props = $props();
|
|
16
|
+
|
|
17
|
+
let thumbWidth = $state(0);
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<svelte:element
|
|
21
|
+
this={onclick ? 'button' : 'div'}
|
|
22
|
+
class={twMerge(
|
|
23
|
+
clsx(
|
|
24
|
+
'flex h-5 w-9 items-center rounded-full border p-0.5',
|
|
25
|
+
value ? 'bg-primary-500 border-primary-500' : 'bg-surface-500/30 border-surface-500/60',
|
|
26
|
+
clazz
|
|
27
|
+
)
|
|
28
|
+
)}
|
|
29
|
+
type={onclick ? 'button' : undefined}
|
|
30
|
+
role={onclick ? 'button' : undefined}
|
|
31
|
+
{onclick}
|
|
32
|
+
tabindex="0"
|
|
33
|
+
data-testid={testId}
|
|
34
|
+
>
|
|
35
|
+
<div class="relative flex h-full w-full flex-row items-center">
|
|
36
|
+
<div
|
|
37
|
+
class={[
|
|
38
|
+
'relative flex aspect-square h-full items-center justify-center rounded-full transition-all',
|
|
39
|
+
value ? 'bg-surface-50' : 'bg-surface-600'
|
|
40
|
+
]}
|
|
41
|
+
style={value ? `left: calc(100% - ${thumbWidth}px);` : 'left: 0;'}
|
|
42
|
+
bind:clientWidth={thumbWidth}
|
|
43
|
+
>
|
|
44
|
+
{@render children?.()}
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
</svelte:element>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { ClassValue } from 'svelte/elements';
|
|
3
|
+
type Props = {
|
|
4
|
+
value?: boolean;
|
|
5
|
+
class?: ClassValue;
|
|
6
|
+
onclick?: () => void;
|
|
7
|
+
children?: Snippet;
|
|
8
|
+
testId?: string;
|
|
9
|
+
};
|
|
10
|
+
declare const Toggle: import("svelte").Component<Props, {}, "">;
|
|
11
|
+
type Toggle = ReturnType<typeof Toggle>;
|
|
12
|
+
export default Toggle;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
import { Copy } from '@lucide/svelte';
|
|
3
|
+
import type { ClassValue } from 'svelte/elements';
|
|
4
|
+
import { Toasts } from '../toast';
|
|
5
|
+
|
|
6
|
+
let lastCopied = $state<string>();
|
|
7
|
+
</script>
|
|
8
|
+
|
|
9
|
+
<script lang="ts">
|
|
10
|
+
interface Props {
|
|
11
|
+
text: string;
|
|
12
|
+
class?: ClassValue;
|
|
13
|
+
toastMessage?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
let { text, class: clazz = 'text-xl', toastMessage }: Props = $props();
|
|
17
|
+
|
|
18
|
+
async function copyText() {
|
|
19
|
+
await navigator.clipboard.writeText(text);
|
|
20
|
+
lastCopied = text;
|
|
21
|
+
if (toastMessage) {
|
|
22
|
+
Toasts.trigger({
|
|
23
|
+
variant: 'success',
|
|
24
|
+
message: toastMessage,
|
|
25
|
+
icon: Copy
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<button type="button" class={['text-surface-500 btn', clazz]} onclick={copyText}>
|
|
32
|
+
<Copy class={['h-5 w-5']} />
|
|
33
|
+
</button>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ClassValue } from 'svelte/elements';
|
|
2
|
+
interface Props {
|
|
3
|
+
text: string;
|
|
4
|
+
class?: ClassValue;
|
|
5
|
+
toastMessage?: string;
|
|
6
|
+
}
|
|
7
|
+
declare const CopyToClipboardButton: import("svelte").Component<Props, {}, "">;
|
|
8
|
+
type CopyToClipboardButton = ReturnType<typeof CopyToClipboardButton>;
|
|
9
|
+
export default CopyToClipboardButton;
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";
|
|
@@ -0,0 +1,33 @@
|
|
|
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
|
+
|
|
7
|
+
export interface Props {
|
|
8
|
+
children: Snippet;
|
|
9
|
+
class?: ClassValue;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function setClasses(c: ClassValue) {
|
|
13
|
+
defaultClasses = c;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
let defaultClasses = $state<ClassValue>('');
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<script lang="ts">
|
|
20
|
+
let { children, class: clazz }: Props = $props();
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<!--
|
|
24
|
+
@component
|
|
25
|
+
A component for unified headings.
|
|
26
|
+
Classes that are set using the `setDefaultClasses` function will be applied to all headings,
|
|
27
|
+
including the ones used in other components of this lib, e.g. the `Modal`.
|
|
28
|
+
If you set the `defaultClasses`, make sure to call it before using a component that uses the heading component (e.g. your root `+layout.svelte`).
|
|
29
|
+
-->
|
|
30
|
+
|
|
31
|
+
<h2 class={twMerge(clsx('truncate text-lg font-bold select-none', defaultClasses, clazz))}>
|
|
32
|
+
{@render children()}
|
|
33
|
+
</h2>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { ClassValue } from 'svelte/elements';
|
|
3
|
+
export interface Props {
|
|
4
|
+
children: Snippet;
|
|
5
|
+
class?: ClassValue;
|
|
6
|
+
}
|
|
7
|
+
export declare function setClasses(c: ClassValue): void;
|
|
8
|
+
/**
|
|
9
|
+
* A component for unified headings.
|
|
10
|
+
* Classes that are set using the `setDefaultClasses` function will be applied to all headings,
|
|
11
|
+
* including the ones used in other components of this lib, e.g. the `Modal`.
|
|
12
|
+
* If you set the `defaultClasses`, make sure to call it before using a component that uses the heading component (e.g. your root `+layout.svelte`).
|
|
13
|
+
*/
|
|
14
|
+
declare const Heading: import("svelte").Component<Props, {}, "">;
|
|
15
|
+
type Heading = ReturnType<typeof Heading>;
|
|
16
|
+
export default Heading;
|
|
@@ -0,0 +1,48 @@
|
|
|
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 { fade } from 'svelte/transition';
|
|
6
|
+
import { twMerge } from 'tailwind-merge';
|
|
7
|
+
import { focusTrap, shortcut } from '../../../utils/actions/index';
|
|
8
|
+
|
|
9
|
+
let globalClass = $state<ClassValue>();
|
|
10
|
+
|
|
11
|
+
export function setClasses(value: ClassValue) {
|
|
12
|
+
globalClass = value;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const TEST_ID = 'background';
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<script lang="ts">
|
|
19
|
+
interface Props {
|
|
20
|
+
class?: ClassValue;
|
|
21
|
+
/** Gets called when the dialog is clicked */
|
|
22
|
+
onclose?: () => void;
|
|
23
|
+
children: Snippet;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
let { class: clazz, onclose, children }: Props = $props();
|
|
27
|
+
</script>
|
|
28
|
+
|
|
29
|
+
<dialog
|
|
30
|
+
class={twMerge(
|
|
31
|
+
clsx(
|
|
32
|
+
'bg-surface-950-50/40 absolute top-0 left-0 z-40 m-0 h-full w-full p-0',
|
|
33
|
+
globalClass,
|
|
34
|
+
clazz
|
|
35
|
+
)
|
|
36
|
+
)}
|
|
37
|
+
open
|
|
38
|
+
use:focusTrap={true}
|
|
39
|
+
use:shortcut={{
|
|
40
|
+
code: 'Escape',
|
|
41
|
+
callback: onclose ?? (() => {})
|
|
42
|
+
}}
|
|
43
|
+
onclick={onclose}
|
|
44
|
+
transition:fade={{ duration: 200 }}
|
|
45
|
+
data-testid={TEST_ID}
|
|
46
|
+
>
|
|
47
|
+
{@render children()}
|
|
48
|
+
</dialog>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { ClassValue } from 'svelte/elements';
|
|
3
|
+
export declare function setClasses(value: ClassValue): void;
|
|
4
|
+
export declare const TEST_ID = "background";
|
|
5
|
+
interface Props {
|
|
6
|
+
class?: ClassValue;
|
|
7
|
+
/** Gets called when the dialog is clicked */
|
|
8
|
+
onclose?: () => void;
|
|
9
|
+
children: Snippet;
|
|
10
|
+
}
|
|
11
|
+
declare const HiddenBackground: import("svelte").Component<Props, {}, "">;
|
|
12
|
+
type HiddenBackground = ReturnType<typeof HiddenBackground>;
|
|
13
|
+
export default HiddenBackground;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { default as Heading } from './heading/index';
|
|
2
|
+
export { default as HiddenBackground } from './hiddenBackground/index';
|
|
3
|
+
export { default as Modal } from './modal/Modal.svelte';
|
|
4
|
+
export { default as Popover } from './popover/Popover.svelte';
|
|
5
|
+
export { default as Portal } from './portal/Portal.svelte';
|
|
6
|
+
export { default as Tabs } from './tabs/index';
|
|
7
|
+
export { default as Tooltip } from './tooltip/Tooltip.svelte';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { default as Heading } from './heading/index';
|
|
2
|
+
export { default as HiddenBackground } from './hiddenBackground/index';
|
|
3
|
+
export { default as Modal } from './modal/Modal.svelte';
|
|
4
|
+
export { default as Popover } from './popover/Popover.svelte';
|
|
5
|
+
export { default as Portal } from './portal/Portal.svelte';
|
|
6
|
+
export { default as Tabs } from './tabs/index';
|
|
7
|
+
export { default as Tooltip } from './tooltip/Tooltip.svelte';
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
import { X } from '@lucide/svelte';
|
|
3
|
+
import clsx from 'clsx';
|
|
4
|
+
import type { Snippet } from 'svelte';
|
|
5
|
+
import type { ClassValue } from 'svelte/elements';
|
|
6
|
+
import { twMerge } from 'tailwind-merge';
|
|
7
|
+
import Heading from '../heading/Heading.svelte';
|
|
8
|
+
import HiddenBackground from '../hiddenBackground/HiddenBackground.svelte';
|
|
9
|
+
|
|
10
|
+
/** Props for the modal, expose if you overwrite the defaults in a custom component */
|
|
11
|
+
export interface ModalProps {
|
|
12
|
+
/** Class of the modal itself, does not apply to the inner div */
|
|
13
|
+
class?: ClassValue;
|
|
14
|
+
/** Class of the div wrapping the children */
|
|
15
|
+
innerClass?: ClassValue;
|
|
16
|
+
/** If `true`, the modal will be open */
|
|
17
|
+
b_open: boolean;
|
|
18
|
+
/** Content of the modal */
|
|
19
|
+
children?: Snippet;
|
|
20
|
+
/** Style applied to the */
|
|
21
|
+
style?: string;
|
|
22
|
+
/** If `true` the modal will not close when clicking outside of it */
|
|
23
|
+
preventClosing?: boolean;
|
|
24
|
+
/** Variant of the modal, applies styling to the header */
|
|
25
|
+
variant?: ModalVariant;
|
|
26
|
+
title?: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export type ModalVariant = 'success' | 'warning' | 'error' | 'info';
|
|
30
|
+
</script>
|
|
31
|
+
|
|
32
|
+
<script lang="ts">
|
|
33
|
+
interface Props extends ModalProps {
|
|
34
|
+
/** If you don't want the title and close button to be included you can overwrite the default modal */
|
|
35
|
+
modal?: Snippet;
|
|
36
|
+
testId?: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
let {
|
|
40
|
+
class: clazz = 'flex ',
|
|
41
|
+
style,
|
|
42
|
+
title,
|
|
43
|
+
b_open = $bindable(),
|
|
44
|
+
children,
|
|
45
|
+
modal,
|
|
46
|
+
preventClosing = false,
|
|
47
|
+
variant,
|
|
48
|
+
innerClass,
|
|
49
|
+
testId
|
|
50
|
+
}: Props = $props();
|
|
51
|
+
|
|
52
|
+
function close() {
|
|
53
|
+
if (preventClosing) return;
|
|
54
|
+
b_open = false;
|
|
55
|
+
}
|
|
56
|
+
</script>
|
|
57
|
+
|
|
58
|
+
<!--
|
|
59
|
+
@component
|
|
60
|
+
A modal, comes with a title, close button and different variants per default.
|
|
61
|
+
-->
|
|
62
|
+
{#if b_open}
|
|
63
|
+
<HiddenBackground
|
|
64
|
+
onclose={close}
|
|
65
|
+
class="flex h-full w-full flex-col items-center justify-start p-16"
|
|
66
|
+
>
|
|
67
|
+
{#if modal}
|
|
68
|
+
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
69
|
+
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
|
70
|
+
<div class={clazz} onclick={(e) => e.stopPropagation()} data-testid={testId} {style}>
|
|
71
|
+
{@render modal()}
|
|
72
|
+
</div>
|
|
73
|
+
{:else}
|
|
74
|
+
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
|
75
|
+
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
76
|
+
<div
|
|
77
|
+
class={twMerge(
|
|
78
|
+
clsx([
|
|
79
|
+
'bg-surface-50-950 relative flex max-h-full max-w-full flex-col overflow-hidden rounded',
|
|
80
|
+
clazz
|
|
81
|
+
])
|
|
82
|
+
)}
|
|
83
|
+
{style}
|
|
84
|
+
onclick={(e) => e.stopPropagation()}
|
|
85
|
+
data-testid={testId}
|
|
86
|
+
>
|
|
87
|
+
<div
|
|
88
|
+
class={[
|
|
89
|
+
'flex flex-row items-center justify-between gap-4 px-4 py-3',
|
|
90
|
+
// !variant && 'pt-3',
|
|
91
|
+
variant === 'success' && 'preset-tonal-success',
|
|
92
|
+
variant === 'warning' && 'preset-tonal-warning',
|
|
93
|
+
variant === 'error' && 'preset-tonal-error',
|
|
94
|
+
variant === 'info' && 'preset-tonal-primary'
|
|
95
|
+
]}
|
|
96
|
+
>
|
|
97
|
+
{#if title}
|
|
98
|
+
<Heading>{title}</Heading>
|
|
99
|
+
{/if}
|
|
100
|
+
<button class="group ml-auto flex justify-end" type="button" onclick={close}>
|
|
101
|
+
<X class="h-full w-auto transition-[stroke-width] group-hover:stroke-3" />
|
|
102
|
+
</button>
|
|
103
|
+
</div>
|
|
104
|
+
<div
|
|
105
|
+
class={twMerge(
|
|
106
|
+
clsx('flex flex-col gap-4 overflow-hidden bg-inherit p-4 pt-2', innerClass)
|
|
107
|
+
)}
|
|
108
|
+
>
|
|
109
|
+
{@render children?.()}
|
|
110
|
+
</div>
|
|
111
|
+
</div>
|
|
112
|
+
{/if}
|
|
113
|
+
</HiddenBackground>
|
|
114
|
+
{/if}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { ClassValue } from 'svelte/elements';
|
|
3
|
+
/** Props for the modal, expose if you overwrite the defaults in a custom component */
|
|
4
|
+
export interface ModalProps {
|
|
5
|
+
/** Class of the modal itself, does not apply to the inner div */
|
|
6
|
+
class?: ClassValue;
|
|
7
|
+
/** Class of the div wrapping the children */
|
|
8
|
+
innerClass?: ClassValue;
|
|
9
|
+
/** If `true`, the modal will be open */
|
|
10
|
+
b_open: boolean;
|
|
11
|
+
/** Content of the modal */
|
|
12
|
+
children?: Snippet;
|
|
13
|
+
/** Style applied to the */
|
|
14
|
+
style?: string;
|
|
15
|
+
/** If `true` the modal will not close when clicking outside of it */
|
|
16
|
+
preventClosing?: boolean;
|
|
17
|
+
/** Variant of the modal, applies styling to the header */
|
|
18
|
+
variant?: ModalVariant;
|
|
19
|
+
title?: string;
|
|
20
|
+
}
|
|
21
|
+
export type ModalVariant = 'success' | 'warning' | 'error' | 'info';
|
|
22
|
+
interface Props extends ModalProps {
|
|
23
|
+
/** If you don't want the title and close button to be included you can overwrite the default modal */
|
|
24
|
+
modal?: Snippet;
|
|
25
|
+
testId?: string;
|
|
26
|
+
}
|
|
27
|
+
/** A modal, comes with a title, close button and different variants per default. */
|
|
28
|
+
declare const Modal: import("svelte").Component<Props, {}, "b_open">;
|
|
29
|
+
type Modal = ReturnType<typeof Modal>;
|
|
30
|
+
export default Modal;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import Modal from './Modal.svelte';
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
open: boolean;
|
|
7
|
+
testId: string;
|
|
8
|
+
children: Snippet;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
let { open, ...props }: Props = $props();
|
|
12
|
+
|
|
13
|
+
let b_open = $state(open);
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<Modal bind:b_open {...props} />
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
interface Props {
|
|
3
|
+
open: boolean;
|
|
4
|
+
testId: string;
|
|
5
|
+
children: Snippet;
|
|
6
|
+
}
|
|
7
|
+
declare const ModalTest: import("svelte").Component<Props, {}, "">;
|
|
8
|
+
type ModalTest = ReturnType<typeof ModalTest>;
|
|
9
|
+
export default ModalTest;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
import { browser } from '$app/environment';
|
|
3
|
+
import {
|
|
4
|
+
autoPlacement,
|
|
5
|
+
autoUpdate,
|
|
6
|
+
computePosition,
|
|
7
|
+
flip,
|
|
8
|
+
shift,
|
|
9
|
+
type ComputePositionConfig
|
|
10
|
+
} from '@floating-ui/dom';
|
|
11
|
+
import clsx from 'clsx';
|
|
12
|
+
import type { Snippet } from 'svelte';
|
|
13
|
+
import type { ClassValue } from 'svelte/elements';
|
|
14
|
+
import { twMerge } from 'tailwind-merge';
|
|
15
|
+
import { clickOutside } from '../../../utils/actions/clickOutside';
|
|
16
|
+
|
|
17
|
+
/** Possible placements for the popover */
|
|
18
|
+
export type PopoverPlacement = ComputePositionConfig['placement'];
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<script lang="ts">
|
|
22
|
+
type Props = {
|
|
23
|
+
class?: ClassValue;
|
|
24
|
+
/** Whether the popover is open or not */
|
|
25
|
+
b_open: boolean;
|
|
26
|
+
style?: string;
|
|
27
|
+
/** The element the popover will be positioned relative to */
|
|
28
|
+
target: Element | undefined;
|
|
29
|
+
/**
|
|
30
|
+
* Where the popover should be positioned relative to the target.
|
|
31
|
+
*
|
|
32
|
+
* default: `bottom-start`
|
|
33
|
+
*/
|
|
34
|
+
placement?: PopoverPlacement;
|
|
35
|
+
/**
|
|
36
|
+
* Callback that is called when the user clicks outside the popover or the target element.
|
|
37
|
+
*/
|
|
38
|
+
onClickOutside?: (e: MouseEvent) => void;
|
|
39
|
+
/** If set to `true`, the nested component will not be unmounted when the popover is closed */
|
|
40
|
+
keepMounted?: boolean;
|
|
41
|
+
children: Snippet;
|
|
42
|
+
/**
|
|
43
|
+
* Whether to place the popover automatically
|
|
44
|
+
*
|
|
45
|
+
* [Further reading](https://floating-ui.com/docs/autoPlacement)
|
|
46
|
+
*/
|
|
47
|
+
autoplacement?: boolean;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
let {
|
|
51
|
+
class: clazz,
|
|
52
|
+
b_open = $bindable(false),
|
|
53
|
+
style: externalStyle,
|
|
54
|
+
target,
|
|
55
|
+
placement = 'bottom-start',
|
|
56
|
+
onClickOutside = () => {
|
|
57
|
+
b_open = false;
|
|
58
|
+
},
|
|
59
|
+
keepMounted = false,
|
|
60
|
+
children,
|
|
61
|
+
autoplacement
|
|
62
|
+
}: Props = $props();
|
|
63
|
+
|
|
64
|
+
let style: string = $state('');
|
|
65
|
+
let popover: HTMLDivElement | undefined = $state();
|
|
66
|
+
|
|
67
|
+
const postion = async (open: boolean) => {
|
|
68
|
+
if (!open || !popover || !browser || !target) return;
|
|
69
|
+
const { x, y } = await computePosition(target, popover, {
|
|
70
|
+
middleware: [shift(), ...(autoplacement ? [autoPlacement()] : [flip()])],
|
|
71
|
+
placement
|
|
72
|
+
});
|
|
73
|
+
style = `top: ${y}px; left: ${x}px;`;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
let cleanup: () => void = () => {};
|
|
77
|
+
$effect(() => {
|
|
78
|
+
if (browser && popover && target)
|
|
79
|
+
if (b_open) {
|
|
80
|
+
cleanup = autoUpdate(target, popover, () => postion(b_open));
|
|
81
|
+
} else {
|
|
82
|
+
cleanup();
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// TODO: this is kinda hacky
|
|
87
|
+
$effect(() => {
|
|
88
|
+
[popover, target];
|
|
89
|
+
postion(b_open);
|
|
90
|
+
});
|
|
91
|
+
</script>
|
|
92
|
+
|
|
93
|
+
<!--
|
|
94
|
+
@component
|
|
95
|
+
A popover, positions itself relative to a target element.
|
|
96
|
+
-->
|
|
97
|
+
{#if b_open || keepMounted}
|
|
98
|
+
<div
|
|
99
|
+
class={twMerge(
|
|
100
|
+
clsx('absolute z-30', !keepMounted && clazz, keepMounted && !b_open ? 'hidden' : clazz)
|
|
101
|
+
)}
|
|
102
|
+
style={style + ' ' + externalStyle}
|
|
103
|
+
bind:this={popover}
|
|
104
|
+
use:clickOutside={{ callback: onClickOutside, target }}
|
|
105
|
+
>
|
|
106
|
+
{@render children()}
|
|
107
|
+
</div>
|
|
108
|
+
{/if}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type ComputePositionConfig } from '@floating-ui/dom';
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import type { ClassValue } from 'svelte/elements';
|
|
4
|
+
/** Possible placements for the popover */
|
|
5
|
+
export type PopoverPlacement = ComputePositionConfig['placement'];
|
|
6
|
+
type Props = {
|
|
7
|
+
class?: ClassValue;
|
|
8
|
+
/** Whether the popover is open or not */
|
|
9
|
+
b_open: boolean;
|
|
10
|
+
style?: string;
|
|
11
|
+
/** The element the popover will be positioned relative to */
|
|
12
|
+
target: Element | undefined;
|
|
13
|
+
/**
|
|
14
|
+
* Where the popover should be positioned relative to the target.
|
|
15
|
+
*
|
|
16
|
+
* default: `bottom-start`
|
|
17
|
+
*/
|
|
18
|
+
placement?: PopoverPlacement;
|
|
19
|
+
/**
|
|
20
|
+
* Callback that is called when the user clicks outside the popover or the target element.
|
|
21
|
+
*/
|
|
22
|
+
onClickOutside?: (e: MouseEvent) => void;
|
|
23
|
+
/** If set to `true`, the nested component will not be unmounted when the popover is closed */
|
|
24
|
+
keepMounted?: boolean;
|
|
25
|
+
children: Snippet;
|
|
26
|
+
/**
|
|
27
|
+
* Whether to place the popover automatically
|
|
28
|
+
*
|
|
29
|
+
* [Further reading](https://floating-ui.com/docs/autoPlacement)
|
|
30
|
+
*/
|
|
31
|
+
autoplacement?: boolean;
|
|
32
|
+
};
|
|
33
|
+
/** A popover, positions itself relative to a target element. */
|
|
34
|
+
declare const Popover: import("svelte").Component<Props, {}, "b_open">;
|
|
35
|
+
type Popover = ReturnType<typeof Popover>;
|
|
36
|
+
export default Popover;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import { portal } from '../../../utils/actions/index';
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
children: Snippet;
|
|
7
|
+
target?: string | HTMLElement;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
let { children, target = 'body' }: Props = $props();
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<!--
|
|
14
|
+
@component
|
|
15
|
+
A portal, renders its children in a different DOM element.
|
|
16
|
+
|
|
17
|
+
Wrapps the `use:portal` action.
|
|
18
|
+
|
|
19
|
+
**Use sparingy as it can make the DOM structure confusing**
|
|
20
|
+
-->
|
|
21
|
+
<div use:portal={target} hidden>
|
|
22
|
+
{@render children()}
|
|
23
|
+
</div>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
interface Props {
|
|
3
|
+
children: Snippet;
|
|
4
|
+
target?: string | HTMLElement;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* A portal, renders its children in a different DOM element.
|
|
8
|
+
*
|
|
9
|
+
* Wrapps the `use:portal` action.
|
|
10
|
+
*
|
|
11
|
+
* **Use sparingy as it can make the DOM structure confusing**
|
|
12
|
+
*/
|
|
13
|
+
declare const Portal: import("svelte").Component<Props, {}, "">;
|
|
14
|
+
type Portal = ReturnType<typeof Portal>;
|
|
15
|
+
export default Portal;
|