@ims360/svelte-ivory 0.1.15 → 0.2.1
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 +0 -5
- package/dist/components/ai/AiMessage.svelte +2 -3
- package/dist/components/ai/AiMessage.svelte.d.ts.map +1 -1
- package/dist/components/ai/Chat.svelte +2 -3
- package/dist/components/ai/Chat.svelte.d.ts.map +1 -1
- package/dist/components/ai/Markdown.svelte +4 -7
- package/dist/components/ai/Markdown.svelte.d.ts.map +1 -1
- package/dist/components/ai/UserMessage.svelte +2 -3
- package/dist/components/ai/UserMessage.svelte.d.ts.map +1 -1
- package/dist/components/basic/checkbox/Checkbox.svelte +13 -11
- package/dist/components/basic/checkbox/Checkbox.svelte.d.ts.map +1 -1
- package/dist/components/basic/toggle/Toggle.svelte +5 -8
- package/dist/components/basic/toggle/Toggle.svelte.d.ts.map +1 -1
- package/dist/components/inputs/CheckboxInput.svelte +39 -0
- package/dist/components/inputs/CheckboxInput.svelte.d.ts +12 -0
- package/dist/components/inputs/CheckboxInput.svelte.d.ts.map +1 -0
- package/dist/components/inputs/ColorInput.svelte +25 -0
- package/dist/components/inputs/ColorInput.svelte.d.ts +5 -0
- package/dist/components/inputs/ColorInput.svelte.d.ts.map +1 -0
- package/dist/components/inputs/DateInput.svelte +11 -0
- package/dist/components/inputs/DateInput.svelte.d.ts +5 -0
- package/dist/components/inputs/DateInput.svelte.d.ts.map +1 -0
- package/dist/components/inputs/EmailInput.svelte +16 -0
- package/dist/components/inputs/EmailInput.svelte.d.ts +5 -0
- package/dist/components/inputs/EmailInput.svelte.d.ts.map +1 -0
- package/dist/components/inputs/FileInput.svelte +131 -0
- package/dist/components/inputs/FileInput.svelte.d.ts +11 -0
- package/dist/components/inputs/FileInput.svelte.d.ts.map +1 -0
- package/dist/components/inputs/Input.svelte +101 -0
- package/dist/components/inputs/Input.svelte.d.ts +48 -0
- package/dist/components/inputs/Input.svelte.d.ts.map +1 -0
- package/dist/components/inputs/NumberInput.svelte +17 -0
- package/dist/components/inputs/NumberInput.svelte.d.ts +10 -0
- package/dist/components/inputs/NumberInput.svelte.d.ts.map +1 -0
- package/dist/components/inputs/PasswordCreateInput.svelte +60 -0
- package/dist/components/inputs/PasswordCreateInput.svelte.d.ts +12 -0
- package/dist/components/inputs/PasswordCreateInput.svelte.d.ts.map +1 -0
- package/dist/components/inputs/PasswordInput.svelte +27 -0
- package/dist/components/inputs/PasswordInput.svelte.d.ts +10 -0
- package/dist/components/inputs/PasswordInput.svelte.d.ts.map +1 -0
- package/dist/components/inputs/TextInput.svelte +16 -0
- package/dist/components/inputs/TextInput.svelte.d.ts +7 -0
- package/dist/components/inputs/TextInput.svelte.d.ts.map +1 -0
- package/dist/components/inputs/ToggleInput.svelte +24 -0
- package/dist/components/inputs/ToggleInput.svelte.d.ts +5 -0
- package/dist/components/inputs/ToggleInput.svelte.d.ts.map +1 -0
- package/dist/components/inputs/index.d.ts +13 -0
- package/dist/components/inputs/index.d.ts.map +1 -1
- package/dist/components/inputs/index.js +13 -0
- package/dist/components/inputs/issues/FormIssues.svelte +35 -0
- package/dist/components/inputs/issues/FormIssues.svelte.d.ts +10 -0
- package/dist/components/inputs/issues/FormIssues.svelte.d.ts.map +1 -0
- package/dist/components/inputs/select/Select.svelte +69 -0
- package/dist/components/inputs/select/Select.svelte.d.ts +15 -0
- package/dist/components/inputs/select/Select.svelte.d.ts.map +1 -0
- package/dist/components/inputs/select/SelectOption.svelte +34 -0
- package/dist/components/inputs/select/SelectOption.svelte.d.ts +11 -0
- package/dist/components/inputs/select/SelectOption.svelte.d.ts.map +1 -0
- package/dist/components/layout/Heading.svelte +5 -4
- package/dist/components/layout/Heading.svelte.d.ts.map +1 -1
- package/dist/components/layout/dialog/Dialog.svelte +5 -8
- package/dist/components/layout/dialog/Dialog.svelte.d.ts.map +1 -1
- package/dist/components/layout/drawer/Drawer.svelte +7 -10
- package/dist/components/layout/drawer/Drawer.svelte.d.ts.map +1 -1
- package/dist/components/layout/index.d.ts +1 -2
- package/dist/components/layout/index.d.ts.map +1 -1
- package/dist/components/layout/index.js +0 -1
- package/dist/components/layout/modal/Modal.svelte +10 -15
- package/dist/components/layout/modal/Modal.svelte.d.ts.map +1 -1
- package/dist/components/layout/popover/Popover.svelte +10 -13
- package/dist/components/layout/popover/Popover.svelte.d.ts.map +1 -1
- package/dist/components/layout/tabs/Tab.svelte +5 -8
- package/dist/components/layout/tabs/Tab.svelte.d.ts.map +1 -1
- package/dist/components/layout/tooltip/Tooltip.svelte +4 -7
- package/dist/components/layout/tooltip/Tooltip.svelte.d.ts.map +1 -1
- package/dist/components/table/Column.svelte +7 -10
- package/dist/components/table/Column.svelte.d.ts.map +1 -1
- package/dist/components/table/ColumnHead.svelte +2 -2
- package/dist/components/table/Table.svelte +5 -8
- package/dist/components/table/Table.svelte.d.ts.map +1 -1
- package/dist/components/table/VirtualList.svelte +3 -8
- package/dist/components/table/VirtualList.svelte.d.ts.map +1 -1
- package/dist/theme.svelte.d.ts +18 -0
- package/dist/theme.svelte.d.ts.map +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/{actions → attachments}/clickOutside.d.ts +2 -4
- package/dist/utils/attachments/clickOutside.d.ts.map +1 -0
- package/dist/utils/{actions → attachments}/clickOutside.js +4 -7
- package/dist/utils/attachments/focusTrap.d.ts +3 -0
- package/dist/utils/attachments/focusTrap.d.ts.map +1 -0
- package/dist/utils/{actions → attachments}/focusTrap.js +5 -14
- package/dist/utils/{actions → attachments}/index.d.ts +0 -1
- package/dist/utils/attachments/index.d.ts.map +1 -0
- package/dist/utils/{actions → attachments}/index.js +0 -1
- package/dist/utils/attachments/resize.d.ts +6 -0
- package/dist/utils/attachments/resize.d.ts.map +1 -0
- package/dist/utils/{actions → attachments}/resize.js +3 -5
- package/dist/utils/attachments/shortcut.svelte.d.ts.map +1 -0
- package/dist/utils/attachments/visible.d.ts +6 -0
- package/dist/utils/attachments/visible.d.ts.map +1 -0
- package/dist/utils/attachments/visible.js +12 -0
- package/dist/utils/merge.d.ts +4 -0
- package/dist/utils/merge.d.ts.map +1 -0
- package/dist/utils/merge.js +6 -0
- package/package.json +7 -5
- package/src/lib/components/ai/AiMessage.svelte +2 -3
- package/src/lib/components/ai/Chat.svelte +2 -3
- package/src/lib/components/ai/Markdown.svelte +4 -7
- package/src/lib/components/ai/UserMessage.svelte +2 -3
- package/src/lib/components/basic/checkbox/Checkbox.svelte +13 -11
- package/src/lib/components/basic/toggle/Toggle.svelte +5 -8
- package/src/lib/components/inputs/CheckboxInput.svelte +39 -0
- package/src/lib/components/inputs/ColorInput.svelte +25 -0
- package/src/lib/components/inputs/DateInput.svelte +11 -0
- package/src/lib/components/inputs/EmailInput.svelte +16 -0
- package/src/lib/components/inputs/FileInput.svelte +131 -0
- package/src/lib/components/inputs/Input.svelte +101 -0
- package/src/lib/components/inputs/NumberInput.svelte +17 -0
- package/src/lib/components/inputs/PasswordCreateInput.svelte +60 -0
- package/src/lib/components/inputs/PasswordInput.svelte +27 -0
- package/src/lib/components/inputs/TextInput.svelte +16 -0
- package/src/lib/components/inputs/ToggleInput.svelte +24 -0
- package/src/lib/components/inputs/index.ts +17 -0
- package/src/lib/components/inputs/issues/FormIssues.svelte +35 -0
- package/src/lib/components/inputs/select/Select.svelte +69 -0
- package/src/lib/components/inputs/select/SelectOption.svelte +34 -0
- package/src/lib/components/layout/Heading.svelte +5 -4
- package/src/lib/components/layout/dialog/Dialog.svelte +5 -8
- package/src/lib/components/layout/drawer/Drawer.svelte +7 -10
- package/src/lib/components/layout/index.ts +1 -5
- package/src/lib/components/layout/modal/Modal.svelte +10 -15
- package/src/lib/components/layout/popover/Popover.svelte +10 -13
- package/src/lib/components/layout/tabs/Tab.svelte +5 -8
- package/src/lib/components/layout/tooltip/Tooltip.svelte +4 -7
- package/src/lib/components/table/Column.svelte +7 -10
- package/src/lib/components/table/ColumnHead.svelte +2 -2
- package/src/lib/components/table/Table.svelte +5 -8
- package/src/lib/components/table/VirtualList.svelte +3 -8
- package/src/lib/theme.svelte.ts +18 -0
- package/src/lib/types.ts +3 -2
- package/src/lib/utils/attachments/clickOutside.ts +36 -0
- package/src/lib/utils/attachments/focusTrap.ts +67 -0
- package/src/lib/utils/{actions → attachments}/index.ts +0 -1
- package/src/lib/utils/attachments/resize.ts +38 -0
- package/src/lib/utils/attachments/visible.ts +22 -0
- package/src/lib/utils/merge.ts +7 -0
- package/dist/components/layout/portal/Portal.svelte +0 -39
- package/dist/components/layout/portal/Portal.svelte.d.ts +0 -21
- package/dist/components/layout/portal/Portal.svelte.d.ts.map +0 -1
- package/dist/components/layout/portal/index.d.ts +0 -6
- package/dist/components/layout/portal/index.d.ts.map +0 -1
- package/dist/components/layout/portal/index.js +0 -5
- package/dist/utils/actions/clickOutside.d.ts.map +0 -1
- package/dist/utils/actions/focusTrap.d.ts +0 -5
- package/dist/utils/actions/focusTrap.d.ts.map +0 -1
- package/dist/utils/actions/index.d.ts.map +0 -1
- package/dist/utils/actions/portal.d.ts +0 -10
- package/dist/utils/actions/portal.d.ts.map +0 -1
- package/dist/utils/actions/portal.js +0 -39
- package/dist/utils/actions/resize.d.ts +0 -6
- package/dist/utils/actions/resize.d.ts.map +0 -1
- package/dist/utils/actions/shortcut.svelte.d.ts.map +0 -1
- package/dist/utils/actions/visible.d.ts +0 -6
- package/dist/utils/actions/visible.d.ts.map +0 -1
- package/dist/utils/actions/visible.js +0 -14
- package/src/lib/components/layout/portal/Portal.svelte +0 -39
- package/src/lib/components/layout/portal/index.ts +0 -7
- package/src/lib/utils/actions/clickOutside.ts +0 -38
- package/src/lib/utils/actions/focusTrap.ts +0 -65
- package/src/lib/utils/actions/portal.ts +0 -43
- package/src/lib/utils/actions/resize.ts +0 -35
- package/src/lib/utils/actions/visible.ts +0 -28
- /package/dist/utils/{actions → attachments}/shortcut.svelte.d.ts +0 -0
- /package/dist/utils/{actions → attachments}/shortcut.svelte.js +0 -0
- /package/src/lib/utils/{actions → attachments}/shortcut.svelte.ts +0 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { theme } from '$lib/theme.svelte';
|
|
3
|
+
import { merge } from '$lib/utils/merge';
|
|
4
|
+
import { TriangleAlert } from '@lucide/svelte';
|
|
5
|
+
import type { RemoteFormIssue } from '@sveltejs/kit';
|
|
6
|
+
import type { ClassValue } from 'svelte/elements';
|
|
7
|
+
import { slide } from 'svelte/transition';
|
|
8
|
+
|
|
9
|
+
interface Props {
|
|
10
|
+
issues?: RemoteFormIssue[];
|
|
11
|
+
class?: ClassValue;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let { issues = [], class: clazz }: Props = $props();
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
{#each issues as err, i (i)}
|
|
18
|
+
<div
|
|
19
|
+
class={merge(
|
|
20
|
+
'text-error-500 flex h-fit w-full flex-row items-start justify-center gap-2 overflow-hidden pl-1',
|
|
21
|
+
theme.current.input?.issues?.issue?.class,
|
|
22
|
+
clazz
|
|
23
|
+
)}
|
|
24
|
+
transition:slide={{ axis: 'y' }}
|
|
25
|
+
>
|
|
26
|
+
<TriangleAlert size="18" class="my-auto" />
|
|
27
|
+
<p class="flex grow">
|
|
28
|
+
{#if theme.current.input?.issues?.issue?.label}
|
|
29
|
+
{theme.current.input?.issues?.issue?.label(err)}
|
|
30
|
+
{:else}
|
|
31
|
+
{err.message}
|
|
32
|
+
{/if}
|
|
33
|
+
</p>
|
|
34
|
+
</div>
|
|
35
|
+
{/each}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
import { Popover } from '$lib/components/layout';
|
|
3
|
+
import { ChevronDown } from '@lucide/svelte';
|
|
4
|
+
import { createContext, type Snippet } from 'svelte';
|
|
5
|
+
import Input, { type InputProps } from '../Input.svelte';
|
|
6
|
+
|
|
7
|
+
export interface SelectContext {
|
|
8
|
+
select: (value: string, snippet: Snippet) => void;
|
|
9
|
+
value: string | undefined | null;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const [getSelectContext, setSelectContext] = createContext<SelectContext>();
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<script lang="ts">
|
|
16
|
+
interface Props extends InputProps<string> {
|
|
17
|
+
placeholder?: string;
|
|
18
|
+
children: Snippet;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
let { placeholder = '', children, ...props }: Props = $props();
|
|
22
|
+
|
|
23
|
+
let button = $state<HTMLButtonElement | undefined>();
|
|
24
|
+
let buttonWidth = $state<number>(200);
|
|
25
|
+
let popover = $state<Popover>();
|
|
26
|
+
let selectedSnippet = $state<Snippet>();
|
|
27
|
+
|
|
28
|
+
const value = $derived(props.form.value());
|
|
29
|
+
|
|
30
|
+
function select(newValue: string, snippet: Snippet) {
|
|
31
|
+
selectedSnippet = snippet;
|
|
32
|
+
if (newValue === value) return;
|
|
33
|
+
props.form.set(newValue);
|
|
34
|
+
popover?.close();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
setSelectContext({
|
|
38
|
+
select,
|
|
39
|
+
get value() {
|
|
40
|
+
return value;
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
</script>
|
|
44
|
+
|
|
45
|
+
<Input {...props}>
|
|
46
|
+
<button
|
|
47
|
+
type="button"
|
|
48
|
+
class="flex h-14 w-full flex-row items-center justify-start gap-2 px-4 py-2"
|
|
49
|
+
onclick={popover?.toggle}
|
|
50
|
+
bind:this={button}
|
|
51
|
+
bind:clientWidth={buttonWidth}
|
|
52
|
+
>
|
|
53
|
+
{#if selectedSnippet}
|
|
54
|
+
{@render selectedSnippet()}
|
|
55
|
+
{:else}
|
|
56
|
+
{placeholder}
|
|
57
|
+
{/if}
|
|
58
|
+
<ChevronDown class={['ml-auto transition-all', popover?.isOpen() && 'rotate-180']} />
|
|
59
|
+
</button>
|
|
60
|
+
</Input>
|
|
61
|
+
|
|
62
|
+
<Popover
|
|
63
|
+
bind:this={popover}
|
|
64
|
+
class="bg-surface-50-950 mt-2 flex flex-col gap-2 rounded p-2 shadow"
|
|
65
|
+
style={`min-width: ${buttonWidth}px`}
|
|
66
|
+
target={button}
|
|
67
|
+
>
|
|
68
|
+
{@render children()}
|
|
69
|
+
</Popover>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { type Snippet } from 'svelte';
|
|
3
|
+
import type { ClassValue } from 'svelte/elements';
|
|
4
|
+
import { getSelectContext } from './Select.svelte';
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
class?: ClassValue;
|
|
8
|
+
value: string;
|
|
9
|
+
children: Snippet;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
let {
|
|
13
|
+
class: clazz = 'flex flex-row justify-start items-center gap-2',
|
|
14
|
+
value,
|
|
15
|
+
children
|
|
16
|
+
}: Props = $props();
|
|
17
|
+
|
|
18
|
+
const context = getSelectContext();
|
|
19
|
+
|
|
20
|
+
// this needs to run in an effect so we can update the value from outside the component
|
|
21
|
+
$effect(function setValue() {
|
|
22
|
+
if (context.value === value) context.select(value, children);
|
|
23
|
+
});
|
|
24
|
+
</script>
|
|
25
|
+
|
|
26
|
+
<button
|
|
27
|
+
type="button"
|
|
28
|
+
class={[clazz]}
|
|
29
|
+
onclick={() => {
|
|
30
|
+
context.select(value, children);
|
|
31
|
+
}}
|
|
32
|
+
>
|
|
33
|
+
{@render children()}
|
|
34
|
+
</button>
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
<script lang="ts" module>
|
|
2
2
|
import { theme } from '$lib/theme.svelte';
|
|
3
3
|
import type { IvoryComponent } from '$lib/types';
|
|
4
|
-
import
|
|
4
|
+
import { merge } from '$lib/utils/merge';
|
|
5
5
|
import type { ClassValue } from 'svelte/elements';
|
|
6
|
-
import { twMerge } from 'tailwind-merge';
|
|
7
6
|
|
|
8
7
|
export interface HeadingProps extends IvoryComponent<HTMLHeadingElement> {
|
|
9
8
|
class?: ClassValue;
|
|
@@ -15,8 +14,10 @@
|
|
|
15
14
|
</script>
|
|
16
15
|
|
|
17
16
|
<h2
|
|
18
|
-
class={
|
|
19
|
-
|
|
17
|
+
class={merge(
|
|
18
|
+
'shrink-0 truncate text-lg font-bold select-none',
|
|
19
|
+
theme.current.heading?.class,
|
|
20
|
+
clazz
|
|
20
21
|
)}
|
|
21
22
|
{...rest}
|
|
22
23
|
>
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
<script lang="ts" module>
|
|
2
2
|
import { theme } from '$lib/theme.svelte';
|
|
3
3
|
import type { IvoryComponent, TransitionProps } from '$lib/types';
|
|
4
|
-
import
|
|
4
|
+
import { merge } from '$lib/utils/merge';
|
|
5
5
|
import { onMount, tick } from 'svelte';
|
|
6
6
|
import type { MouseEventHandler } from 'svelte/elements';
|
|
7
7
|
import { fade } from 'svelte/transition';
|
|
8
|
-
import { twMerge } from 'tailwind-merge';
|
|
9
8
|
|
|
10
9
|
export interface DialogProps extends IvoryComponent<HTMLElement>, TransitionProps {
|
|
11
10
|
/** Gets called when the dialog requests to close (Escape, backdrop click) */
|
|
@@ -61,12 +60,10 @@
|
|
|
61
60
|
onclick={handleBackdropClick}
|
|
62
61
|
oncancel={requestClose}
|
|
63
62
|
onclose={close}
|
|
64
|
-
class={
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
clazz
|
|
69
|
-
)
|
|
63
|
+
class={merge(
|
|
64
|
+
'h-full max-h-none w-screen max-w-full bg-transparent backdrop:bg-transparent',
|
|
65
|
+
theme.current.dialog?.class,
|
|
66
|
+
clazz
|
|
70
67
|
)}
|
|
71
68
|
in:inTransition
|
|
72
69
|
out:outTransition
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
<script lang="ts" module>
|
|
2
2
|
import type { TransitionProps } from '$lib/types';
|
|
3
|
+
import { merge } from '$lib/utils/merge';
|
|
3
4
|
import { X } from '@lucide/svelte';
|
|
4
|
-
import clsx from 'clsx';
|
|
5
5
|
import type { Snippet } from 'svelte';
|
|
6
6
|
import { fly } from 'svelte/transition';
|
|
7
|
-
import { twMerge } from 'tailwind-merge';
|
|
8
7
|
import { HiddenBackground } from '..';
|
|
9
8
|
import Heading from '../Heading.svelte';
|
|
10
9
|
|
|
@@ -58,14 +57,12 @@
|
|
|
58
57
|
}}
|
|
59
58
|
>
|
|
60
59
|
<div
|
|
61
|
-
class={
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
])
|
|
68
|
-
)}
|
|
60
|
+
class={merge([
|
|
61
|
+
'bg-surface-50-950 absolute top-0 flex h-full flex-col gap-4 p-4',
|
|
62
|
+
placement === 'left' && 'left-0',
|
|
63
|
+
placement === 'right' && 'right-0',
|
|
64
|
+
clazz
|
|
65
|
+
])}
|
|
69
66
|
onclick={(e) => e.stopPropagation()}
|
|
70
67
|
in:inTransition|global
|
|
71
68
|
out:outTransition|global
|
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
export { default as Drawer } from './drawer/Drawer.svelte';
|
|
2
2
|
export { default as Heading } from './Heading.svelte';
|
|
3
|
-
export {
|
|
4
|
-
default as HiddenBackground,
|
|
5
|
-
type HiddenBackgroundProps
|
|
6
|
-
} from './hiddenBackground/HiddenBackground.svelte';
|
|
3
|
+
export { default as HiddenBackground } from './hiddenBackground/HiddenBackground.svelte';
|
|
7
4
|
export { default as Modal, type ModalProps, type ModalVariant } from './modal/Modal.svelte';
|
|
8
5
|
export {
|
|
9
6
|
default as Popover,
|
|
10
7
|
type PopoverPlacement,
|
|
11
8
|
type PopoverProps
|
|
12
9
|
} from './popover/Popover.svelte';
|
|
13
|
-
export { default as Portal } from './portal';
|
|
14
10
|
export {
|
|
15
11
|
getTabContext,
|
|
16
12
|
Tab,
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
<script lang="ts" module>
|
|
2
2
|
import { theme } from '$lib/theme.svelte';
|
|
3
3
|
import type { TransitionProps } from '$lib/types';
|
|
4
|
+
import { merge } from '$lib/utils/merge';
|
|
4
5
|
import { X } from '@lucide/svelte';
|
|
5
|
-
import clsx from 'clsx';
|
|
6
6
|
import { type Snippet } from 'svelte';
|
|
7
7
|
import type { ClassValue, MouseEventHandler } from 'svelte/elements';
|
|
8
8
|
import { fade } from 'svelte/transition';
|
|
9
|
-
import { twMerge } from 'tailwind-merge';
|
|
10
9
|
import { Heading, HiddenBackground } from '..';
|
|
11
10
|
|
|
12
11
|
/** Props for the modal, expose if you overwrite the defaults in a custom component */
|
|
@@ -95,13 +94,11 @@
|
|
|
95
94
|
</div>
|
|
96
95
|
{:else}
|
|
97
96
|
<div
|
|
98
|
-
class={
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
])
|
|
104
|
-
)}
|
|
97
|
+
class={merge([
|
|
98
|
+
'bg-surface-50-950 flex max-h-full max-w-full flex-col overflow-hidden rounded',
|
|
99
|
+
theme.current.modal?.class,
|
|
100
|
+
clazz
|
|
101
|
+
])}
|
|
105
102
|
{...rest}
|
|
106
103
|
{onclick}
|
|
107
104
|
in:inTransition|global
|
|
@@ -131,12 +128,10 @@
|
|
|
131
128
|
</button>
|
|
132
129
|
</div>
|
|
133
130
|
<div
|
|
134
|
-
class={
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
innerClass
|
|
139
|
-
)
|
|
131
|
+
class={merge(
|
|
132
|
+
'flex grow flex-col gap-4 overflow-hidden bg-inherit p-4 pt-3',
|
|
133
|
+
theme.current.modal?.innerClass,
|
|
134
|
+
innerClass
|
|
140
135
|
)}
|
|
141
136
|
>
|
|
142
137
|
{@render children?.()}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { browser } from '$app/environment';
|
|
3
3
|
import { theme } from '$lib/theme.svelte';
|
|
4
4
|
import type { IvoryComponent } from '$lib/types';
|
|
5
|
+
import { clickOutside } from '$lib/utils/attachments';
|
|
5
6
|
import {
|
|
6
7
|
autoPlacement,
|
|
7
8
|
autoUpdate,
|
|
@@ -12,8 +13,6 @@
|
|
|
12
13
|
} from '@floating-ui/dom';
|
|
13
14
|
import clsx from 'clsx';
|
|
14
15
|
import { twMerge } from 'tailwind-merge';
|
|
15
|
-
import { clickOutside } from '../../../utils/actions/clickOutside';
|
|
16
|
-
import { Dialog } from '../dialog';
|
|
17
16
|
|
|
18
17
|
/** Possible placements for the popover */
|
|
19
18
|
export type PopoverPlacement = ComputePositionConfig['placement'];
|
|
@@ -99,15 +98,13 @@
|
|
|
99
98
|
A popover, positions itself relative to a target element.
|
|
100
99
|
-->
|
|
101
100
|
{#if currentlyOpen}
|
|
102
|
-
<
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
</div>
|
|
112
|
-
</Dialog>
|
|
101
|
+
<div
|
|
102
|
+
class={twMerge(clsx('absolute', theme.current.popover?.class, clazz))}
|
|
103
|
+
style={style + ' ' + externalStyle}
|
|
104
|
+
bind:this={popover}
|
|
105
|
+
{@attach clickOutside({ callback: onClickOutside, target })}
|
|
106
|
+
{...rest}
|
|
107
|
+
>
|
|
108
|
+
{@render children?.()}
|
|
109
|
+
</div>
|
|
113
110
|
{/if}
|
|
@@ -3,10 +3,9 @@
|
|
|
3
3
|
import { theme } from '$lib/theme.svelte';
|
|
4
4
|
import type { IvoryComponent } from '$lib/types';
|
|
5
5
|
import { pseudoRandomId } from '$lib/utils/functions/index';
|
|
6
|
-
import
|
|
6
|
+
import { merge } from '$lib/utils/merge';
|
|
7
7
|
import { onMount, type Snippet } from 'svelte';
|
|
8
8
|
import type { ClassValue } from 'svelte/elements';
|
|
9
|
-
import { twMerge } from 'tailwind-merge';
|
|
10
9
|
import { getTabContext } from './Tabs.svelte';
|
|
11
10
|
|
|
12
11
|
export interface TabProps extends Omit<IvoryComponent<HTMLElement>, 'children'> {
|
|
@@ -52,12 +51,10 @@
|
|
|
52
51
|
|
|
53
52
|
<svelte:element
|
|
54
53
|
this={href ? 'a' : 'button'}
|
|
55
|
-
class={
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
typeof clazz === 'function' ? clazz(selected) : clazz
|
|
60
|
-
)
|
|
54
|
+
class={merge(
|
|
55
|
+
'btn flex h-fit w-fit shrink-0 items-center justify-center px-0 text-xl font-bold select-none',
|
|
56
|
+
theme.current.tabs?.tab?.class?.(selected),
|
|
57
|
+
typeof clazz === 'function' ? clazz(selected) : clazz
|
|
61
58
|
)}
|
|
62
59
|
onclick={href
|
|
63
60
|
? undefined
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
<script lang="ts" module>
|
|
2
|
-
import
|
|
2
|
+
import { merge } from '$lib/utils/merge';
|
|
3
3
|
import type { Snippet } from 'svelte';
|
|
4
4
|
import type { ClassValue, MouseEventHandler } from 'svelte/elements';
|
|
5
|
-
import { twMerge } from 'tailwind-merge';
|
|
6
5
|
import Popover, { type PopoverPlacement } from '../popover/Popover.svelte';
|
|
7
6
|
|
|
8
7
|
export interface TooltipProps {
|
|
@@ -84,11 +83,9 @@
|
|
|
84
83
|
bind:this={popover}
|
|
85
84
|
{target}
|
|
86
85
|
{placement}
|
|
87
|
-
class={
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
tooltipClass
|
|
91
|
-
)
|
|
86
|
+
class={merge(
|
|
87
|
+
'bg-surface-50-950 max-w-96 -translate-y-0.5 rounded px-4 py-1 shadow-lg',
|
|
88
|
+
tooltipClass
|
|
92
89
|
)}
|
|
93
90
|
>
|
|
94
91
|
{#if typeof tooltip === 'string'}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
<script lang="ts" module>
|
|
2
2
|
import { theme } from '$lib/theme.svelte';
|
|
3
|
-
import
|
|
3
|
+
import { merge } from '$lib/utils/merge';
|
|
4
4
|
import { type Snippet } from 'svelte';
|
|
5
5
|
import type { ClassValue } from 'svelte/elements';
|
|
6
|
-
import { twMerge } from 'tailwind-merge';
|
|
7
6
|
import type { ColumnConfig } from './columnController.svelte';
|
|
8
7
|
import { getRowContext } from './Row.svelte';
|
|
9
8
|
import { getTableContext } from './Table.svelte';
|
|
@@ -67,14 +66,12 @@
|
|
|
67
66
|
href={!allowClicking ? rowContext.href : undefined}
|
|
68
67
|
type={allowClicking ? 'button' : undefined}
|
|
69
68
|
style={ignoreWidth ? '' : `width: ${widthStyle}`}
|
|
70
|
-
class={
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
])
|
|
77
|
-
)}
|
|
69
|
+
class={merge([
|
|
70
|
+
'box-border flex h-full shrink-0 flex-row items-center justify-start gap-1 truncate',
|
|
71
|
+
column.width !== 0 && 'border-r-[calc(var(--spacing)*2)] border-transparent',
|
|
72
|
+
theme.current.table?.column?.class,
|
|
73
|
+
clazz
|
|
74
|
+
])}
|
|
78
75
|
>
|
|
79
76
|
{@render children()}
|
|
80
77
|
</svelte:element>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script lang="ts" module>
|
|
2
2
|
import { getContext, setContext, type Snippet } from 'svelte';
|
|
3
|
-
import { resize } from '../../utils/
|
|
3
|
+
import { resize } from '../../utils/attachments';
|
|
4
4
|
import type { ColumnController } from './columnController.svelte';
|
|
5
5
|
|
|
6
6
|
const CONTEXT = {};
|
|
@@ -53,12 +53,12 @@
|
|
|
53
53
|
{@render children?.()}
|
|
54
54
|
{#if column.resizable}
|
|
55
55
|
<button
|
|
56
|
+
{@attach resize({ resized: onResize, dragging: onDragging })}
|
|
56
57
|
type="button"
|
|
57
58
|
class={[
|
|
58
59
|
'relative ml-auto h-full w-4 shrink-0 cursor-col-resize bg-inherit after:absolute after:top-0 after:right-2 after:h-full after:w-px',
|
|
59
60
|
dragging ? 'after:bg-primary-400-600' : 'group-hover:after:bg-surface-300-700'
|
|
60
61
|
]}
|
|
61
|
-
use:resize={{ resized: onResize, dragging: onDragging }}
|
|
62
62
|
onmouseenter={onHoverStart}
|
|
63
63
|
onmouseleave={onHoverEnd}
|
|
64
64
|
onfocusin={onHoverStart}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
<script lang="ts" module>
|
|
2
|
+
import { merge } from '$lib/utils/merge';
|
|
2
3
|
import { ChevronRight } from '@lucide/svelte';
|
|
3
|
-
import clsx from 'clsx';
|
|
4
4
|
import { getContext, setContext, untrack, type Snippet } from 'svelte';
|
|
5
5
|
import type { ClassValue } from 'svelte/elements';
|
|
6
6
|
import { SvelteSet } from 'svelte/reactivity';
|
|
7
|
-
import { twMerge } from 'tailwind-merge';
|
|
8
7
|
import ColumnComponent from './Column.svelte';
|
|
9
8
|
import { ColumnController, type ColumnConfig } from './columnController.svelte';
|
|
10
9
|
import ColumnHead from './ColumnHead.svelte';
|
|
@@ -200,17 +199,15 @@
|
|
|
200
199
|
bind:this={list}
|
|
201
200
|
bind:b_scrollTop
|
|
202
201
|
data={results.entries}
|
|
203
|
-
class={
|
|
202
|
+
class={merge(['flex flex-col overflow-hidden border-transparent', clazz])}
|
|
204
203
|
rowClass={['pl-2 pr-4', rowClass]}
|
|
205
204
|
{rowHeight}
|
|
206
205
|
>
|
|
207
206
|
{#snippet header()}
|
|
208
207
|
<div
|
|
209
|
-
class={
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
headerClass
|
|
213
|
-
)
|
|
208
|
+
class={merge(
|
|
209
|
+
'flex w-fit min-w-full flex-row border-b border-inherit pr-4 pl-2',
|
|
210
|
+
headerClass
|
|
214
211
|
)}
|
|
215
212
|
>
|
|
216
213
|
{#if results.someHaveChildren}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
<script lang="ts" generics="T extends { id: string }">
|
|
2
|
-
import
|
|
2
|
+
import { merge } from '$lib/utils/merge';
|
|
3
3
|
import { onMount, tick, untrack, type Snippet } from 'svelte';
|
|
4
4
|
import type { ClassValue } from 'svelte/elements';
|
|
5
|
-
import { twMerge } from 'tailwind-merge';
|
|
6
5
|
|
|
7
6
|
type Props<T> = {
|
|
8
7
|
class?: ClassValue;
|
|
@@ -27,7 +26,7 @@
|
|
|
27
26
|
}: Props<T> = $props();
|
|
28
27
|
|
|
29
28
|
const finalRowClass = $derived(
|
|
30
|
-
|
|
29
|
+
merge(['flex w-full shrink-0 grow flex-row items-center overflow-hidden', rowClass])
|
|
31
30
|
);
|
|
32
31
|
|
|
33
32
|
let viewportReactivity = $state(0);
|
|
@@ -93,11 +92,7 @@
|
|
|
93
92
|
});
|
|
94
93
|
</script>
|
|
95
94
|
|
|
96
|
-
<div
|
|
97
|
-
class={twMerge(
|
|
98
|
-
clsx(['scroll relative flex grow flex-col overflow-hidden border-inherit', clazz])
|
|
99
|
-
)}
|
|
100
|
-
>
|
|
95
|
+
<div class={merge(['scroll relative flex grow flex-col overflow-hidden border-inherit', clazz])}>
|
|
101
96
|
{#if header}
|
|
102
97
|
<div class="h-fit w-full border-inherit">
|
|
103
98
|
<div
|
package/src/lib/theme.svelte.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
import type { RemoteFormIssue } from '@sveltejs/kit';
|
|
1
2
|
import type { ClassValue } from 'svelte/elements';
|
|
2
3
|
|
|
3
4
|
export interface Theme {
|
|
5
|
+
checkbox?: {
|
|
6
|
+
class?: (checked: boolean, partial: boolean) => ClassValue;
|
|
7
|
+
};
|
|
4
8
|
heading?: {
|
|
5
9
|
class?: ClassValue;
|
|
6
10
|
};
|
|
@@ -27,6 +31,20 @@ export interface Theme {
|
|
|
27
31
|
popover?: {
|
|
28
32
|
class?: ClassValue;
|
|
29
33
|
};
|
|
34
|
+
input?: {
|
|
35
|
+
outerClass?: ClassValue;
|
|
36
|
+
class?: (value: boolean, issues?: boolean) => ClassValue;
|
|
37
|
+
label?: {
|
|
38
|
+
class?: (value: boolean, issues?: boolean) => ClassValue;
|
|
39
|
+
};
|
|
40
|
+
issues?: {
|
|
41
|
+
issue?: {
|
|
42
|
+
label?: (issue: RemoteFormIssue) => string;
|
|
43
|
+
class?: ClassValue;
|
|
44
|
+
};
|
|
45
|
+
class?: ClassValue;
|
|
46
|
+
};
|
|
47
|
+
};
|
|
30
48
|
}
|
|
31
49
|
|
|
32
50
|
function createTheme() {
|
package/src/lib/types.ts
CHANGED
|
@@ -2,8 +2,9 @@ import type { HTMLAttributes } from 'svelte/elements';
|
|
|
2
2
|
import type { TransitionConfig } from 'svelte/transition';
|
|
3
3
|
|
|
4
4
|
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
5
|
-
export interface IvoryComponent<
|
|
6
|
-
extends
|
|
5
|
+
export interface IvoryComponent<
|
|
6
|
+
RootElement extends EventTarget
|
|
7
|
+
> extends HTMLAttributes<RootElement> {}
|
|
7
8
|
|
|
8
9
|
export interface TransitionProps {
|
|
9
10
|
inTransition?: (node: Element) => TransitionConfig;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Attachment } from 'svelte/attachments';
|
|
2
|
+
|
|
3
|
+
interface ClickOutsideParams {
|
|
4
|
+
/** Callback to be called when clicking outside of node */
|
|
5
|
+
callback: (e: MouseEvent) => void;
|
|
6
|
+
/** Callback is also not fired if the click target is inside this element */
|
|
7
|
+
target?: Element;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const clickOutside =
|
|
11
|
+
(params: ((e: MouseEvent) => void) | ClickOutsideParams): Attachment =>
|
|
12
|
+
(node) => {
|
|
13
|
+
function handleClick(event: MouseEvent) {
|
|
14
|
+
if (
|
|
15
|
+
!(event.target instanceof Node) ||
|
|
16
|
+
!node ||
|
|
17
|
+
node.contains(event.target) ||
|
|
18
|
+
event.defaultPrevented
|
|
19
|
+
)
|
|
20
|
+
return;
|
|
21
|
+
|
|
22
|
+
if (typeof params === 'function') {
|
|
23
|
+
params(event);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (params.target?.contains(event.target)) return;
|
|
28
|
+
params.callback(event);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
document.addEventListener('click', handleClick, true);
|
|
32
|
+
|
|
33
|
+
return () => {
|
|
34
|
+
document.removeEventListener('click', handleClick, true);
|
|
35
|
+
};
|
|
36
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { Attachment } from 'svelte/attachments';
|
|
2
|
+
|
|
3
|
+
export const focusTrap =
|
|
4
|
+
(enabled: boolean): Attachment =>
|
|
5
|
+
(node) => {
|
|
6
|
+
const elementWhitelist =
|
|
7
|
+
'a[href], button, input, textarea, select, details, [tabindex]:not([tabindex="-1"])';
|
|
8
|
+
let firstElement: HTMLElement;
|
|
9
|
+
let lastElement: HTMLElement;
|
|
10
|
+
|
|
11
|
+
function onFirstElemKeydown(e: KeyboardEvent): void {
|
|
12
|
+
if (e.shiftKey && e.code === 'Tab') {
|
|
13
|
+
e.preventDefault();
|
|
14
|
+
lastElement.focus();
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function onLastElemKeydown(e: KeyboardEvent): void {
|
|
19
|
+
if (!e.shiftKey && e.code === 'Tab') {
|
|
20
|
+
e.preventDefault();
|
|
21
|
+
firstElement.focus();
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function scanElements(fromObserver: boolean) {
|
|
26
|
+
if (enabled === false) return;
|
|
27
|
+
const focusableElems: HTMLElement[] = Array.from(
|
|
28
|
+
node.querySelectorAll(elementWhitelist)
|
|
29
|
+
);
|
|
30
|
+
if (focusableElems.length) {
|
|
31
|
+
// Set first/last focusable elements
|
|
32
|
+
firstElement = focusableElems[0];
|
|
33
|
+
lastElement = focusableElems[focusableElems.length - 1];
|
|
34
|
+
// Auto-focus first focusable element only when not called from mutation observer
|
|
35
|
+
if (!fromObserver) firstElement.focus();
|
|
36
|
+
// Listen for keydown on first & last element
|
|
37
|
+
firstElement.addEventListener('keydown', onFirstElemKeydown);
|
|
38
|
+
lastElement.addEventListener('keydown', onLastElemKeydown);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
scanElements(false);
|
|
42
|
+
|
|
43
|
+
function cleanUp(): void {
|
|
44
|
+
if (firstElement) firstElement.removeEventListener('keydown', onFirstElemKeydown);
|
|
45
|
+
if (lastElement) lastElement.removeEventListener('keydown', onLastElemKeydown);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Re-determine focusable elements when mutations are observed
|
|
49
|
+
const onObservationChange = (
|
|
50
|
+
mutationRecords: MutationRecord[],
|
|
51
|
+
observer: MutationObserver
|
|
52
|
+
) => {
|
|
53
|
+
if (mutationRecords.length) {
|
|
54
|
+
cleanUp();
|
|
55
|
+
scanElements(true);
|
|
56
|
+
}
|
|
57
|
+
return observer;
|
|
58
|
+
};
|
|
59
|
+
const observer = new MutationObserver(onObservationChange);
|
|
60
|
+
observer.observe(node, { childList: true, subtree: true });
|
|
61
|
+
|
|
62
|
+
// Lifecycle
|
|
63
|
+
return () => {
|
|
64
|
+
cleanUp();
|
|
65
|
+
observer.disconnect();
|
|
66
|
+
};
|
|
67
|
+
};
|