lithesome 0.4.0 → 0.5.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/dist/components/Hovercard/Hovercard.svelte +43 -0
- package/dist/components/Hovercard/Hovercard.svelte.d.ts +30 -0
- package/dist/components/Hovercard/HovercardContent.svelte +110 -0
- package/dist/components/Hovercard/HovercardContent.svelte.d.ts +35 -0
- package/dist/components/Hovercard/HovercardTrigger.svelte +57 -0
- package/dist/components/Hovercard/HovercardTrigger.svelte.d.ts +17 -0
- package/dist/components/Hovercard/context.svelte.d.ts +27 -0
- package/dist/components/Hovercard/context.svelte.js +36 -0
- package/dist/components/Hovercard/index.d.ts +3 -0
- package/dist/components/Hovercard/index.js +3 -0
- package/dist/components/Menu/MenuTrigger.svelte +1 -1
- package/dist/components/Popover/Popover.svelte +1 -2
- package/dist/components/Popover/PopoverTrigger.svelte +5 -3
- package/dist/components/Select/SelectTrigger.svelte +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/internal/helpers/utils.svelte.d.ts +7 -0
- package/dist/internal/helpers/utils.svelte.js +9 -0
- package/package.json +1 -1
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<script context="module">import { getContext } from "svelte";
|
|
2
|
+
import { HovercardContext } from "./context.svelte.js";
|
|
3
|
+
const contextName = "hovercard-context";
|
|
4
|
+
export const context = () => getContext(contextName);
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<script>import { useActions, classProp, parseDelay } from "../../internal/index.js";
|
|
8
|
+
import { setContext } from "svelte";
|
|
9
|
+
let {
|
|
10
|
+
children,
|
|
11
|
+
use = [],
|
|
12
|
+
class: klass,
|
|
13
|
+
visible = $bindable(false),
|
|
14
|
+
self = $bindable(),
|
|
15
|
+
delay = 700,
|
|
16
|
+
...props
|
|
17
|
+
} = $props();
|
|
18
|
+
const delays = parseDelay(delay);
|
|
19
|
+
const ctx = new HovercardContext(
|
|
20
|
+
{ visible, delays },
|
|
21
|
+
{
|
|
22
|
+
onChange(val) {
|
|
23
|
+
visible = val;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
);
|
|
27
|
+
setContext(contextName, ctx);
|
|
28
|
+
$effect(() => {
|
|
29
|
+
ctx.visible = visible;
|
|
30
|
+
});
|
|
31
|
+
</script>
|
|
32
|
+
|
|
33
|
+
<div
|
|
34
|
+
bind:this={self}
|
|
35
|
+
use:useActions={use}
|
|
36
|
+
id={ctx.uid()}
|
|
37
|
+
class={classProp(klass, { visible: ctx.visible })}
|
|
38
|
+
data-hovercard=""
|
|
39
|
+
data-state={ctx.visible ? 'opened' : 'closed'}
|
|
40
|
+
{...props}
|
|
41
|
+
>
|
|
42
|
+
{@render children({ visible: ctx.visible })}
|
|
43
|
+
</div>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { SvelteComponent } from "svelte";
|
|
2
|
+
import { HovercardContext } from './context.svelte.js';
|
|
3
|
+
export declare const context: () => HovercardContext;
|
|
4
|
+
import { type BaseProps } from '../../internal/index.js';
|
|
5
|
+
declare const __propDef: {
|
|
6
|
+
props: BaseProps<HTMLDivElement, {
|
|
7
|
+
visible: boolean;
|
|
8
|
+
}> & {
|
|
9
|
+
/**
|
|
10
|
+
* Whether or not the content is visible or not.
|
|
11
|
+
*/
|
|
12
|
+
visible?: boolean | undefined;
|
|
13
|
+
/**
|
|
14
|
+
* The delay between the the content being visible or not.
|
|
15
|
+
*
|
|
16
|
+
* Passing an array will allow you to change the delays for in and out.
|
|
17
|
+
*/
|
|
18
|
+
delay?: number | [number, number] | undefined;
|
|
19
|
+
};
|
|
20
|
+
events: {
|
|
21
|
+
[evt: string]: CustomEvent<any>;
|
|
22
|
+
};
|
|
23
|
+
slots: {};
|
|
24
|
+
};
|
|
25
|
+
export type HovercardProps = typeof __propDef.props;
|
|
26
|
+
export type HovercardEvents = typeof __propDef.events;
|
|
27
|
+
export type HovercardSlots = typeof __propDef.slots;
|
|
28
|
+
export default class Hovercard extends SvelteComponent<HovercardProps, HovercardEvents, HovercardSlots> {
|
|
29
|
+
}
|
|
30
|
+
export {};
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
<script>import { context } from "./Hovercard.svelte";
|
|
2
|
+
import {
|
|
3
|
+
clickOutside,
|
|
4
|
+
anchorElement,
|
|
5
|
+
portal,
|
|
6
|
+
useActions,
|
|
7
|
+
trap,
|
|
8
|
+
getTransition,
|
|
9
|
+
classProp
|
|
10
|
+
} from "../../internal/index.js";
|
|
11
|
+
import { log } from "../../internal/index.js";
|
|
12
|
+
import { onMount } from "svelte";
|
|
13
|
+
let {
|
|
14
|
+
children,
|
|
15
|
+
transition,
|
|
16
|
+
use = [],
|
|
17
|
+
portalTarget = "body",
|
|
18
|
+
class: klass,
|
|
19
|
+
self = $bindable(),
|
|
20
|
+
placement = "bottom",
|
|
21
|
+
constrainViewport,
|
|
22
|
+
sameWidth = false,
|
|
23
|
+
onMouseenter,
|
|
24
|
+
onMouseleave,
|
|
25
|
+
...props
|
|
26
|
+
} = $props();
|
|
27
|
+
const ctx = context();
|
|
28
|
+
let contentCleanup = $state(void 0);
|
|
29
|
+
const _transition = getTransition(transition);
|
|
30
|
+
const attrs = $derived({
|
|
31
|
+
id: ctx.uid("content"),
|
|
32
|
+
"aria-labelledby": ctx.uid("trigger"),
|
|
33
|
+
class: classProp(klass, { visible: ctx.visible }),
|
|
34
|
+
"data-menucontent": "",
|
|
35
|
+
role: "menu",
|
|
36
|
+
tabindex: -1
|
|
37
|
+
});
|
|
38
|
+
onMount(async () => {
|
|
39
|
+
if (!ctx)
|
|
40
|
+
log.error("<HoverCardContent> Must be a direct child of <HoverCard />");
|
|
41
|
+
});
|
|
42
|
+
$effect(() => {
|
|
43
|
+
if (ctx.visible && self)
|
|
44
|
+
ctx.content = self;
|
|
45
|
+
});
|
|
46
|
+
$effect(() => {
|
|
47
|
+
if (ctx.visible && ctx.trigger && ctx.content) {
|
|
48
|
+
contentCleanup = anchorElement(ctx.trigger, ctx.content, {
|
|
49
|
+
placement,
|
|
50
|
+
constrainViewport,
|
|
51
|
+
sameWidth
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
return () => {
|
|
55
|
+
contentCleanup?.();
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
const handleMouseenter = (e) => {
|
|
59
|
+
onMouseenter?.(e);
|
|
60
|
+
ctx.hovered = true;
|
|
61
|
+
ctx.timeout = null;
|
|
62
|
+
};
|
|
63
|
+
const handleMouseleave = (e) => {
|
|
64
|
+
onMouseleave?.(e);
|
|
65
|
+
ctx.hovered = false;
|
|
66
|
+
ctx.close();
|
|
67
|
+
};
|
|
68
|
+
</script>
|
|
69
|
+
|
|
70
|
+
{#if _transition}
|
|
71
|
+
{#if ctx.visible}
|
|
72
|
+
<div
|
|
73
|
+
bind:this={self}
|
|
74
|
+
use:clickOutside={{
|
|
75
|
+
exclude: [ctx.trigger],
|
|
76
|
+
callback: () => {
|
|
77
|
+
ctx.visible = false;
|
|
78
|
+
}
|
|
79
|
+
}}
|
|
80
|
+
use:portal={portalTarget}
|
|
81
|
+
use:useActions={use}
|
|
82
|
+
in:_transition.in.fn={_transition.in.params}
|
|
83
|
+
out:_transition.out.fn={_transition.out.params}
|
|
84
|
+
onmouseenter={handleMouseenter}
|
|
85
|
+
onmouseleave={handleMouseleave}
|
|
86
|
+
{...attrs}
|
|
87
|
+
{...props}
|
|
88
|
+
>
|
|
89
|
+
{@render children({ visible: ctx.visible })}
|
|
90
|
+
</div>
|
|
91
|
+
{/if}
|
|
92
|
+
{:else if ctx.visible}
|
|
93
|
+
<div
|
|
94
|
+
bind:this={self}
|
|
95
|
+
use:clickOutside={{
|
|
96
|
+
exclude: [ctx.trigger],
|
|
97
|
+
callback: () => {
|
|
98
|
+
ctx.visible = false;
|
|
99
|
+
}
|
|
100
|
+
}}
|
|
101
|
+
use:portal={portalTarget}
|
|
102
|
+
use:useActions={use}
|
|
103
|
+
onmouseenter={handleMouseenter}
|
|
104
|
+
onmouseleave={handleMouseleave}
|
|
105
|
+
{...attrs}
|
|
106
|
+
{...props}
|
|
107
|
+
>
|
|
108
|
+
{@render children({ visible: ctx.visible })}
|
|
109
|
+
</div>
|
|
110
|
+
{/if}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { SvelteComponent } from "svelte";
|
|
2
|
+
import { type Transition, type BaseProps, type Handler } from '../../internal/index.js';
|
|
3
|
+
import type { Placement } from '@floating-ui/dom';
|
|
4
|
+
declare const __propDef: {
|
|
5
|
+
props: BaseProps<HTMLDivElement, {
|
|
6
|
+
visible: boolean;
|
|
7
|
+
}> & {
|
|
8
|
+
/**
|
|
9
|
+
* The `svelte/transtion` you wish to use.
|
|
10
|
+
*
|
|
11
|
+
* @see https://lithesome.dev/docs/api#transition-prop
|
|
12
|
+
*/
|
|
13
|
+
transition?: Transition | undefined;
|
|
14
|
+
/** The element to portal the content menu to. */
|
|
15
|
+
portalTarget?: string | HTMLElement | undefined;
|
|
16
|
+
/** The anchor point of the content relative to the trigger. */
|
|
17
|
+
placement?: Placement | undefined;
|
|
18
|
+
/** Keeps the content from ever growing outside of the viewport. */
|
|
19
|
+
constrainViewport?: boolean | undefined;
|
|
20
|
+
/** Makes the content the same width as the trigger. */
|
|
21
|
+
sameWidth?: boolean | undefined;
|
|
22
|
+
onMouseenter?: Handler<MouseEvent, HTMLDivElement> | undefined;
|
|
23
|
+
onMouseleave?: Handler<MouseEvent, HTMLDivElement> | undefined;
|
|
24
|
+
};
|
|
25
|
+
events: {
|
|
26
|
+
[evt: string]: CustomEvent<any>;
|
|
27
|
+
};
|
|
28
|
+
slots: {};
|
|
29
|
+
};
|
|
30
|
+
export type HovercardContentProps = typeof __propDef.props;
|
|
31
|
+
export type HovercardContentEvents = typeof __propDef.events;
|
|
32
|
+
export type HovercardContentSlots = typeof __propDef.slots;
|
|
33
|
+
export default class HovercardContent extends SvelteComponent<HovercardContentProps, HovercardContentEvents, HovercardContentSlots> {
|
|
34
|
+
}
|
|
35
|
+
export {};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
<script>import { context } from "./Hovercard.svelte";
|
|
2
|
+
import {
|
|
3
|
+
log,
|
|
4
|
+
setNodeProps,
|
|
5
|
+
addEventListeners,
|
|
6
|
+
useActions,
|
|
7
|
+
removeNodeProps,
|
|
8
|
+
classProp
|
|
9
|
+
} from "../../internal/index.js";
|
|
10
|
+
import { onMount } from "svelte";
|
|
11
|
+
let { children, class: klass, use = [], self = $bindable(), ...props } = $props();
|
|
12
|
+
const ctx = context();
|
|
13
|
+
onMount(() => {
|
|
14
|
+
if (!self)
|
|
15
|
+
return;
|
|
16
|
+
if (self && self.children.length > 1) {
|
|
17
|
+
log.error("<HoverCardTrigger /> comoponent can only take 1 child node.");
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const target = self.children[0];
|
|
21
|
+
setNodeProps(target, {
|
|
22
|
+
id: ctx.uid("trigger"),
|
|
23
|
+
role: "button",
|
|
24
|
+
"aria-haspopup": "dialog",
|
|
25
|
+
"aria-expanded": "false"
|
|
26
|
+
});
|
|
27
|
+
addEventListeners(target, {
|
|
28
|
+
mouseenter: () => ctx.open(),
|
|
29
|
+
mouseleave: () => ctx.close()
|
|
30
|
+
});
|
|
31
|
+
ctx.trigger = target;
|
|
32
|
+
});
|
|
33
|
+
$effect(() => {
|
|
34
|
+
if (!ctx.trigger)
|
|
35
|
+
return;
|
|
36
|
+
const target = ctx.trigger;
|
|
37
|
+
if (ctx.visible) {
|
|
38
|
+
setNodeProps(target, {
|
|
39
|
+
"aria-expanded": "true",
|
|
40
|
+
"aria-controls": ctx.uid("content")
|
|
41
|
+
});
|
|
42
|
+
} else {
|
|
43
|
+
setNodeProps(target, { "aria-expanded": "false" });
|
|
44
|
+
removeNodeProps(target, "aria-controls");
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
</script>
|
|
48
|
+
|
|
49
|
+
<div
|
|
50
|
+
bind:this={self}
|
|
51
|
+
use:useActions={use}
|
|
52
|
+
class={classProp(klass, { visible: ctx.visible })}
|
|
53
|
+
data-hovercardtrigger=""
|
|
54
|
+
{...props}
|
|
55
|
+
>
|
|
56
|
+
{@render children({ visible: ctx.visible })}
|
|
57
|
+
</div>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { SvelteComponent } from "svelte";
|
|
2
|
+
import { type BaseProps } from '../../internal/index.js';
|
|
3
|
+
declare const __propDef: {
|
|
4
|
+
props: BaseProps<HTMLDivElement, {
|
|
5
|
+
visible: boolean;
|
|
6
|
+
}>;
|
|
7
|
+
events: {
|
|
8
|
+
[evt: string]: CustomEvent<any>;
|
|
9
|
+
};
|
|
10
|
+
slots: {};
|
|
11
|
+
};
|
|
12
|
+
export type HovercardTriggerProps = typeof __propDef.props;
|
|
13
|
+
export type HovercardTriggerEvents = typeof __propDef.events;
|
|
14
|
+
export type HovercardTriggerSlots = typeof __propDef.slots;
|
|
15
|
+
export default class HovercardTrigger extends SvelteComponent<HovercardTriggerProps, HovercardTriggerEvents, HovercardTriggerSlots> {
|
|
16
|
+
}
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Context } from '../../internal/index.js';
|
|
2
|
+
interface Init {
|
|
3
|
+
visible: boolean;
|
|
4
|
+
delays: {
|
|
5
|
+
in: number;
|
|
6
|
+
out: number;
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
interface Hooks {
|
|
10
|
+
onChange: (value: boolean) => void;
|
|
11
|
+
}
|
|
12
|
+
export declare class HovercardContext extends Context<Hooks> {
|
|
13
|
+
#private;
|
|
14
|
+
visible: boolean;
|
|
15
|
+
trigger: HTMLElement | null;
|
|
16
|
+
content: HTMLElement | null;
|
|
17
|
+
timeout: number | null;
|
|
18
|
+
delays: {
|
|
19
|
+
in: number;
|
|
20
|
+
out: number;
|
|
21
|
+
};
|
|
22
|
+
hovered: boolean;
|
|
23
|
+
constructor(init: Init, hooks: Hooks);
|
|
24
|
+
open(): void;
|
|
25
|
+
close(): void;
|
|
26
|
+
}
|
|
27
|
+
export {};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Context, effects } from '../../internal/index.js';
|
|
2
|
+
export class HovercardContext extends Context {
|
|
3
|
+
visible = $state(false);
|
|
4
|
+
trigger = $state(null);
|
|
5
|
+
content = $state(null);
|
|
6
|
+
timeout = $state(null);
|
|
7
|
+
delays = $state({ in: 700, out: 700 });
|
|
8
|
+
hovered = $state(false);
|
|
9
|
+
constructor(init, hooks) {
|
|
10
|
+
super('hovercard', hooks);
|
|
11
|
+
this.visible = init.visible;
|
|
12
|
+
this.delays = init.delays;
|
|
13
|
+
}
|
|
14
|
+
open() {
|
|
15
|
+
if (this.timeout) {
|
|
16
|
+
clearTimeout(this.timeout);
|
|
17
|
+
this.timeout = null;
|
|
18
|
+
}
|
|
19
|
+
this.timeout = setTimeout(() => {
|
|
20
|
+
this.visible = true;
|
|
21
|
+
}, this.delays.in);
|
|
22
|
+
}
|
|
23
|
+
close() {
|
|
24
|
+
if (this.timeout) {
|
|
25
|
+
clearTimeout(this.timeout);
|
|
26
|
+
this.timeout = null;
|
|
27
|
+
}
|
|
28
|
+
this.timeout = setTimeout(() => {
|
|
29
|
+
if (!this.hovered)
|
|
30
|
+
this.visible = false;
|
|
31
|
+
}, this.delays.out);
|
|
32
|
+
}
|
|
33
|
+
#effects = effects(() => {
|
|
34
|
+
this.hooks?.onChange?.(this.visible);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
@@ -13,7 +13,7 @@ let { children, class: klass, use = [], self = $bindable(), onClick, onKeydown,
|
|
|
13
13
|
const ctx = context();
|
|
14
14
|
onMount(() => {
|
|
15
15
|
if (self && self.children.length > 1) {
|
|
16
|
-
log.error("<MenuTrigger /> comoponent can only take 1
|
|
16
|
+
log.error("<MenuTrigger /> comoponent can only take 1 child node.");
|
|
17
17
|
return;
|
|
18
18
|
}
|
|
19
19
|
const target = self?.children[0];
|
|
@@ -7,7 +7,6 @@ export const context = () => getContext(contextName);
|
|
|
7
7
|
<script>import { createUID, useActions, KEYS, isBrowser, classProp } from "../../internal/index.js";
|
|
8
8
|
import { setContext } from "svelte";
|
|
9
9
|
let { children, use = [], class: klass, self = $bindable(), visible = $bindable(false), ...props } = $props();
|
|
10
|
-
const { uid } = createUID("popover");
|
|
11
10
|
const ctx = new PopoverContext(
|
|
12
11
|
{ visible },
|
|
13
12
|
{
|
|
@@ -35,7 +34,7 @@ $effect(() => {
|
|
|
35
34
|
<div
|
|
36
35
|
bind:this={self}
|
|
37
36
|
use:useActions={use}
|
|
38
|
-
id={uid()}
|
|
37
|
+
id={ctx.uid()}
|
|
39
38
|
class={classProp(klass, { visible: ctx.visible })}
|
|
40
39
|
data-popover=""
|
|
41
40
|
data-state={ctx.visible ? 'opened' : 'closed'}
|
|
@@ -5,21 +5,22 @@ import {
|
|
|
5
5
|
addEventListeners,
|
|
6
6
|
useActions,
|
|
7
7
|
KEYS,
|
|
8
|
-
classProp
|
|
8
|
+
classProp,
|
|
9
|
+
removeNodeProps
|
|
9
10
|
} from "../../internal/index.js";
|
|
10
11
|
import { onMount } from "svelte";
|
|
11
12
|
let { children, class: klass, use = [], self = $bindable(), onClick, onKeydown, ...props } = $props();
|
|
12
13
|
const ctx = context();
|
|
13
14
|
onMount(() => {
|
|
14
15
|
if (self && self.children.length > 1) {
|
|
15
|
-
log.error("<MenuTrigger /> comoponent can only take 1
|
|
16
|
+
log.error("<MenuTrigger /> comoponent can only take 1 child node.");
|
|
16
17
|
return;
|
|
17
18
|
}
|
|
18
19
|
const target = self?.children[0];
|
|
19
20
|
setNodeProps(target, {
|
|
20
21
|
id: ctx.uid("trigger"),
|
|
21
22
|
role: "button",
|
|
22
|
-
"aria-
|
|
23
|
+
"aria-haspopup": "dialog",
|
|
23
24
|
"aria-expanded": "false"
|
|
24
25
|
});
|
|
25
26
|
addEventListeners(target, {
|
|
@@ -40,6 +41,7 @@ $effect(() => {
|
|
|
40
41
|
}
|
|
41
42
|
if (!ctx.visible) {
|
|
42
43
|
setNodeProps(target, { "aria-expanded": "false" });
|
|
44
|
+
removeNodeProps(target, "aria-controls");
|
|
43
45
|
}
|
|
44
46
|
});
|
|
45
47
|
const handleKeydown = (e) => {
|
|
@@ -39,7 +39,7 @@ const handleKeydown = (e) => {
|
|
|
39
39
|
};
|
|
40
40
|
onMount(() => {
|
|
41
41
|
if (self && self.children.length > 1) {
|
|
42
|
-
log.error("<SelectTrigger /> comoponent can only take 1
|
|
42
|
+
log.error("<SelectTrigger /> comoponent can only take 1 child node.");
|
|
43
43
|
return;
|
|
44
44
|
}
|
|
45
45
|
const target = self?.children[0];
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -32,3 +32,10 @@ export declare const defaultConfig: <const T>(config: Partial<T> | undefined, de
|
|
|
32
32
|
* @param props Any state to be passed down to the function.
|
|
33
33
|
*/
|
|
34
34
|
export declare const classProp: <T extends Record<string, any>>(klass: ClassProp<T>, props?: T) => string | null | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* Contructs a object with in and out properties.
|
|
37
|
+
*/
|
|
38
|
+
export declare const parseDelay: (delay: number | [number, number]) => {
|
|
39
|
+
in: number;
|
|
40
|
+
out: number;
|
|
41
|
+
};
|
|
@@ -77,3 +77,12 @@ export const classProp = (klass, props) => {
|
|
|
77
77
|
const cls = $derived(typeof klass === 'function' ? klass(_props) : klass);
|
|
78
78
|
return cls;
|
|
79
79
|
};
|
|
80
|
+
/**
|
|
81
|
+
* Contructs a object with in and out properties.
|
|
82
|
+
*/
|
|
83
|
+
export const parseDelay = (delay) => {
|
|
84
|
+
return {
|
|
85
|
+
in: Array.isArray(delay) ? delay[0] : delay,
|
|
86
|
+
out: Array.isArray(delay) ? delay[1] : delay
|
|
87
|
+
};
|
|
88
|
+
};
|