@svelte-atoms/core 1.0.0-alpha.29 → 1.0.0-alpha.31
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 +3 -2
- package/dist/attachments/clickout.svelte.d.ts +1 -1
- package/dist/attachments/clickout.svelte.js +2 -2
- package/dist/components/accordion/accordion-root.svelte +65 -61
- package/dist/components/accordion/accordion-root.svelte.d.ts +1 -1
- package/dist/components/accordion/accordion.stories.svelte +70 -134
- package/dist/components/accordion/item/accordion-item-body.svelte +44 -42
- package/dist/components/accordion/item/accordion-item-header.svelte +51 -50
- package/dist/components/accordion/item/accordion-item-indicator.svelte +51 -50
- package/dist/components/accordion/item/accordion-item-root.svelte +66 -65
- package/dist/components/accordion/item/bond.svelte.d.ts +2 -0
- package/dist/components/accordion/item/index.d.ts +3 -0
- package/dist/components/accordion/item/index.js +3 -0
- package/dist/components/accordion/item/motion.svelte.d.ts +15 -0
- package/dist/components/accordion/item/motion.svelte.js +30 -0
- package/dist/components/accordion/item/types.d.ts +7 -24
- package/dist/components/alert/alert-close-button.svelte +66 -70
- package/dist/components/alert/alert-description.svelte +42 -42
- package/dist/components/alert/alert-description.svelte.d.ts +3 -6
- package/dist/components/alert/alert-root.svelte +68 -103
- package/dist/components/alert/alert-root.svelte.d.ts +2 -2
- package/dist/components/alert/alert.stories.svelte +10 -11
- package/dist/components/alert/bond.svelte.d.ts +0 -13
- package/dist/components/alert/bond.svelte.js +0 -32
- package/dist/components/alert/types.d.ts +8 -32
- package/dist/components/atom/html-atom.svelte +261 -207
- package/dist/components/avatar/avatar.stories.svelte +8 -13
- package/dist/components/badge/badge.stories.svelte +1 -6
- package/dist/components/badge/badge.svelte +1 -1
- package/dist/components/breadcrumb/breadcrumb.stories.svelte +16 -21
- package/dist/components/button/button.stories.svelte +1 -34
- package/dist/components/calendar/calendar-day.svelte +9 -4
- package/dist/components/calendar/calendar-header.svelte +29 -29
- package/dist/components/calendar/calendar-root.svelte +206 -206
- package/dist/components/calendar/calendar.stories.svelte +26 -31
- package/dist/components/card/card-body.svelte +1 -1
- package/dist/components/card/card-footer.svelte +1 -1
- package/dist/components/card/card-root.svelte +1 -1
- package/dist/components/card/card.stories.svelte +92 -104
- package/dist/components/checkbox/checkbox.stories.svelte +4 -9
- package/dist/components/checkbox/checkbox.svelte +159 -157
- package/dist/components/collapsible/collapsible.stories.svelte +2 -3
- package/dist/components/combobox/atoms.d.ts +1 -1
- package/dist/components/combobox/atoms.js +1 -1
- package/dist/components/combobox/combobox-root.svelte +1 -1
- package/dist/components/combobox/compobox.stories.svelte +19 -22
- package/dist/components/combobox/index.d.ts +1 -0
- package/dist/components/container/container.stories.svelte +8 -11
- package/dist/components/container/container.svelte.d.ts +1 -1
- package/dist/components/datagrid/datagrid-root.svelte +59 -59
- package/dist/components/datagrid/datagrid.css +5 -5
- package/dist/components/datagrid/datagrid.stories.svelte +47 -50
- package/dist/components/datagrid/tr/bond.svelte.d.ts +4 -2
- package/dist/components/datagrid/tr/bond.svelte.js +9 -7
- package/dist/components/datagrid/tr/datagrid-tr.svelte +90 -88
- package/dist/components/date-picker/date-picker-calendar.svelte +2 -2
- package/dist/components/date-picker/date-picker-header.svelte +100 -100
- package/dist/components/date-picker/date-picker-months.svelte +142 -142
- package/dist/components/date-picker/date-picker-root.svelte +95 -95
- package/dist/components/date-picker/date-picker-years.svelte +205 -205
- package/dist/components/date-picker/date-picker.stories.svelte +35 -42
- package/dist/components/dialog/bond.svelte.d.ts +13 -3
- package/dist/components/dialog/bond.svelte.js +66 -5
- package/dist/components/dialog/dialog-content.svelte +2 -20
- package/dist/components/dialog/dialog-root.svelte +91 -110
- package/dist/components/dialog/dialog.stories.svelte +34 -37
- package/dist/components/dialog/motion.svelte.d.ts +13 -0
- package/dist/components/dialog/motion.svelte.js +44 -0
- package/dist/components/drawer/attachments.svelte.d.ts +1 -1
- package/dist/components/drawer/attachments.svelte.js +7 -10
- package/dist/components/drawer/bond.svelte.d.ts +24 -5
- package/dist/components/drawer/bond.svelte.js +77 -11
- package/dist/components/drawer/drawer-content.svelte +49 -42
- package/dist/components/drawer/drawer.stories.svelte +144 -224
- package/dist/components/drawer/index.d.ts +2 -0
- package/dist/components/drawer/index.js +2 -0
- package/dist/components/drawer/motion.d.ts +15 -0
- package/dist/components/drawer/motion.js +28 -0
- package/dist/components/dropdown/atoms.d.ts +1 -1
- package/dist/components/dropdown/atoms.js +1 -1
- package/dist/components/dropdown/bond.svelte.d.ts +5 -1
- package/dist/components/dropdown/dropdown-root.svelte +1 -1
- package/dist/components/dropdown/dropdown.stories.svelte +38 -41
- package/dist/components/dropdown/index.d.ts +1 -0
- package/dist/components/form/form.stories.svelte +58 -61
- package/dist/components/image/image.stories.svelte +9 -12
- package/dist/components/input/input.stories.svelte +11 -14
- package/dist/components/label/label.stories.svelte +1 -12
- package/dist/components/label/label.stories.svelte.d.ts +24 -4
- package/dist/components/lazy/lazy.stories.svelte +28 -35
- package/dist/components/lazy/lazy.svelte +28 -28
- package/dist/components/link/link.stories.svelte +1 -12
- package/dist/components/link/link.stories.svelte.d.ts +24 -4
- package/dist/components/list/list-item.svelte +20 -20
- package/dist/components/menu/atoms.d.ts +1 -0
- package/dist/components/menu/atoms.js +1 -0
- package/dist/components/menu/index.d.ts +2 -1
- package/dist/components/menu/index.js +1 -1
- package/dist/components/menu/menu-item.svelte +69 -51
- package/dist/components/menu/menu-item.svelte.d.ts +1 -0
- package/dist/components/menu/menu-list.svelte +40 -40
- package/dist/components/menu/menu.stories.svelte +9 -12
- package/dist/components/popover/bond.svelte.d.ts +20 -7
- package/dist/components/popover/bond.svelte.js +104 -45
- package/dist/components/popover/motion.d.ts +6 -0
- package/dist/components/popover/motion.js +56 -0
- package/dist/components/popover/popover-arrow.svelte +4 -4
- package/dist/components/popover/popover-content.svelte +137 -178
- package/dist/components/popover/popover-indicator.svelte +2 -1
- package/dist/components/popover/popover-root.svelte +1 -1
- package/dist/components/popover/popover.stories.svelte +49 -52
- package/dist/components/popover/types.d.ts +9 -7
- package/dist/components/portal/active-portal.svelte +29 -22
- package/dist/components/portal/active-portal.svelte.d.ts +2 -9
- package/dist/components/portal/portal-root.svelte +76 -83
- package/dist/components/portal/portal-root.svelte.d.ts +4 -6
- package/dist/components/portal/teleport.svelte +49 -50
- package/dist/components/portal/teleport.svelte.d.ts +3 -4
- package/dist/components/qr-code/qr-code.stories.svelte +18 -27
- package/dist/components/qr-code/qr-code.svelte +75 -75
- package/dist/components/radio/radio-group.stories.svelte +21 -30
- package/dist/components/radio/radio.stories.svelte +1 -10
- package/dist/components/radio/radio.svelte +109 -109
- package/dist/components/radio/types.d.ts +98 -0
- package/dist/components/radio/types.js +2 -0
- package/dist/components/root/root.svelte +104 -121
- package/dist/components/scrollable/scrollable-root.svelte.d.ts +2 -2
- package/dist/components/scrollable/scrollable.stories.svelte +95 -105
- package/dist/components/sidebar/index.d.ts +2 -0
- package/dist/components/sidebar/index.js +2 -0
- package/dist/components/sidebar/motion.svelte.d.ts +11 -0
- package/dist/components/sidebar/motion.svelte.js +16 -0
- package/dist/components/sidebar/sidebar-content.svelte +3 -2
- package/dist/components/sidebar/sidebar-root.svelte +39 -41
- package/dist/components/sidebar/sidebar.stories.svelte +43 -54
- package/dist/components/sidebar/types.d.ts +3 -12
- package/dist/components/tabs/tab/bond.svelte.d.ts +4 -1
- package/dist/components/tabs/tab/bond.svelte.js +4 -1
- package/dist/components/tabs/tabs.stories.svelte +31 -34
- package/dist/components/textarea/atoms.d.ts +1 -0
- package/dist/components/textarea/atoms.js +1 -0
- package/dist/components/textarea/textarea-input.svelte +9 -6
- package/dist/components/textarea/textarea-root.svelte +9 -9
- package/dist/components/textarea/textarea-root.svelte.d.ts +2 -0
- package/dist/components/tooltip/tooltip-trigger.svelte +39 -37
- package/dist/components/tooltip/tooltip-trigger.svelte.d.ts +1 -0
- package/dist/components/tooltip/tooltip.stories.svelte +7 -10
- package/dist/components/tree/tree.stories.svelte +102 -94
- package/dist/context/preset.svelte.d.ts +3 -3
- package/dist/icons/icon-copy.svelte +6 -0
- package/dist/{components/radio/types.svelte.d.ts → icons/icon-copy.svelte.d.ts} +3 -3
- package/dist/utils/function.d.ts +2 -0
- package/dist/utils/function.js +6 -0
- package/dist/utils/markdown-to-llm.d.ts +28 -0
- package/dist/utils/markdown-to-llm.js +76 -0
- package/package.json +6 -10
- package/dist/actions/animation.svelte.d.ts +0 -6
- package/dist/actions/animation.svelte.js +0 -14
- package/dist/actions/clickout.svelte.d.ts +0 -2
- package/dist/actions/clickout.svelte.js +0 -15
- package/dist/actions/popover.svelte.d.ts +0 -19
- package/dist/actions/popover.svelte.js +0 -81
- package/dist/actions/portal.svelte.d.ts +0 -8
- package/dist/actions/portal.svelte.js +0 -32
- package/dist/attachments/gsap.svelte.d.ts +0 -2
- package/dist/attachments/gsap.svelte.js +0 -26
- package/dist/components/radio/types.svelte +0 -0
- package/llm/composition.md +0 -395
- package/llm/crafting.md +0 -838
- package/llm/motion.md +0 -970
- package/llm/philosophy.md +0 -23
- package/llm/preset-variant-integration.md +0 -516
- package/llm/preset.md +0 -383
- package/llm/styling.md +0 -216
- package/llm/usage.md +0 -46
- package/llm/variants.md +0 -1259
|
@@ -1,51 +1,69 @@
|
|
|
1
|
-
<script lang="ts" generics="T extends keyof HTMLElementTagNameMap = 'div', B extends Base = Base">
|
|
2
|
-
import { PopoverBond } from '../popover/bond.svelte';
|
|
3
|
-
import type { Base } from '../atom';
|
|
4
|
-
import { List } from '../list';
|
|
5
|
-
|
|
6
|
-
const bond = PopoverBond.get();
|
|
7
|
-
|
|
8
|
-
let {
|
|
9
|
-
class: klass = '',
|
|
10
|
-
preset: presetKey = 'menu.item',
|
|
11
|
-
children = undefined,
|
|
12
|
-
onclick = undefined,
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
'
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
{
|
|
49
|
-
|
|
50
|
-
{
|
|
51
|
-
|
|
1
|
+
<script lang="ts" generics="T extends keyof HTMLElementTagNameMap = 'div', B extends Base = Base">
|
|
2
|
+
import { PopoverBond } from '../popover/bond.svelte';
|
|
3
|
+
import type { Base } from '../atom';
|
|
4
|
+
import { List } from '../list';
|
|
5
|
+
|
|
6
|
+
const bond = PopoverBond.get();
|
|
7
|
+
|
|
8
|
+
let {
|
|
9
|
+
class: klass = '',
|
|
10
|
+
preset: presetKey = 'menu.item',
|
|
11
|
+
children = undefined,
|
|
12
|
+
onclick = undefined,
|
|
13
|
+
disabled = undefined,
|
|
14
|
+
onmount = undefined,
|
|
15
|
+
ondestroy = undefined,
|
|
16
|
+
animate = undefined,
|
|
17
|
+
enter = undefined,
|
|
18
|
+
exit = undefined,
|
|
19
|
+
initial = undefined,
|
|
20
|
+
...restProps
|
|
21
|
+
} = $props();
|
|
22
|
+
|
|
23
|
+
function _onclick(ev: MouseEvent) {
|
|
24
|
+
onclick?.(ev);
|
|
25
|
+
|
|
26
|
+
if (ev.defaultPrevented) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
bond?.state.close();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function _onkeydown(ev: KeyboardEvent) {
|
|
34
|
+
if (disabled) return;
|
|
35
|
+
|
|
36
|
+
// Activate on Enter or Space
|
|
37
|
+
if (ev.key === 'Enter' || ev.key === ' ') {
|
|
38
|
+
ev.preventDefault();
|
|
39
|
+
// Call the click handler if provided
|
|
40
|
+
// cast to any to avoid strict event-type mismatch when forwarding
|
|
41
|
+
onclick?.(ev as unknown as MouseEvent);
|
|
42
|
+
bond?.state.close();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
</script>
|
|
46
|
+
|
|
47
|
+
<List.Item
|
|
48
|
+
{bond}
|
|
49
|
+
preset={presetKey}
|
|
50
|
+
class={[
|
|
51
|
+
'border-border last:border-b-none hover:bg-foreground/5 active:bg-foreground/10 cursor-pointer border-b',
|
|
52
|
+
'$preset',
|
|
53
|
+
klass
|
|
54
|
+
]}
|
|
55
|
+
onmount={onmount?.bind(bond.state)}
|
|
56
|
+
ondestroy={ondestroy?.bind(bond.state)}
|
|
57
|
+
enter={enter?.bind(bond.state)}
|
|
58
|
+
exit={exit?.bind(bond.state)}
|
|
59
|
+
initial={initial?.bind(bond.state)}
|
|
60
|
+
animate={animate?.bind(bond.state)}
|
|
61
|
+
role="menuitem"
|
|
62
|
+
aria-disabled={disabled ? true : undefined}
|
|
63
|
+
tabIndex={disabled ? -1 : 0}
|
|
64
|
+
onkeydown={_onkeydown}
|
|
65
|
+
onclick={_onclick}
|
|
66
|
+
{...restProps}
|
|
67
|
+
>
|
|
68
|
+
{@render children?.({ menu: bond })}
|
|
69
|
+
</List.Item>
|
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
<script lang="ts" generics="T extends keyof HTMLElementTagNameMap = 'div', B extends Base = Base">
|
|
2
|
-
import { List } from '../list';
|
|
3
|
-
import { Content } from '../popover/atoms';
|
|
4
|
-
import type { Base } from '../atom';
|
|
5
|
-
import { PopoverBond } from '../popover';
|
|
6
|
-
|
|
7
|
-
const bond = PopoverBond.get();
|
|
8
|
-
|
|
9
|
-
let {
|
|
10
|
-
class: klass = '',
|
|
11
|
-
as = 'ul' as T,
|
|
12
|
-
base = List.Root as B,
|
|
13
|
-
preset = 'menu.list',
|
|
14
|
-
children = undefined,
|
|
15
|
-
onmount = undefined,
|
|
16
|
-
ondestroy = undefined,
|
|
17
|
-
animate = undefined,
|
|
18
|
-
enter = undefined,
|
|
19
|
-
exit = undefined,
|
|
20
|
-
initial = undefined,
|
|
21
|
-
...restProps
|
|
22
|
-
} = $props();
|
|
23
|
-
</script>
|
|
24
|
-
|
|
25
|
-
<Content
|
|
26
|
-
{as}
|
|
27
|
-
{base}
|
|
28
|
-
{bond}
|
|
29
|
-
{preset}
|
|
30
|
-
class={['bg-background border-border overflow-hidden p-0', '$preset', klass]}
|
|
31
|
-
onmount={onmount?.bind(bond.state)}
|
|
32
|
-
ondestroy={ondestroy?.bind(bond.state)}
|
|
33
|
-
enter={enter?.bind(bond.state)}
|
|
34
|
-
exit={exit?.bind(bond.state)}
|
|
35
|
-
initial={initial?.bind(bond.state)}
|
|
36
|
-
animate={animate?.bind(bond.state)}
|
|
37
|
-
{...restProps}
|
|
38
|
-
>
|
|
39
|
-
{@render children?.()}
|
|
40
|
-
</Content>
|
|
1
|
+
<script lang="ts" generics="T extends keyof HTMLElementTagNameMap = 'div', B extends Base = Base">
|
|
2
|
+
import { List } from '../list';
|
|
3
|
+
import { Content } from '../popover/atoms';
|
|
4
|
+
import type { Base } from '../atom';
|
|
5
|
+
import { PopoverBond } from '../popover';
|
|
6
|
+
|
|
7
|
+
const bond = PopoverBond.get();
|
|
8
|
+
|
|
9
|
+
let {
|
|
10
|
+
class: klass = '',
|
|
11
|
+
as = 'ul' as T,
|
|
12
|
+
base = List.Root as B,
|
|
13
|
+
preset = 'menu.list',
|
|
14
|
+
children = undefined,
|
|
15
|
+
onmount = undefined,
|
|
16
|
+
ondestroy = undefined,
|
|
17
|
+
animate = undefined,
|
|
18
|
+
enter = undefined,
|
|
19
|
+
exit = undefined,
|
|
20
|
+
initial = undefined,
|
|
21
|
+
...restProps
|
|
22
|
+
} = $props();
|
|
23
|
+
</script>
|
|
24
|
+
|
|
25
|
+
<Content
|
|
26
|
+
{as}
|
|
27
|
+
{base}
|
|
28
|
+
{bond}
|
|
29
|
+
{preset}
|
|
30
|
+
class={['bg-background border-border overflow-hidden p-0', '$preset', klass]}
|
|
31
|
+
onmount={onmount?.bind(bond.state)}
|
|
32
|
+
ondestroy={ondestroy?.bind(bond.state)}
|
|
33
|
+
enter={enter?.bind(bond.state)}
|
|
34
|
+
exit={exit?.bind(bond.state)}
|
|
35
|
+
initial={initial?.bind(bond.state)}
|
|
36
|
+
animate={animate?.bind(bond.state)}
|
|
37
|
+
{...restProps}
|
|
38
|
+
>
|
|
39
|
+
{@render children?.()}
|
|
40
|
+
</Content>
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
<script module>
|
|
2
2
|
import { defineMeta } from '@storybook/addon-svelte-csf';
|
|
3
3
|
import { Menu as AMenu } from '.';
|
|
4
|
-
import Root from '../root/root.svelte';
|
|
5
4
|
import { Button } from '../button';
|
|
6
5
|
|
|
7
6
|
// More on how to set up stories at: https://storybook.js.org/docs/writing-stories
|
|
@@ -22,15 +21,13 @@
|
|
|
22
21
|
</script>
|
|
23
22
|
|
|
24
23
|
<Story name="Menu" args={{}}>
|
|
25
|
-
<Root
|
|
26
|
-
<AMenu.
|
|
27
|
-
|
|
28
|
-
<AMenu.
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
</AMenu.Root>
|
|
35
|
-
</Root>
|
|
24
|
+
<AMenu.Root bind:open offset={4}>
|
|
25
|
+
<AMenu.Trigger base={Button}>Select a language</AMenu.Trigger>
|
|
26
|
+
<AMenu.List>
|
|
27
|
+
<AMenu.Item>Arabic</AMenu.Item>
|
|
28
|
+
<AMenu.Item>English</AMenu.Item>
|
|
29
|
+
<AMenu.Item>Spanish</AMenu.Item>
|
|
30
|
+
<AMenu.Item>Italian</AMenu.Item>
|
|
31
|
+
</AMenu.List>
|
|
32
|
+
</AMenu.Root>
|
|
36
33
|
</Story>
|
|
@@ -31,11 +31,15 @@ export type PopoverDomElements = {
|
|
|
31
31
|
arrow: HTMLElement;
|
|
32
32
|
};
|
|
33
33
|
export declare class PopoverBond<Props extends PopoverStateProps = PopoverStateProps, State extends PopoverState<Props> = PopoverState<Props>, Elements extends PopoverDomElements = PopoverDomElements> extends Bond<Props, State, Elements> {
|
|
34
|
-
#private;
|
|
35
34
|
static CONTEXT_KEY: string;
|
|
35
|
+
position: ComputePositionReturn | undefined;
|
|
36
36
|
constructor(state: State);
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
trigger(props?: Record<string, unknown> & {
|
|
38
|
+
onclick?: (ev: PointerEvent) => void;
|
|
39
|
+
onkeydown?: (ev: KeyboardEvent) => void;
|
|
40
|
+
}): {
|
|
41
|
+
onclick: (ev: PointerEvent) => void;
|
|
42
|
+
onkeydown: (ev: KeyboardEvent) => void;
|
|
39
43
|
id: string;
|
|
40
44
|
role: string;
|
|
41
45
|
disabled: boolean | undefined;
|
|
@@ -43,26 +47,35 @@ export declare class PopoverBond<Props extends PopoverStateProps = PopoverStateP
|
|
|
43
47
|
'aria-expanded': boolean;
|
|
44
48
|
'aria-disabled': boolean;
|
|
45
49
|
'aria-controls': string;
|
|
50
|
+
'aria-haspopup': string;
|
|
46
51
|
'data-kind': string;
|
|
47
|
-
onclick: (ev: PointerEvent) => void;
|
|
48
52
|
};
|
|
49
|
-
content(props?: Record<string, unknown>
|
|
53
|
+
content(props?: Record<string, unknown> & {
|
|
54
|
+
onchange?: (node: HTMLElement, position: ComputePositionReturn) => void;
|
|
55
|
+
}): {
|
|
56
|
+
onchange?: (node: HTMLElement, position: ComputePositionReturn) => void;
|
|
50
57
|
id: string;
|
|
51
58
|
role: string;
|
|
52
59
|
'aria-modal': boolean;
|
|
53
60
|
'aria-labelledby': string;
|
|
54
|
-
'aria-
|
|
61
|
+
'aria-hidden': boolean;
|
|
62
|
+
inert: string | undefined;
|
|
63
|
+
tabindex: number;
|
|
55
64
|
'data-atom': string;
|
|
56
65
|
'data-kind': string;
|
|
57
66
|
'data-active': boolean;
|
|
67
|
+
onkeydown: ((ev: KeyboardEvent) => void) | undefined;
|
|
58
68
|
};
|
|
59
69
|
indicator(props?: Record<string, unknown>): {
|
|
60
70
|
id: string;
|
|
61
|
-
'aria-
|
|
71
|
+
'aria-hidden': boolean;
|
|
72
|
+
'aria-live': string;
|
|
62
73
|
'data-kind': string;
|
|
63
74
|
};
|
|
64
75
|
arrow(props?: Record<string, unknown>): {
|
|
65
76
|
id: string;
|
|
77
|
+
role: string;
|
|
78
|
+
'aria-hidden': boolean;
|
|
66
79
|
'data-kind': string;
|
|
67
80
|
};
|
|
68
81
|
share(): this;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { getContext, setContext, untrack } from 'svelte';
|
|
2
2
|
import { createAttachmentKey } from 'svelte/attachments';
|
|
3
3
|
import { autoUpdate, computePosition, arrow, flip, offset } from '@floating-ui/dom';
|
|
4
|
-
import { debounce } from 'es-toolkit';
|
|
5
4
|
import { getElementId, isBrowser } from '../../utils/dom.svelte.js';
|
|
6
5
|
import { Bond, BondState } from '../../shared/bond.svelte.js';
|
|
7
6
|
const POPOVER_ELEMENTS_KIND = {
|
|
@@ -12,13 +11,10 @@ const POPOVER_ELEMENTS_KIND = {
|
|
|
12
11
|
};
|
|
13
12
|
export class PopoverBond extends Bond {
|
|
14
13
|
static CONTEXT_KEY = '@atomic-sv/bonds/popover';
|
|
15
|
-
|
|
14
|
+
position = $state();
|
|
16
15
|
constructor(state) {
|
|
17
16
|
super(state);
|
|
18
17
|
}
|
|
19
|
-
get position() {
|
|
20
|
-
return this.#position;
|
|
21
|
-
}
|
|
22
18
|
trigger(props = {}) {
|
|
23
19
|
const isButtonElement = isBrowser()
|
|
24
20
|
? this.elements.trigger instanceof HTMLButtonElement
|
|
@@ -30,12 +26,13 @@ export class PopoverBond extends Bond {
|
|
|
30
26
|
const overlayId = getElementId(this.id, POPOVER_ELEMENTS_KIND.content);
|
|
31
27
|
return {
|
|
32
28
|
id,
|
|
33
|
-
role: isButtonElement ? '' : 'button',
|
|
29
|
+
role: isButtonElement ? '' : 'button',
|
|
34
30
|
disabled: isButtonElement ? isDisabled : undefined,
|
|
35
|
-
tabindex: isDisabled ? -1 : 0,
|
|
31
|
+
tabindex: isDisabled ? -1 : 0,
|
|
36
32
|
'aria-expanded': isOpen,
|
|
37
33
|
'aria-disabled': isDisabled,
|
|
38
34
|
'aria-controls': overlayId,
|
|
35
|
+
'aria-haspopup': 'dialog',
|
|
39
36
|
'data-kind': kind,
|
|
40
37
|
onclick: (ev) => {
|
|
41
38
|
if (ev.button === 2) {
|
|
@@ -45,17 +42,34 @@ export class PopoverBond extends Bond {
|
|
|
45
42
|
return;
|
|
46
43
|
}
|
|
47
44
|
this.state.toggle();
|
|
45
|
+
props.onclick?.(ev);
|
|
46
|
+
},
|
|
47
|
+
onkeydown: (ev) => {
|
|
48
|
+
if (isDisabled)
|
|
49
|
+
return;
|
|
50
|
+
// Toggle on Enter or Space
|
|
51
|
+
if (ev.key === 'Enter' || ev.key === ' ') {
|
|
52
|
+
ev.preventDefault();
|
|
53
|
+
this.state.toggle();
|
|
54
|
+
props.onkeydown?.(ev);
|
|
55
|
+
}
|
|
56
|
+
// Close on Escape
|
|
57
|
+
else if (ev.key === 'Escape' && isOpen) {
|
|
58
|
+
ev.preventDefault();
|
|
59
|
+
this.state.close();
|
|
60
|
+
props.onkeydown?.(ev);
|
|
61
|
+
}
|
|
48
62
|
},
|
|
49
63
|
...props,
|
|
50
64
|
[createAttachmentKey()]: (node) => {
|
|
51
65
|
this.elements.trigger = node;
|
|
52
|
-
const position = untrack(() => this
|
|
66
|
+
const position = untrack(() => this.position);
|
|
53
67
|
if (!position) {
|
|
54
68
|
const init = async () => {
|
|
55
|
-
popover(this)(
|
|
69
|
+
popover(this)({
|
|
56
70
|
...props,
|
|
57
|
-
onchange: (
|
|
58
|
-
this
|
|
71
|
+
onchange: (_node, position) => {
|
|
72
|
+
this.position = position;
|
|
59
73
|
}
|
|
60
74
|
});
|
|
61
75
|
const pointerLeaveHandler = () => {
|
|
@@ -79,40 +93,76 @@ export class PopoverBond extends Bond {
|
|
|
79
93
|
const isOpen = this.state?.props?.open ?? false;
|
|
80
94
|
const isDisabled = this.state?.props?.disabled ?? false;
|
|
81
95
|
const isActive = isOpen && !isDisabled;
|
|
96
|
+
// Focus management
|
|
97
|
+
const focusTrap = (ev) => {
|
|
98
|
+
const node = ev.currentTarget;
|
|
99
|
+
if (ev.key === 'Escape') {
|
|
100
|
+
ev.preventDefault();
|
|
101
|
+
this.state.close();
|
|
102
|
+
this.elements.trigger?.focus();
|
|
103
|
+
}
|
|
104
|
+
// Tab trap - keep focus within popover
|
|
105
|
+
else if (ev.key === 'Tab') {
|
|
106
|
+
const focusableElements = node.querySelectorAll('a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])');
|
|
107
|
+
const firstElement = focusableElements[0];
|
|
108
|
+
const lastElement = focusableElements[focusableElements.length - 1];
|
|
109
|
+
if (ev.shiftKey && document.activeElement === firstElement) {
|
|
110
|
+
ev.preventDefault();
|
|
111
|
+
lastElement?.focus();
|
|
112
|
+
}
|
|
113
|
+
else if (!ev.shiftKey && document.activeElement === lastElement) {
|
|
114
|
+
ev.preventDefault();
|
|
115
|
+
firstElement?.focus();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
};
|
|
82
119
|
return {
|
|
83
120
|
id,
|
|
84
|
-
role: 'dialog',
|
|
85
|
-
'aria-modal':
|
|
86
|
-
'aria-labelledby': triggerId,
|
|
87
|
-
'aria-
|
|
121
|
+
role: 'dialog',
|
|
122
|
+
'aria-modal': false,
|
|
123
|
+
'aria-labelledby': triggerId,
|
|
124
|
+
'aria-hidden': !isActive,
|
|
125
|
+
inert: !isActive ? '' : undefined,
|
|
126
|
+
tabindex: -1,
|
|
88
127
|
'data-atom': this.id,
|
|
89
|
-
'data-kind': '
|
|
128
|
+
'data-kind': 'content',
|
|
90
129
|
'data-active': isActive,
|
|
130
|
+
onkeydown: isOpen ? focusTrap : undefined,
|
|
91
131
|
...props,
|
|
92
132
|
[createAttachmentKey()]: (node) => {
|
|
93
133
|
this.elements.content = node;
|
|
94
134
|
if (!this.elements.trigger) {
|
|
95
135
|
return;
|
|
96
136
|
}
|
|
97
|
-
if (!this.state.isOpen)
|
|
137
|
+
if (!this.state.isOpen) {
|
|
98
138
|
return;
|
|
99
|
-
|
|
139
|
+
}
|
|
140
|
+
// Move focus to popover when opened
|
|
141
|
+
setTimeout(() => {
|
|
142
|
+
const firstFocusable = node.querySelector('a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])');
|
|
143
|
+
(firstFocusable || node).focus();
|
|
144
|
+
}, 0);
|
|
145
|
+
const cleanup = popover(this)({
|
|
100
146
|
...props,
|
|
101
147
|
onchange: (node, position) => {
|
|
102
|
-
this
|
|
148
|
+
this.position = position;
|
|
103
149
|
props.onchange?.(node, position);
|
|
104
150
|
}
|
|
105
151
|
}, autoUpdate);
|
|
152
|
+
return () => {
|
|
153
|
+
cleanup?.();
|
|
154
|
+
};
|
|
106
155
|
}
|
|
107
156
|
};
|
|
108
157
|
}
|
|
109
158
|
indicator(props = {}) {
|
|
110
159
|
const kind = POPOVER_ELEMENTS_KIND.indicator;
|
|
111
160
|
const id = getElementId(this.id, kind);
|
|
112
|
-
const
|
|
161
|
+
const isOpen = this.state?.props?.open ?? false;
|
|
113
162
|
return {
|
|
114
163
|
id,
|
|
115
|
-
'aria-
|
|
164
|
+
'aria-hidden': true,
|
|
165
|
+
'aria-live': isOpen ? 'polite' : 'off',
|
|
116
166
|
'data-kind': kind,
|
|
117
167
|
...props,
|
|
118
168
|
[createAttachmentKey()]: (node) => {
|
|
@@ -125,6 +175,8 @@ export class PopoverBond extends Bond {
|
|
|
125
175
|
const id = getElementId(this.id, kind);
|
|
126
176
|
return {
|
|
127
177
|
id: id,
|
|
178
|
+
role: 'presentation',
|
|
179
|
+
'aria-hidden': true,
|
|
128
180
|
'data-kind': kind,
|
|
129
181
|
...props,
|
|
130
182
|
[createAttachmentKey()]: (node) => {
|
|
@@ -160,38 +212,45 @@ export class PopoverState extends BondState {
|
|
|
160
212
|
}
|
|
161
213
|
}
|
|
162
214
|
function popover(bond) {
|
|
163
|
-
return (
|
|
215
|
+
return (props, updater) => {
|
|
164
216
|
const { offset: ofs, placements, placement } = bond.state.props;
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
}
|
|
168
|
-
if (!bond.elements.trigger) {
|
|
217
|
+
// Guard: ensure required elements exist
|
|
218
|
+
if (!bond.elements.content || !bond.elements.trigger) {
|
|
169
219
|
return;
|
|
170
220
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
221
|
+
const { content, trigger, arrow: arrowElement } = bond.elements;
|
|
222
|
+
// Build middleware stack
|
|
223
|
+
const middleware = [
|
|
224
|
+
offset(ofs),
|
|
225
|
+
flip({
|
|
226
|
+
fallbackPlacements: placements,
|
|
227
|
+
padding: 4
|
|
228
|
+
})
|
|
229
|
+
];
|
|
230
|
+
// Add arrow middleware if element exists
|
|
231
|
+
if (arrowElement) {
|
|
232
|
+
middleware.push(arrow({ element: arrowElement }));
|
|
175
233
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
234
|
+
// Debounce position change callback
|
|
235
|
+
const onchangeCallback = props.onchange;
|
|
236
|
+
// Compute position and notify listeners
|
|
179
237
|
const compute = async () => {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
238
|
+
// Wait for next frame to ensure DOM has settled and styles are applied
|
|
239
|
+
// Double requestAnimationFrame - This ensures the browser has completed both layout calculation AND painting, giving us accurate final dimensions
|
|
240
|
+
await new Promise((resolve) => requestAnimationFrame(() => requestAnimationFrame(resolve)));
|
|
241
|
+
const position = await computePosition(trigger, content, {
|
|
242
|
+
placement: placement ?? 'bottom',
|
|
243
|
+
middleware
|
|
244
|
+
});
|
|
245
|
+
onchangeCallback?.(content, position);
|
|
246
|
+
// Set minimum width to match trigger
|
|
247
|
+
requestAnimationFrame(() => {
|
|
248
|
+
content.style.minWidth = `${trigger.clientWidth}px`;
|
|
190
249
|
});
|
|
191
|
-
onchangeDebounced?.(node, position);
|
|
192
250
|
};
|
|
251
|
+
// Use auto-update if provided, otherwise compute once
|
|
193
252
|
if (updater) {
|
|
194
|
-
return updater(
|
|
253
|
+
return updater(trigger, content, compute, {});
|
|
195
254
|
}
|
|
196
255
|
compute();
|
|
197
256
|
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { animate } from 'motion';
|
|
2
|
+
import { PopoverBond } from '.';
|
|
3
|
+
import { DURATION } from '../../shared';
|
|
4
|
+
export function animatePopoverContent(params = {}) {
|
|
5
|
+
return (node) => {
|
|
6
|
+
const bond = PopoverBond.get();
|
|
7
|
+
const { duration = DURATION.quick / 1000, delay = 0, ease = 'easeInOut' } = params;
|
|
8
|
+
const isOpen = bond?.state.props.open ?? false;
|
|
9
|
+
const position = bond.position;
|
|
10
|
+
const placement = position?.placement;
|
|
11
|
+
const x = position?.x ?? 0;
|
|
12
|
+
const y = position?.y ?? 0;
|
|
13
|
+
const dy = placement?.startsWith('top') ? -1 : placement?.startsWith('bottom') ? 1 : 0;
|
|
14
|
+
const dx = placement?.startsWith('left') ? -1 : placement?.startsWith('right') ? 1 : 0;
|
|
15
|
+
const offset = bond.state.props.offset;
|
|
16
|
+
const xOffset = dx * offset;
|
|
17
|
+
const yOffset = dy * offset;
|
|
18
|
+
const openAsNumber = +isOpen;
|
|
19
|
+
const deltaArrow = position?.middlewareData?.arrow ? 1 : 0;
|
|
20
|
+
const arrowClientWidth = bond?.elements.arrow?.clientWidth ?? 0;
|
|
21
|
+
const arrowClientHeight = bond?.elements.arrow?.clientHeight ?? 0;
|
|
22
|
+
const getTransformOrigin = () => {
|
|
23
|
+
switch (placement) {
|
|
24
|
+
case 'top':
|
|
25
|
+
case 'top-start':
|
|
26
|
+
case 'top-end':
|
|
27
|
+
return 'bottom';
|
|
28
|
+
case 'bottom':
|
|
29
|
+
case 'bottom-start':
|
|
30
|
+
case 'bottom-end':
|
|
31
|
+
return 'top';
|
|
32
|
+
case 'left':
|
|
33
|
+
case 'left-start':
|
|
34
|
+
case 'left-end':
|
|
35
|
+
return 'right';
|
|
36
|
+
case 'right':
|
|
37
|
+
case 'right-start':
|
|
38
|
+
case 'right-end':
|
|
39
|
+
return 'left';
|
|
40
|
+
default:
|
|
41
|
+
return 'center';
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
const transformOrigin = getTransformOrigin();
|
|
45
|
+
const from = isOpen ? 1 : 0.95;
|
|
46
|
+
animate(node, {
|
|
47
|
+
opacity: openAsNumber,
|
|
48
|
+
y: dy * (!isOpen ? -1 : 0) * (arrowClientHeight + yOffset),
|
|
49
|
+
x: dx * (!isOpen ? -1 : 0) * (arrowClientWidth + xOffset),
|
|
50
|
+
scaleY: dy ? (isOpen ? [from, 1] : [1, 0.8]) : undefined,
|
|
51
|
+
scaleX: dx ? (isOpen ? [from, 1] : [1, 0.8]) : undefined,
|
|
52
|
+
transformOrigin
|
|
53
|
+
}, { duration, delay, ease });
|
|
54
|
+
animate(node, { opacity: +isOpen }, { duration, ease, delay });
|
|
55
|
+
};
|
|
56
|
+
}
|
|
@@ -98,14 +98,14 @@
|
|
|
98
98
|
{@render children({ popover: bond })}
|
|
99
99
|
{:else}
|
|
100
100
|
<svg
|
|
101
|
-
width="
|
|
102
|
-
height="
|
|
103
|
-
viewBox="0 0
|
|
101
|
+
width="16"
|
|
102
|
+
height="8"
|
|
103
|
+
viewBox="0 0 16 8"
|
|
104
104
|
fill="none"
|
|
105
105
|
xmlns="http://www.w3.org/2000/svg"
|
|
106
106
|
style="transform: rotate({rotation}deg);"
|
|
107
107
|
>
|
|
108
|
-
<path d="M0
|
|
108
|
+
<path d="M0 8C2 8 6 4 8 0C10 4 14 8 16 8H0Z" fill="currentColor" />
|
|
109
109
|
</svg>
|
|
110
110
|
{/if}
|
|
111
111
|
</HtmlAtom>
|