@svelte-atoms/core 1.0.0-alpha.31 → 1.0.0-alpha.33
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/LICENSE +21 -0
- package/README.md +289 -853
- package/dist/attachments/index.d.ts +1 -0
- package/dist/attachments/index.js +1 -0
- package/dist/components/accordion/accordion-root.svelte +65 -65
- package/dist/components/accordion/accordion.stories.svelte +70 -70
- package/dist/components/accordion/item/accordion-item-body.svelte +44 -44
- package/dist/components/accordion/item/accordion-item-header.svelte +51 -51
- package/dist/components/accordion/item/accordion-item-indicator.svelte +51 -51
- package/dist/components/accordion/item/accordion-item-root.svelte +66 -66
- package/dist/components/alert/alert-close-button.svelte +66 -66
- package/dist/components/alert/alert-description.svelte +42 -42
- package/dist/components/alert/alert-root.svelte +68 -68
- package/dist/components/atom/html-atom.svelte +26 -194
- package/dist/components/atom/types.d.ts +3 -2
- package/dist/components/atom/utils.d.ts +37 -0
- package/dist/components/atom/utils.js +208 -0
- package/dist/components/breadcrumb/breadcrumb-item.svelte +1 -1
- package/dist/components/breadcrumb/breadcrumb-separator.svelte +5 -1
- package/dist/components/breadcrumb/breadcrumb.stories.svelte +16 -16
- package/dist/components/calendar/calendar-day.svelte +101 -101
- package/dist/components/checkbox/checkbox.svelte +159 -159
- package/dist/components/collapsible/bond.svelte.js +2 -1
- package/dist/components/collapsible/collapsible-body.svelte +3 -2
- package/dist/components/collapsible/motion.svelte.d.ts +6 -0
- package/dist/components/collapsible/motion.svelte.js +15 -0
- package/dist/components/combobox/atoms.d.ts +3 -3
- package/dist/components/combobox/atoms.js +3 -3
- package/dist/components/combobox/bond.svelte.d.ts +6 -6
- package/dist/components/combobox/bond.svelte.js +3 -26
- package/dist/components/combobox/combobox-control.svelte +52 -52
- package/dist/components/combobox/{compobox-item.svelte → combobox-item.svelte} +62 -68
- package/dist/components/combobox/combobox-item.svelte.d.ts +12 -0
- package/dist/components/combobox/combobox.stories.svelte +50 -0
- package/dist/components/combobox/combobox.stories.svelte.d.ts +3 -0
- package/dist/components/datagrid/tr/datagrid-tr.svelte +90 -90
- package/dist/components/date-picker/bond.svelte.d.ts +15 -5
- package/dist/components/date-picker/bond.svelte.js +6 -11
- package/dist/components/date-picker/date-picker-calendar.svelte +1 -8
- package/dist/components/dialog/bond.svelte.js +5 -20
- package/dist/components/dialog/dialog-content.svelte +44 -44
- package/dist/components/dialog/dialog-root.svelte +91 -91
- package/dist/components/drawer/bond.svelte.d.ts +18 -16
- package/dist/components/drawer/bond.svelte.js +8 -18
- package/dist/components/drawer/drawer-content.svelte +49 -49
- package/dist/components/drawer/drawer-root.svelte +5 -4
- package/dist/components/drawer/drawer.stories.svelte +141 -144
- package/dist/components/drawer/motion.js +1 -1
- 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 +21 -22
- package/dist/components/dropdown/bond.svelte.js +29 -53
- package/dist/components/dropdown/dropdown-root.svelte +65 -59
- package/dist/components/dropdown/dropdown-values.svelte +17 -17
- package/dist/components/dropdown/dropdown-values.svelte.d.ts +1 -2
- package/dist/components/dropdown/dropdown.stories.svelte +83 -80
- package/dist/components/dropdown/index.d.ts +1 -0
- package/dist/components/dropdown/index.js +1 -0
- package/dist/components/dropdown/item/attachments.svelte.d.ts +2 -2
- package/dist/components/dropdown/item/attachments.svelte.js +2 -2
- package/dist/components/dropdown/item/controller.svelte.d.ts +34 -0
- package/dist/components/dropdown/item/controller.svelte.js +82 -0
- package/dist/components/dropdown/item/dropdown-item.svelte +109 -102
- package/dist/components/dropdown/item/dropdown-item.svelte.d.ts +13 -28
- package/dist/components/dropdown/item/index.d.ts +3 -0
- package/dist/components/dropdown/item/index.js +3 -0
- package/dist/components/dropdown/item/types.d.ts +29 -0
- package/dist/components/dropdown/item/types.js +1 -0
- package/dist/components/list/list-item.svelte +20 -20
- package/dist/components/menu/atoms.d.ts +8 -3
- package/dist/components/menu/atoms.js +8 -3
- package/dist/components/menu/bond.svelte.d.ts +54 -0
- package/dist/components/menu/bond.svelte.js +132 -0
- package/dist/components/menu/index.d.ts +1 -0
- package/dist/components/menu/index.js +1 -0
- package/dist/components/menu/item/controller.svelte.d.ts +26 -0
- package/dist/components/menu/item/controller.svelte.js +69 -0
- package/dist/components/menu/item/index.d.ts +2 -0
- package/dist/components/menu/item/index.js +2 -0
- package/dist/components/menu/item/menu-item.svelte +103 -0
- package/dist/components/menu/item/menu-item.svelte.d.ts +31 -0
- package/dist/components/menu/item/types.d.ts +62 -0
- package/dist/components/menu/item/types.js +1 -0
- package/dist/components/menu/{menu-list.svelte → menu-content.svelte} +40 -40
- package/dist/components/menu/{menu-list.svelte.d.ts → menu-content.svelte.d.ts} +3 -3
- package/dist/components/menu/menu-root.svelte +15 -0
- package/dist/components/menu/menu-root.svelte.d.ts +8 -0
- package/dist/components/menu/menu.stories.svelte +33 -33
- package/dist/components/menu/types.d.ts +0 -7
- package/dist/components/popover/bond.svelte.d.ts +11 -14
- package/dist/components/popover/bond.svelte.js +27 -44
- package/dist/components/popover/popover-content.svelte +137 -137
- package/dist/components/popover/popover.stories.svelte +37 -49
- package/dist/components/portal/active-portal.svelte +29 -29
- package/dist/components/portal/portal-root.svelte +76 -76
- package/dist/components/portal/teleport.svelte +49 -49
- package/dist/components/radio/radio.svelte +109 -109
- package/dist/components/root/index.d.ts +1 -0
- package/dist/components/root/index.js +1 -0
- package/dist/components/root/l0-portal.svelte +8 -0
- package/dist/components/root/l0-portal.svelte.d.ts +26 -0
- package/dist/components/root/l1-portal.svelte +7 -0
- package/dist/components/root/l1-portal.svelte.d.ts +26 -0
- package/dist/components/root/root.css +119 -119
- package/dist/components/root/root.svelte +17 -18
- package/dist/components/root/root.svelte.d.ts +2 -6
- package/dist/components/root/toasts-portal.svelte +7 -0
- package/dist/components/root/toasts-portal.svelte.d.ts +26 -0
- package/dist/components/root/types.d.ts +17 -0
- package/dist/components/sidebar/motion.svelte.js +3 -3
- package/dist/components/sidebar/sidebar-content.svelte +40 -40
- package/dist/components/textarea/textarea-input.svelte +9 -9
- package/dist/components/textarea/textarea-root.svelte +9 -9
- package/dist/components/tooltip/tooltip-trigger.svelte +39 -39
- package/dist/components/tree/index.d.ts +1 -0
- package/dist/components/tree/index.js +1 -0
- package/dist/components/tree/motion.svelte.d.ts +6 -0
- package/dist/components/tree/motion.svelte.js +14 -0
- package/dist/components/tree/tree-body.svelte +4 -3
- package/dist/context/preset.svelte.d.ts +3 -1
- package/dist/icons/icon-copy.svelte +6 -6
- package/dist/utils/dom.svelte.d.ts +2 -0
- package/dist/utils/dom.svelte.js +21 -0
- package/dist/utils/function.d.ts +1 -1
- package/dist/utils/promise.svelte.d.ts +5 -0
- package/dist/utils/promise.svelte.js +20 -0
- package/package.json +4 -2
- package/dist/components/combobox/compobox-item.svelte.d.ts +0 -34
- package/dist/components/combobox/compobox.stories.svelte +0 -51
- package/dist/components/combobox/compobox.stories.svelte.d.ts +0 -3
- package/dist/components/dropdown/item/bond.svelte.d.ts +0 -42
- package/dist/components/dropdown/item/bond.svelte.js +0 -99
- package/dist/components/menu/menu-item.svelte +0 -69
- package/dist/components/menu/menu-item.svelte.d.ts +0 -37
- package/dist/utils/markdown-to-llm.d.ts +0 -28
- package/dist/utils/markdown-to-llm.js +0 -76
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { MenuItemProps } from '../../menu/item/types';
|
|
3
|
+
import type { DropdownItemController } from './controller.svelte';
|
|
4
|
+
export interface DropdownItemProps<T = unknown> extends Omit<MenuItemProps, 'factory' | 'children' | 'preset'> {
|
|
5
|
+
/**
|
|
6
|
+
* Preset key for styling
|
|
7
|
+
* @default 'dropdown.item'
|
|
8
|
+
*/
|
|
9
|
+
preset?: string;
|
|
10
|
+
/**
|
|
11
|
+
* The value of the dropdown item
|
|
12
|
+
* @default nanoid()
|
|
13
|
+
*/
|
|
14
|
+
value?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Custom data associated with the item
|
|
17
|
+
*/
|
|
18
|
+
data?: T;
|
|
19
|
+
/**
|
|
20
|
+
* Factory function to create a custom DropdownItemController instance
|
|
21
|
+
*/
|
|
22
|
+
factory?: () => DropdownItemController<T>;
|
|
23
|
+
/**
|
|
24
|
+
* Render prop for children
|
|
25
|
+
*/
|
|
26
|
+
children?: Snippet<[{
|
|
27
|
+
dropdownItem: DropdownItemController<T>;
|
|
28
|
+
}]>;
|
|
29
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
<script lang="ts" generics="T extends keyof HTMLElementTagNameMap = 'li', B extends Base = Base">
|
|
2
|
-
import { HtmlAtom, type Base } from '../atom';
|
|
3
|
-
|
|
4
|
-
let {
|
|
5
|
-
class: klass = '',
|
|
6
|
-
as = 'li' as T,
|
|
7
|
-
preset = 'list.item',
|
|
8
|
-
children = undefined,
|
|
9
|
-
...restProps
|
|
10
|
-
} = $props();
|
|
11
|
-
</script>
|
|
12
|
-
|
|
13
|
-
<HtmlAtom
|
|
14
|
-
{as}
|
|
15
|
-
{preset}
|
|
16
|
-
class={['border-border flex w-full gap-2 px-4 py-1', '$preset', klass]}
|
|
17
|
-
{...restProps}
|
|
18
|
-
>
|
|
19
|
-
{@render children?.()}
|
|
20
|
-
</HtmlAtom>
|
|
1
|
+
<script lang="ts" generics="T extends keyof HTMLElementTagNameMap = 'li', B extends Base = Base">
|
|
2
|
+
import { HtmlAtom, type Base } from '../atom';
|
|
3
|
+
|
|
4
|
+
let {
|
|
5
|
+
class: klass = '',
|
|
6
|
+
as = 'li' as T,
|
|
7
|
+
preset = 'list.item',
|
|
8
|
+
children = undefined,
|
|
9
|
+
...restProps
|
|
10
|
+
} = $props();
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<HtmlAtom
|
|
14
|
+
{as}
|
|
15
|
+
{preset}
|
|
16
|
+
class={['border-border flex w-full gap-2 px-4 py-1', '$preset', klass]}
|
|
17
|
+
{...restProps}
|
|
18
|
+
>
|
|
19
|
+
{@render children?.()}
|
|
20
|
+
</HtmlAtom>
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export { default as
|
|
3
|
-
|
|
1
|
+
export { default as Root } from './menu-root.svelte';
|
|
2
|
+
export { default as Content } from './menu-content.svelte';
|
|
3
|
+
/**
|
|
4
|
+
* @deprecated Use Menu.Content instead
|
|
5
|
+
*/
|
|
6
|
+
export { default as List } from './menu-content.svelte';
|
|
7
|
+
export { default as Item } from './item/menu-item.svelte';
|
|
8
|
+
export { Trigger, Arrow, Indicator } from '../popover/atoms';
|
|
4
9
|
export { Divider, Group, Title } from '../list/atoms';
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export { default as
|
|
3
|
-
|
|
1
|
+
export { default as Root } from './menu-root.svelte';
|
|
2
|
+
export { default as Content } from './menu-content.svelte';
|
|
3
|
+
/**
|
|
4
|
+
* @deprecated Use Menu.Content instead
|
|
5
|
+
*/
|
|
6
|
+
export { default as List } from './menu-content.svelte';
|
|
7
|
+
export { default as Item } from './item/menu-item.svelte';
|
|
8
|
+
export { Trigger, Arrow, Indicator } from '../popover/atoms';
|
|
4
9
|
export { Divider, Group, Title } from '../list/atoms';
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { PopoverBond, PopoverState, type PopoverDomElements, type PopoverStateProps } from '../popover/bond.svelte';
|
|
2
|
+
import type { MenuItemController } from './item/controller.svelte';
|
|
3
|
+
export type MenuBondProps = PopoverStateProps;
|
|
4
|
+
export type MenuBondElements = PopoverDomElements;
|
|
5
|
+
export declare class MenuBond<Props extends MenuBondProps = MenuBondProps, State extends MenuBondState<Props> = MenuBondState<Props>, Elements extends MenuBondElements = MenuBondElements> extends PopoverBond<Props, State, Elements> {
|
|
6
|
+
constructor(state: State);
|
|
7
|
+
content(): {
|
|
8
|
+
role: string;
|
|
9
|
+
'aria-activedescendant': string | undefined;
|
|
10
|
+
'aria-orientation': "vertical";
|
|
11
|
+
onkeydown: (ev: KeyboardEvent) => void;
|
|
12
|
+
id: string;
|
|
13
|
+
'aria-modal': boolean;
|
|
14
|
+
'aria-labelledby': string;
|
|
15
|
+
inert: boolean | undefined;
|
|
16
|
+
tabindex: number;
|
|
17
|
+
'data-atom': string;
|
|
18
|
+
'data-kind': string;
|
|
19
|
+
'data-active': boolean;
|
|
20
|
+
};
|
|
21
|
+
trigger(): {
|
|
22
|
+
'aria-haspopup': "menu";
|
|
23
|
+
onkeydown: (ev: KeyboardEvent) => void;
|
|
24
|
+
id: string;
|
|
25
|
+
role: string;
|
|
26
|
+
disabled: boolean | undefined;
|
|
27
|
+
tabindex: number;
|
|
28
|
+
'aria-expanded': boolean;
|
|
29
|
+
'aria-disabled': boolean;
|
|
30
|
+
'aria-controls': string;
|
|
31
|
+
'data-kind': string;
|
|
32
|
+
onclick: (ev: PointerEvent) => void;
|
|
33
|
+
};
|
|
34
|
+
item(): {
|
|
35
|
+
role: string;
|
|
36
|
+
onkeyup: (ev: KeyboardEvent) => void;
|
|
37
|
+
};
|
|
38
|
+
static get<Props extends MenuBondProps = MenuBondProps, State extends MenuBondState<Props> = MenuBondState<Props>, Elements extends MenuBondElements = MenuBondElements>(): MenuBond<Props, State, Elements> | undefined;
|
|
39
|
+
static set<Props extends MenuBondProps = MenuBondProps, State extends MenuBondState<Props> = MenuBondState<Props>, Elements extends MenuBondElements = MenuBondElements>(context: MenuBond<Props, State, Elements>): MenuBond<Props, State, Elements>;
|
|
40
|
+
}
|
|
41
|
+
export declare class MenuBondState<Props extends MenuBondProps = MenuBondProps> extends PopoverState<Props> {
|
|
42
|
+
#private;
|
|
43
|
+
constructor(props: () => Props);
|
|
44
|
+
get items(): Map<string, MenuItemController>;
|
|
45
|
+
get highlightedId(): string | null;
|
|
46
|
+
get highlightedItem(): MenuItemController | null;
|
|
47
|
+
get navigation(): {
|
|
48
|
+
next: () => MenuItemController | null;
|
|
49
|
+
previous: () => MenuItemController | null;
|
|
50
|
+
};
|
|
51
|
+
mountItem(id: string, item: MenuItemController): () => void;
|
|
52
|
+
unmountItem(id: string): void;
|
|
53
|
+
item(id: string): MenuItemController | undefined;
|
|
54
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { SvelteMap, SvelteSet } from 'svelte/reactivity';
|
|
2
|
+
import { PopoverBond, PopoverState } from '../popover/bond.svelte';
|
|
3
|
+
export class MenuBond extends PopoverBond {
|
|
4
|
+
constructor(state) {
|
|
5
|
+
super(state);
|
|
6
|
+
}
|
|
7
|
+
content() {
|
|
8
|
+
const superProps = super.content();
|
|
9
|
+
const onkeydown = superProps.onkeydown;
|
|
10
|
+
const highlightedId = this.state.highlightedId;
|
|
11
|
+
return {
|
|
12
|
+
...superProps,
|
|
13
|
+
role: 'menu',
|
|
14
|
+
'aria-activedescendant': highlightedId ? `item-${highlightedId}` : undefined,
|
|
15
|
+
'aria-orientation': 'vertical',
|
|
16
|
+
onkeydown: (ev) => {
|
|
17
|
+
// Call any additional onkeydown handler
|
|
18
|
+
onkeydown?.(ev);
|
|
19
|
+
if (ev.defaultPrevented)
|
|
20
|
+
return;
|
|
21
|
+
// Handle arrow key navigation
|
|
22
|
+
if (ev.key === 'ArrowDown') {
|
|
23
|
+
this.state.navigation.next();
|
|
24
|
+
}
|
|
25
|
+
if (ev.key === 'ArrowUp') {
|
|
26
|
+
this.state.navigation.previous();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
trigger() {
|
|
32
|
+
const superProps = super.trigger();
|
|
33
|
+
return {
|
|
34
|
+
...superProps,
|
|
35
|
+
'aria-haspopup': 'menu',
|
|
36
|
+
'onkeydown': (ev) => {
|
|
37
|
+
if (ev.key === 'ArrowDown') {
|
|
38
|
+
this.state.navigation.next();
|
|
39
|
+
}
|
|
40
|
+
if (ev.key === 'ArrowUp') {
|
|
41
|
+
this.state.navigation.previous();
|
|
42
|
+
}
|
|
43
|
+
if ((ev.key === 'Enter' || ev.key === ' ') && this.state.props.open && this.state.highlightedItem) {
|
|
44
|
+
if (ev.key === ' ') {
|
|
45
|
+
ev.preventDefault();
|
|
46
|
+
}
|
|
47
|
+
this.state.highlightedItem?.element?.click();
|
|
48
|
+
}
|
|
49
|
+
// Call any additional onkeydown handler
|
|
50
|
+
superProps.onkeydown?.(ev);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
item() {
|
|
55
|
+
return {
|
|
56
|
+
role: 'menuitem',
|
|
57
|
+
onkeyup: (ev) => {
|
|
58
|
+
const currentTarget = ev.currentTarget;
|
|
59
|
+
const disabled = currentTarget.getAttribute('disabled') ||
|
|
60
|
+
currentTarget.getAttribute('aria-disabled') === 'true';
|
|
61
|
+
if (disabled)
|
|
62
|
+
return;
|
|
63
|
+
// Activate on Enter or Space
|
|
64
|
+
if (ev.key === 'Enter' || ev.key === ' ') {
|
|
65
|
+
ev.preventDefault();
|
|
66
|
+
// Call the click handler if provided
|
|
67
|
+
// cast to any to avoid strict event-type mismatch when forwarding
|
|
68
|
+
this?.state.close();
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
static get() {
|
|
74
|
+
return PopoverBond.get();
|
|
75
|
+
}
|
|
76
|
+
static set(context) {
|
|
77
|
+
return PopoverBond.set(context);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
export class MenuBondState extends PopoverState {
|
|
81
|
+
#keys = new SvelteSet();
|
|
82
|
+
#items = new SvelteMap();
|
|
83
|
+
#itemsAsArray = $derived(Array.from(this.#items.values()));
|
|
84
|
+
#index = $state(-1);
|
|
85
|
+
#highlightedId = $derived(Array.from(this.#items.keys())[this.#index] ?? null);
|
|
86
|
+
#highlightedItem = $derived(this.#itemsAsArray[this.#index] ?? null);
|
|
87
|
+
constructor(props) {
|
|
88
|
+
super(props);
|
|
89
|
+
}
|
|
90
|
+
get items() {
|
|
91
|
+
return this.#items;
|
|
92
|
+
}
|
|
93
|
+
get highlightedId() {
|
|
94
|
+
return this.#highlightedId;
|
|
95
|
+
}
|
|
96
|
+
get highlightedItem() {
|
|
97
|
+
return this.#highlightedItem;
|
|
98
|
+
}
|
|
99
|
+
get navigation() {
|
|
100
|
+
return {
|
|
101
|
+
next: () => {
|
|
102
|
+
if (this.#index < 0) {
|
|
103
|
+
this.#index = 0;
|
|
104
|
+
return this.#highlightedItem;
|
|
105
|
+
}
|
|
106
|
+
const length = this.#items.size;
|
|
107
|
+
this.#index = Math.min((this.#index + 1) % length, length - 1);
|
|
108
|
+
return this.#highlightedItem;
|
|
109
|
+
},
|
|
110
|
+
previous: () => {
|
|
111
|
+
if (this.#index <= 0) {
|
|
112
|
+
this.#index = this.#items.size - 1;
|
|
113
|
+
return this.#highlightedItem;
|
|
114
|
+
}
|
|
115
|
+
this.#index = Math.max(this.#index - 1, 0);
|
|
116
|
+
return this.#highlightedItem;
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
mountItem(id, item) {
|
|
121
|
+
this.#items.set(id, item);
|
|
122
|
+
return () => this.unmountItem(id);
|
|
123
|
+
}
|
|
124
|
+
unmountItem(id) {
|
|
125
|
+
if (this.#keys.has(id))
|
|
126
|
+
return; // keep the item if it's still in the data source
|
|
127
|
+
this.#items.delete(id);
|
|
128
|
+
}
|
|
129
|
+
item(id) {
|
|
130
|
+
return this.#items.get(id);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
@@ -2,3 +2,4 @@ export * as Menu from './atoms';
|
|
|
2
2
|
export * from './types';
|
|
3
3
|
export { PopoverBond, type PopoverDomElements, type PopoverParams, PopoverState, type PopoverStateProps, type TriggerParams } from '../popover';
|
|
4
4
|
export type { AnimatePopoverContentParams as AnimateMenuContentParams, animatePopoverContent as animateMenuContent } from '../popover/motion';
|
|
5
|
+
export * from './item';
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { MenuBond, MenuBondState, type MenuBondProps } from '../bond.svelte';
|
|
2
|
+
export type MenuItemControllerProps = {
|
|
3
|
+
id?: string;
|
|
4
|
+
};
|
|
5
|
+
export declare class MenuItemController {
|
|
6
|
+
#private;
|
|
7
|
+
static CONTEXT_KEY: string;
|
|
8
|
+
constructor(props?: () => MenuItemControllerProps);
|
|
9
|
+
get id(): string;
|
|
10
|
+
get props(): MenuItemControllerProps;
|
|
11
|
+
get element(): HTMLElement | null;
|
|
12
|
+
get menu(): MenuBond<MenuBondProps, MenuBondState<MenuBondProps>, import("..").PopoverDomElements> | undefined;
|
|
13
|
+
get isHighlighted(): boolean;
|
|
14
|
+
mount(): () => void;
|
|
15
|
+
unmount(): void;
|
|
16
|
+
destroy(): void;
|
|
17
|
+
share(): MenuItemController;
|
|
18
|
+
elementProps(): {
|
|
19
|
+
readonly [x: symbol]: (node: HTMLElement) => () => void;
|
|
20
|
+
readonly id: string;
|
|
21
|
+
readonly role: "menuitem";
|
|
22
|
+
readonly 'data-highlighted': boolean;
|
|
23
|
+
};
|
|
24
|
+
static get(): MenuItemController | undefined;
|
|
25
|
+
static set(item: MenuItemController): MenuItemController;
|
|
26
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { getContext, setContext } from 'svelte';
|
|
2
|
+
import { createAttachmentKey } from 'svelte/attachments';
|
|
3
|
+
import { nanoid } from 'nanoid';
|
|
4
|
+
import { MenuBond, MenuBondState } from '../bond.svelte';
|
|
5
|
+
export class MenuItemController {
|
|
6
|
+
static CONTEXT_KEY = '@atoms/context/menu/item';
|
|
7
|
+
#id;
|
|
8
|
+
#props;
|
|
9
|
+
#element = null;
|
|
10
|
+
#menu;
|
|
11
|
+
#unmount;
|
|
12
|
+
constructor(props = () => ({})) {
|
|
13
|
+
this.#props = props;
|
|
14
|
+
this.#id = this.props.id ?? nanoid();
|
|
15
|
+
this.#menu = MenuBond.get();
|
|
16
|
+
if (!this.#menu) {
|
|
17
|
+
throw new Error('MenuItem must be used within a Menu context');
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
get id() {
|
|
21
|
+
return this.#id;
|
|
22
|
+
}
|
|
23
|
+
get props() {
|
|
24
|
+
return this.#props();
|
|
25
|
+
}
|
|
26
|
+
get element() {
|
|
27
|
+
return this.#element;
|
|
28
|
+
}
|
|
29
|
+
get menu() {
|
|
30
|
+
return this.#menu;
|
|
31
|
+
}
|
|
32
|
+
get isHighlighted() {
|
|
33
|
+
return this.#menu?.state.highlightedId === this.#id;
|
|
34
|
+
}
|
|
35
|
+
mount() {
|
|
36
|
+
this.#unmount = this.#menu?.state?.mountItem?.(this.#id, this) ?? undefined;
|
|
37
|
+
return this.unmount;
|
|
38
|
+
}
|
|
39
|
+
unmount() {
|
|
40
|
+
this.#unmount?.();
|
|
41
|
+
}
|
|
42
|
+
destroy() {
|
|
43
|
+
this.unmount();
|
|
44
|
+
}
|
|
45
|
+
share() {
|
|
46
|
+
return MenuItemController.set(this);
|
|
47
|
+
}
|
|
48
|
+
elementProps() {
|
|
49
|
+
const itemId = `item-${this.id}`;
|
|
50
|
+
return {
|
|
51
|
+
id: itemId,
|
|
52
|
+
role: 'menuitem',
|
|
53
|
+
'data-highlighted': this.isHighlighted,
|
|
54
|
+
[createAttachmentKey()]: (node) => {
|
|
55
|
+
this.#element = node;
|
|
56
|
+
return () => {
|
|
57
|
+
// this.#unmount?.();
|
|
58
|
+
this.#element = null;
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
static get() {
|
|
64
|
+
return getContext(MenuItemController.CONTEXT_KEY);
|
|
65
|
+
}
|
|
66
|
+
static set(item) {
|
|
67
|
+
return setContext(MenuItemController.CONTEXT_KEY, item);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
<script
|
|
2
|
+
lang="ts"
|
|
3
|
+
generics="D, E extends keyof HTMLElementTagNameMap = 'div', B extends Base = Base"
|
|
4
|
+
>
|
|
5
|
+
import { defineProperty, defineState } from '../../../utils';
|
|
6
|
+
import type { Base } from '../../atom';
|
|
7
|
+
import { MenuItemController, type MenuItemControllerProps } from './controller.svelte';
|
|
8
|
+
import { MenuBond } from '../bond.svelte';
|
|
9
|
+
import { List } from '../../list';
|
|
10
|
+
import type { MenuItemProps } from './types';
|
|
11
|
+
|
|
12
|
+
const menu = MenuBond.get();
|
|
13
|
+
|
|
14
|
+
if (!menu) {
|
|
15
|
+
throw new Error('<MenuItem> must be used within a <Menu>.');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const ID = $props.id();
|
|
19
|
+
|
|
20
|
+
let {
|
|
21
|
+
class: klass = '',
|
|
22
|
+
id = ID,
|
|
23
|
+
preset: presetKey = 'menu.item',
|
|
24
|
+
children = undefined,
|
|
25
|
+
onclick = undefined,
|
|
26
|
+
disabled = undefined,
|
|
27
|
+
onmount = undefined,
|
|
28
|
+
ondestroy = undefined,
|
|
29
|
+
animate = undefined,
|
|
30
|
+
enter = undefined,
|
|
31
|
+
exit = undefined,
|
|
32
|
+
initial = undefined,
|
|
33
|
+
factory = _factory,
|
|
34
|
+
...restProps
|
|
35
|
+
}: MenuItemProps = $props();
|
|
36
|
+
|
|
37
|
+
const controller = factory().share();
|
|
38
|
+
|
|
39
|
+
const itemProps = $derived({
|
|
40
|
+
...menu?.item?.(),
|
|
41
|
+
...controller?.elementProps(),
|
|
42
|
+
...restProps
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
$effect(() => {
|
|
46
|
+
return () => {
|
|
47
|
+
controller.destroy();
|
|
48
|
+
};
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
function _factory() {
|
|
52
|
+
const item = menu?.state?.item?.(id);
|
|
53
|
+
|
|
54
|
+
if (item) {
|
|
55
|
+
return item as MenuItemController;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const bondProps = defineState<MenuItemControllerProps>([defineProperty('id', () => id)]);
|
|
59
|
+
const controller = new MenuItemController(() => bondProps);
|
|
60
|
+
|
|
61
|
+
controller.mount();
|
|
62
|
+
|
|
63
|
+
return controller;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function handleClick(ev: MouseEvent) {
|
|
67
|
+
onclick?.(ev);
|
|
68
|
+
|
|
69
|
+
if (ev.defaultPrevented) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
ev.preventDefault();
|
|
74
|
+
|
|
75
|
+
controller?.menu?.state.close();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function getController() {
|
|
79
|
+
return controller;
|
|
80
|
+
}
|
|
81
|
+
</script>
|
|
82
|
+
|
|
83
|
+
<List.Item
|
|
84
|
+
bond={controller}
|
|
85
|
+
preset={presetKey}
|
|
86
|
+
class={[
|
|
87
|
+
'border-border last:border-b-none hover:bg-foreground/5 active:bg-foreground/10 outline-primary cursor-pointer border-b',
|
|
88
|
+
'$preset',
|
|
89
|
+
klass
|
|
90
|
+
]}
|
|
91
|
+
onmount={onmount?.bind(controller) as any}
|
|
92
|
+
ondestroy={ondestroy?.bind(controller) as any}
|
|
93
|
+
enter={enter?.bind(controller) as any}
|
|
94
|
+
exit={exit?.bind(controller) as any}
|
|
95
|
+
initial={initial?.bind(controller) as any}
|
|
96
|
+
animate={animate?.bind(controller) as any}
|
|
97
|
+
aria-disabled={disabled ? true : undefined}
|
|
98
|
+
tabIndex={disabled ? -1 : 0}
|
|
99
|
+
onclick={handleClick}
|
|
100
|
+
{...itemProps}
|
|
101
|
+
>
|
|
102
|
+
{@render children?.({ menuItem: controller })}
|
|
103
|
+
</List.Item>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { Base } from '../../atom';
|
|
2
|
+
import { MenuItemController } from './controller.svelte';
|
|
3
|
+
import type { MenuItemProps } from './types';
|
|
4
|
+
declare function $$render<D, E extends keyof HTMLElementTagNameMap = 'div', B extends Base = Base>(): {
|
|
5
|
+
props: MenuItemProps;
|
|
6
|
+
exports: {
|
|
7
|
+
getController: () => MenuItemController;
|
|
8
|
+
};
|
|
9
|
+
bindings: "";
|
|
10
|
+
slots: {};
|
|
11
|
+
events: {};
|
|
12
|
+
};
|
|
13
|
+
declare class __sveltets_Render<D, E extends keyof HTMLElementTagNameMap = 'div', B extends Base = Base> {
|
|
14
|
+
props(): ReturnType<typeof $$render<D, E, B>>['props'];
|
|
15
|
+
events(): ReturnType<typeof $$render<D, E, B>>['events'];
|
|
16
|
+
slots(): ReturnType<typeof $$render<D, E, B>>['slots'];
|
|
17
|
+
bindings(): "";
|
|
18
|
+
exports(): {
|
|
19
|
+
getController: () => MenuItemController;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
interface $$IsomorphicComponent {
|
|
23
|
+
new <D, E extends keyof HTMLElementTagNameMap = 'div', B extends Base = Base>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<D, E, B>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<D, E, B>['props']>, ReturnType<__sveltets_Render<D, E, B>['events']>, ReturnType<__sveltets_Render<D, E, B>['slots']>> & {
|
|
24
|
+
$$bindings?: ReturnType<__sveltets_Render<D, E, B>['bindings']>;
|
|
25
|
+
} & ReturnType<__sveltets_Render<D, E, B>['exports']>;
|
|
26
|
+
<D, E extends keyof HTMLElementTagNameMap = 'div', B extends Base = Base>(internal: unknown, props: ReturnType<__sveltets_Render<D, E, B>['props']> & {}): ReturnType<__sveltets_Render<D, E, B>['exports']>;
|
|
27
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any, any, any>['bindings']>;
|
|
28
|
+
}
|
|
29
|
+
declare const MenuItem: $$IsomorphicComponent;
|
|
30
|
+
type MenuItem<D, E extends keyof HTMLElementTagNameMap = 'div', B extends Base = Base> = InstanceType<typeof MenuItem<D, E, B>>;
|
|
31
|
+
export default MenuItem;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { MenuItemController } from './controller.svelte';
|
|
3
|
+
import type { ClassValue } from '../../../utils';
|
|
4
|
+
import type { Base, HtmlAtomProps } from '../../atom';
|
|
5
|
+
/**
|
|
6
|
+
* Extend this interface to add custom menu list properties in your application.
|
|
7
|
+
*/
|
|
8
|
+
export interface MenuItemExtendProps {
|
|
9
|
+
}
|
|
10
|
+
export interface MenuItemProps<E extends keyof HTMLElementTagNameMap = 'div', B extends Base = Base> extends HtmlAtomProps<E, B>, MenuItemExtendProps {
|
|
11
|
+
/**
|
|
12
|
+
* Custom CSS class(es) to apply to the menu item
|
|
13
|
+
*/
|
|
14
|
+
class?: ClassValue;
|
|
15
|
+
/**
|
|
16
|
+
* Preset key for styling
|
|
17
|
+
* @default 'menu.item'
|
|
18
|
+
*/
|
|
19
|
+
preset?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Whether the menu item is disabled
|
|
22
|
+
*/
|
|
23
|
+
disabled?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Click event handler
|
|
26
|
+
*/
|
|
27
|
+
onclick?: (event: MouseEvent) => void;
|
|
28
|
+
/**
|
|
29
|
+
* Mount lifecycle callback
|
|
30
|
+
*/
|
|
31
|
+
onmount?: (this: MenuItemController) => void;
|
|
32
|
+
/**
|
|
33
|
+
* Destroy lifecycle callback
|
|
34
|
+
*/
|
|
35
|
+
ondestroy?: (this: MenuItemController) => void;
|
|
36
|
+
/**
|
|
37
|
+
* Animation configuration
|
|
38
|
+
*/
|
|
39
|
+
animate?: (this: MenuItemController) => any;
|
|
40
|
+
/**
|
|
41
|
+
* Enter animation configuration
|
|
42
|
+
*/
|
|
43
|
+
enter?: (this: MenuItemController) => any;
|
|
44
|
+
/**
|
|
45
|
+
* Exit animation configuration
|
|
46
|
+
*/
|
|
47
|
+
exit?: (this: MenuItemController) => any;
|
|
48
|
+
/**
|
|
49
|
+
* Initial state configuration
|
|
50
|
+
*/
|
|
51
|
+
initial?: (this: MenuItemController) => any;
|
|
52
|
+
/**
|
|
53
|
+
* Factory function to create a custom MenuItemController instance
|
|
54
|
+
*/
|
|
55
|
+
factory?: () => MenuItemController;
|
|
56
|
+
/**
|
|
57
|
+
* Render prop for children
|
|
58
|
+
*/
|
|
59
|
+
children?: Snippet<[{
|
|
60
|
+
menuItem: MenuItemController;
|
|
61
|
+
}]>;
|
|
62
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|