INIT
This commit is contained in:
+14
@@ -0,0 +1,14 @@
|
||||
<script lang="ts">
|
||||
import { mergeProps } from "svelte-toolbelt";
|
||||
import type { MenuArrowProps } from "../types.js";
|
||||
import { MenuArrowState } from "../menu.svelte.js";
|
||||
import FloatingLayerArrow from "../../utilities/floating-layer/components/floating-layer-arrow.svelte";
|
||||
|
||||
let { ref = $bindable(null), ...restProps }: MenuArrowProps = $props();
|
||||
|
||||
const arrowState = MenuArrowState.create();
|
||||
|
||||
const mergedProps = $derived(mergeProps(restProps, arrowState.props));
|
||||
</script>
|
||||
|
||||
<FloatingLayerArrow bind:ref {...mergedProps} />
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
declare const MenuArrow: import("svelte").Component<import("../../utilities/arrow/types.js").ArrowProps, {}, "ref">;
|
||||
type MenuArrow = ReturnType<typeof MenuArrow>;
|
||||
export default MenuArrow;
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
<script lang="ts">
|
||||
import { boxWith, mergeProps } from "svelte-toolbelt";
|
||||
import type { MenuCheckboxGroupProps } from "../types.js";
|
||||
import { MenuCheckboxGroupState } from "../menu.svelte.js";
|
||||
import { noop } from "../../../internal/noop.js";
|
||||
import { createId } from "../../../internal/create-id.js";
|
||||
|
||||
const uid = $props.id();
|
||||
|
||||
let {
|
||||
id = createId(uid),
|
||||
children,
|
||||
child,
|
||||
ref = $bindable(null),
|
||||
value = $bindable([]),
|
||||
onValueChange = noop,
|
||||
...restProps
|
||||
}: MenuCheckboxGroupProps = $props();
|
||||
|
||||
const checkboxGroupState = MenuCheckboxGroupState.create({
|
||||
value: boxWith(
|
||||
() => $state.snapshot(value),
|
||||
(v) => {
|
||||
value = $state.snapshot(v);
|
||||
onValueChange(v);
|
||||
}
|
||||
),
|
||||
onValueChange: boxWith(() => onValueChange),
|
||||
ref: boxWith(
|
||||
() => ref,
|
||||
(v) => (ref = v)
|
||||
),
|
||||
id: boxWith(() => id),
|
||||
});
|
||||
|
||||
const mergedProps = $derived(mergeProps(restProps, checkboxGroupState.props));
|
||||
</script>
|
||||
|
||||
{#if child}
|
||||
{@render child({ props: mergedProps })}
|
||||
{:else}
|
||||
<div {...mergedProps}>
|
||||
{@render children?.()}
|
||||
</div>
|
||||
{/if}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import type { MenuCheckboxGroupProps } from "../types.js";
|
||||
declare const MenuCheckboxGroup: import("svelte").Component<MenuCheckboxGroupProps, {}, "value" | "ref">;
|
||||
type MenuCheckboxGroup = ReturnType<typeof MenuCheckboxGroup>;
|
||||
export default MenuCheckboxGroup;
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
<script lang="ts">
|
||||
import { boxWith, mergeProps } from "svelte-toolbelt";
|
||||
import type { MenuCheckboxItemProps } from "../types.js";
|
||||
import { MenuCheckboxGroupContext, MenuCheckboxItemState } from "../menu.svelte.js";
|
||||
import { createId } from "../../../internal/create-id.js";
|
||||
import { noop } from "../../../internal/noop.js";
|
||||
import { watch } from "runed";
|
||||
|
||||
const uid = $props.id();
|
||||
|
||||
let {
|
||||
child,
|
||||
children,
|
||||
ref = $bindable(null),
|
||||
checked = $bindable(false),
|
||||
id = createId(uid),
|
||||
onCheckedChange = noop,
|
||||
disabled = false,
|
||||
onSelect = noop,
|
||||
closeOnSelect = true,
|
||||
indeterminate = $bindable(false),
|
||||
onIndeterminateChange = noop,
|
||||
value = "",
|
||||
...restProps
|
||||
}: MenuCheckboxItemProps = $props();
|
||||
|
||||
const group = MenuCheckboxGroupContext.getOr(null);
|
||||
|
||||
if (group && value) {
|
||||
if (group.opts.value.current.includes(value)) {
|
||||
checked = true;
|
||||
} else {
|
||||
checked = false;
|
||||
}
|
||||
}
|
||||
|
||||
watch.pre(
|
||||
() => value,
|
||||
() => {
|
||||
if (group && value) {
|
||||
if (group.opts.value.current.includes(value)) {
|
||||
checked = true;
|
||||
} else {
|
||||
checked = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const checkboxItemState = MenuCheckboxItemState.create(
|
||||
{
|
||||
checked: boxWith(
|
||||
() => checked,
|
||||
(v) => {
|
||||
if (v !== checked) {
|
||||
checked = v;
|
||||
onCheckedChange(v);
|
||||
}
|
||||
}
|
||||
),
|
||||
id: boxWith(() => id),
|
||||
disabled: boxWith(() => disabled),
|
||||
onSelect: boxWith(() => handleSelect),
|
||||
ref: boxWith(
|
||||
() => ref,
|
||||
(v) => (ref = v)
|
||||
),
|
||||
closeOnSelect: boxWith(() => closeOnSelect),
|
||||
indeterminate: boxWith(
|
||||
() => indeterminate,
|
||||
(v) => {
|
||||
if (v !== indeterminate) {
|
||||
indeterminate = v;
|
||||
onIndeterminateChange(v);
|
||||
}
|
||||
}
|
||||
),
|
||||
value: boxWith(() => value),
|
||||
},
|
||||
group
|
||||
);
|
||||
|
||||
function handleSelect(e: Event) {
|
||||
onSelect(e);
|
||||
if (e.defaultPrevented) return;
|
||||
checkboxItemState.toggleChecked();
|
||||
}
|
||||
|
||||
const mergedProps = $derived(mergeProps(restProps, checkboxItemState.props));
|
||||
</script>
|
||||
|
||||
{#if child}
|
||||
{@render child({ checked, indeterminate, props: mergedProps })}
|
||||
{:else}
|
||||
<div {...mergedProps}>
|
||||
{@render children?.({ checked, indeterminate })}
|
||||
</div>
|
||||
{/if}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import type { MenuCheckboxItemProps } from "../types.js";
|
||||
declare const MenuCheckboxItem: import("svelte").Component<MenuCheckboxItemProps, {}, "checked" | "indeterminate" | "ref">;
|
||||
type MenuCheckboxItem = ReturnType<typeof MenuCheckboxItem>;
|
||||
export default MenuCheckboxItem;
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
<script lang="ts">
|
||||
import { boxWith, mergeProps } from "svelte-toolbelt";
|
||||
import type { MenuContentStaticProps } from "../types.js";
|
||||
import { MenuContentState } from "../menu.svelte.js";
|
||||
import { createId } from "../../../internal/create-id.js";
|
||||
import { noop } from "../../../internal/noop.js";
|
||||
import PopperLayer from "../../utilities/popper-layer/popper-layer.svelte";
|
||||
import { getFloatingContentCSSVars } from "../../../internal/floating-svelte/floating-utils.svelte.js";
|
||||
import PopperLayerForceMount from "../../utilities/popper-layer/popper-layer-force-mount.svelte";
|
||||
|
||||
const uid = $props.id();
|
||||
|
||||
let {
|
||||
id = createId(uid),
|
||||
child,
|
||||
children,
|
||||
ref = $bindable(null),
|
||||
loop = true,
|
||||
onInteractOutside = noop,
|
||||
onEscapeKeydown = noop,
|
||||
onCloseAutoFocus: onCloseAutoFocusProp = noop,
|
||||
forceMount = false,
|
||||
style,
|
||||
...restProps
|
||||
}: MenuContentStaticProps = $props();
|
||||
|
||||
const contentState = MenuContentState.create({
|
||||
id: boxWith(() => id),
|
||||
loop: boxWith(() => loop),
|
||||
ref: boxWith(
|
||||
() => ref,
|
||||
(v) => (ref = v)
|
||||
),
|
||||
onCloseAutoFocus: boxWith(() => onCloseAutoFocusProp),
|
||||
});
|
||||
|
||||
const mergedProps = $derived(
|
||||
mergeProps(restProps, contentState.props, {
|
||||
style: { outline: "none" },
|
||||
})
|
||||
);
|
||||
|
||||
function handleInteractOutside(e: PointerEvent) {
|
||||
onInteractOutside(e);
|
||||
if (e.defaultPrevented) return;
|
||||
contentState.parentMenu.onClose();
|
||||
}
|
||||
|
||||
function handleEscapeKeydown(e: KeyboardEvent) {
|
||||
onEscapeKeydown(e);
|
||||
if (e.defaultPrevented) return;
|
||||
contentState.parentMenu.onClose();
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if forceMount}
|
||||
<PopperLayerForceMount
|
||||
{...mergedProps}
|
||||
{...contentState.popperProps}
|
||||
ref={contentState.opts.ref}
|
||||
enabled={contentState.parentMenu.opts.open.current}
|
||||
onInteractOutside={handleInteractOutside}
|
||||
onEscapeKeydown={handleEscapeKeydown}
|
||||
trapFocus
|
||||
{loop}
|
||||
forceMount={true}
|
||||
isStatic
|
||||
{id}
|
||||
shouldRender={contentState.shouldRender}
|
||||
>
|
||||
{#snippet popper({ props })}
|
||||
{@const finalProps = mergeProps(
|
||||
props,
|
||||
{ style: { outline: "none", ...getFloatingContentCSSVars("menu") } },
|
||||
{ style }
|
||||
)}
|
||||
{#if child}
|
||||
{@render child({ props: finalProps, ...contentState.snippetProps })}
|
||||
{:else}
|
||||
<div {...finalProps}>
|
||||
{@render children?.()}
|
||||
</div>
|
||||
{/if}
|
||||
{/snippet}
|
||||
</PopperLayerForceMount>
|
||||
{:else if !forceMount}
|
||||
<PopperLayer
|
||||
{...mergedProps}
|
||||
{...contentState.popperProps}
|
||||
ref={contentState.opts.ref}
|
||||
open={contentState.parentMenu.opts.open.current}
|
||||
onInteractOutside={handleInteractOutside}
|
||||
onEscapeKeydown={handleEscapeKeydown}
|
||||
trapFocus
|
||||
{loop}
|
||||
forceMount={false}
|
||||
isStatic
|
||||
{id}
|
||||
shouldRender={contentState.shouldRender}
|
||||
>
|
||||
{#snippet popper({ props })}
|
||||
{@const finalProps = mergeProps(
|
||||
props,
|
||||
{ style: { outline: "none", ...getFloatingContentCSSVars("menu") } },
|
||||
{ style }
|
||||
)}
|
||||
{#if child}
|
||||
{@render child({ props: finalProps, ...contentState.snippetProps })}
|
||||
{:else}
|
||||
<div {...finalProps}>
|
||||
{@render children?.()}
|
||||
</div>
|
||||
{/if}
|
||||
{/snippet}
|
||||
</PopperLayer>
|
||||
{/if}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import type { MenuContentStaticProps } from "../types.js";
|
||||
declare const MenuContentStatic: import("svelte").Component<MenuContentStaticProps, {}, "ref">;
|
||||
type MenuContentStatic = ReturnType<typeof MenuContentStatic>;
|
||||
export default MenuContentStatic;
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
<script lang="ts">
|
||||
import { boxWith, mergeProps } from "svelte-toolbelt";
|
||||
import type { MenuContentProps } from "../types.js";
|
||||
import { MenuContentState } from "../menu.svelte.js";
|
||||
import { createId } from "../../../internal/create-id.js";
|
||||
import { noop } from "../../../internal/noop.js";
|
||||
import PopperLayer from "../../utilities/popper-layer/popper-layer.svelte";
|
||||
import { getFloatingContentCSSVars } from "../../../internal/floating-svelte/floating-utils.svelte.js";
|
||||
import PopperLayerForceMount from "../../utilities/popper-layer/popper-layer-force-mount.svelte";
|
||||
|
||||
const uid = $props.id();
|
||||
|
||||
let {
|
||||
id = createId(uid),
|
||||
child,
|
||||
children,
|
||||
ref = $bindable(null),
|
||||
loop = true,
|
||||
onInteractOutside = noop,
|
||||
onEscapeKeydown = noop,
|
||||
onCloseAutoFocus: onCloseAutoFocusProp = noop,
|
||||
forceMount = false,
|
||||
style,
|
||||
...restProps
|
||||
}: MenuContentProps = $props();
|
||||
|
||||
const contentState = MenuContentState.create({
|
||||
id: boxWith(() => id),
|
||||
loop: boxWith(() => loop),
|
||||
ref: boxWith(
|
||||
() => ref,
|
||||
(v) => (ref = v)
|
||||
),
|
||||
onCloseAutoFocus: boxWith(() => onCloseAutoFocusProp),
|
||||
});
|
||||
|
||||
const mergedProps = $derived(
|
||||
mergeProps(restProps, contentState.props, {
|
||||
style: { outline: "none" },
|
||||
})
|
||||
);
|
||||
|
||||
function handleInteractOutside(e: PointerEvent) {
|
||||
onInteractOutside(e);
|
||||
if (e.defaultPrevented) return;
|
||||
// don't close if the interaction is with a submenu content or items
|
||||
if (e.target && e.target instanceof Element) {
|
||||
const subContentSelector = `[${contentState.parentMenu.root.getBitsAttr("sub-content")}]`;
|
||||
if (e.target.closest(subContentSelector)) return;
|
||||
}
|
||||
contentState.parentMenu.onClose();
|
||||
}
|
||||
|
||||
function handleEscapeKeydown(e: KeyboardEvent) {
|
||||
onEscapeKeydown(e);
|
||||
if (e.defaultPrevented) return;
|
||||
contentState.parentMenu.onClose();
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if forceMount}
|
||||
<PopperLayerForceMount
|
||||
{...mergedProps}
|
||||
{...contentState.popperProps}
|
||||
ref={contentState.opts.ref}
|
||||
enabled={contentState.parentMenu.opts.open.current}
|
||||
onInteractOutside={handleInteractOutside}
|
||||
onEscapeKeydown={handleEscapeKeydown}
|
||||
trapFocus
|
||||
{loop}
|
||||
forceMount={true}
|
||||
{id}
|
||||
shouldRender={contentState.shouldRender}
|
||||
>
|
||||
{#snippet popper({ props, wrapperProps })}
|
||||
{@const finalProps = mergeProps(
|
||||
props,
|
||||
{ style: { outline: "none", ...getFloatingContentCSSVars("menu") } },
|
||||
{ style }
|
||||
)}
|
||||
{#if child}
|
||||
{@render child({ props: finalProps, wrapperProps, ...contentState.snippetProps })}
|
||||
{:else}
|
||||
<div {...wrapperProps}>
|
||||
<div {...finalProps}>
|
||||
{@render children?.()}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{/snippet}
|
||||
</PopperLayerForceMount>
|
||||
{:else if !forceMount}
|
||||
<PopperLayer
|
||||
{...mergedProps}
|
||||
{...contentState.popperProps}
|
||||
ref={contentState.opts.ref}
|
||||
open={contentState.parentMenu.opts.open.current}
|
||||
onInteractOutside={handleInteractOutside}
|
||||
onEscapeKeydown={handleEscapeKeydown}
|
||||
trapFocus
|
||||
{loop}
|
||||
forceMount={false}
|
||||
{id}
|
||||
shouldRender={contentState.shouldRender}
|
||||
>
|
||||
{#snippet popper({ props, wrapperProps })}
|
||||
{@const finalProps = mergeProps(
|
||||
props,
|
||||
{ style: { outline: "none", ...getFloatingContentCSSVars("menu") } },
|
||||
{ style }
|
||||
)}
|
||||
{#if child}
|
||||
{@render child({ props: finalProps, wrapperProps, ...contentState.snippetProps })}
|
||||
{:else}
|
||||
<div {...wrapperProps}>
|
||||
<div {...finalProps}>
|
||||
{@render children?.()}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{/snippet}
|
||||
</PopperLayer>
|
||||
{/if}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import type { MenuContentProps } from "../types.js";
|
||||
declare const MenuContent: import("svelte").Component<MenuContentProps, {}, "ref">;
|
||||
type MenuContent = ReturnType<typeof MenuContent>;
|
||||
export default MenuContent;
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
<script lang="ts">
|
||||
import { boxWith, mergeProps } from "svelte-toolbelt";
|
||||
import type { MenuGroupHeadingProps } from "../types.js";
|
||||
import { MenuGroupHeadingState } from "../menu.svelte.js";
|
||||
import { createId } from "../../../internal/create-id.js";
|
||||
|
||||
const uid = $props.id();
|
||||
|
||||
let {
|
||||
children,
|
||||
child,
|
||||
ref = $bindable(null),
|
||||
id = createId(uid),
|
||||
...restProps
|
||||
}: MenuGroupHeadingProps = $props();
|
||||
|
||||
const groupHeadingState = MenuGroupHeadingState.create({
|
||||
id: boxWith(() => id),
|
||||
ref: boxWith(
|
||||
() => ref,
|
||||
(v) => (ref = v)
|
||||
),
|
||||
});
|
||||
const mergedProps = $derived(mergeProps(restProps, groupHeadingState.props));
|
||||
</script>
|
||||
|
||||
{#if child}
|
||||
{@render child({ props: mergedProps })}
|
||||
{:else}
|
||||
<div {...mergedProps}>
|
||||
{@render children?.()}
|
||||
</div>
|
||||
{/if}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import type { MenuGroupHeadingProps } from "../types.js";
|
||||
declare const MenuGroupHeading: import("svelte").Component<MenuGroupHeadingProps, {}, "ref">;
|
||||
type MenuGroupHeading = ReturnType<typeof MenuGroupHeading>;
|
||||
export default MenuGroupHeading;
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
<script lang="ts">
|
||||
import { boxWith, mergeProps } from "svelte-toolbelt";
|
||||
import type { MenuGroupProps } from "../types.js";
|
||||
import { MenuGroupState } from "../menu.svelte.js";
|
||||
import { createId } from "../../../internal/create-id.js";
|
||||
|
||||
const uid = $props.id();
|
||||
|
||||
let {
|
||||
children,
|
||||
child,
|
||||
ref = $bindable(null),
|
||||
id = createId(uid),
|
||||
...restProps
|
||||
}: MenuGroupProps = $props();
|
||||
|
||||
const groupState = MenuGroupState.create({
|
||||
id: boxWith(() => id),
|
||||
ref: boxWith(
|
||||
() => ref,
|
||||
(v) => (ref = v)
|
||||
),
|
||||
});
|
||||
const mergedProps = $derived(mergeProps(restProps, groupState.props));
|
||||
</script>
|
||||
|
||||
{#if child}
|
||||
{@render child({ props: mergedProps })}
|
||||
{:else}
|
||||
<div {...mergedProps}>
|
||||
{@render children?.()}
|
||||
</div>
|
||||
{/if}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import type { MenuGroupProps } from "../types.js";
|
||||
declare const MenuGroup: import("svelte").Component<MenuGroupProps, {}, "ref">;
|
||||
type MenuGroup = ReturnType<typeof MenuGroup>;
|
||||
export default MenuGroup;
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
<script lang="ts">
|
||||
import { boxWith, mergeProps } from "svelte-toolbelt";
|
||||
import type { MenuItemProps } from "../types.js";
|
||||
import { MenuItemState } from "../menu.svelte.js";
|
||||
import { createId } from "../../../internal/create-id.js";
|
||||
import { noop } from "../../../internal/noop.js";
|
||||
|
||||
const uid = $props.id();
|
||||
|
||||
let {
|
||||
child,
|
||||
children,
|
||||
ref = $bindable(null),
|
||||
id = createId(uid),
|
||||
disabled = false,
|
||||
onSelect = noop,
|
||||
closeOnSelect = true,
|
||||
...restProps
|
||||
}: MenuItemProps = $props();
|
||||
|
||||
const itemState = MenuItemState.create({
|
||||
id: boxWith(() => id),
|
||||
disabled: boxWith(() => disabled),
|
||||
onSelect: boxWith(() => onSelect),
|
||||
ref: boxWith(
|
||||
() => ref,
|
||||
(v) => (ref = v)
|
||||
),
|
||||
closeOnSelect: boxWith(() => closeOnSelect),
|
||||
});
|
||||
|
||||
const mergedProps = $derived(mergeProps(restProps, itemState.props));
|
||||
</script>
|
||||
|
||||
{#if child}
|
||||
{@render child({ props: mergedProps })}
|
||||
{:else}
|
||||
<div {...mergedProps}>
|
||||
{@render children?.()}
|
||||
</div>
|
||||
{/if}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import type { MenuItemProps } from "../types.js";
|
||||
declare const MenuItem: import("svelte").Component<MenuItemProps, {}, "ref">;
|
||||
type MenuItem = ReturnType<typeof MenuItem>;
|
||||
export default MenuItem;
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
<script lang="ts">
|
||||
import { boxWith, mergeProps } from "svelte-toolbelt";
|
||||
import type { MenuRadioGroupProps } from "../types.js";
|
||||
import { MenuRadioGroupState } from "../menu.svelte.js";
|
||||
import { noop } from "../../../internal/noop.js";
|
||||
import { createId } from "../../../internal/create-id.js";
|
||||
|
||||
const uid = $props.id();
|
||||
|
||||
let {
|
||||
id = createId(uid),
|
||||
children,
|
||||
child,
|
||||
ref = $bindable(null),
|
||||
value = $bindable(""),
|
||||
onValueChange = noop,
|
||||
...restProps
|
||||
}: MenuRadioGroupProps = $props();
|
||||
|
||||
const radioGroupState = MenuRadioGroupState.create({
|
||||
value: boxWith(
|
||||
() => value,
|
||||
(v) => {
|
||||
value = v;
|
||||
onValueChange(v);
|
||||
}
|
||||
),
|
||||
ref: boxWith(
|
||||
() => ref,
|
||||
(v) => (ref = v)
|
||||
),
|
||||
id: boxWith(() => id),
|
||||
});
|
||||
|
||||
const mergedProps = $derived(mergeProps(restProps, radioGroupState.props));
|
||||
</script>
|
||||
|
||||
{#if child}
|
||||
{@render child({ props: mergedProps })}
|
||||
{:else}
|
||||
<div {...mergedProps}>
|
||||
{@render children?.()}
|
||||
</div>
|
||||
{/if}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import type { MenuRadioGroupProps } from "../types.js";
|
||||
declare const MenuRadioGroup: import("svelte").Component<MenuRadioGroupProps, {}, "value" | "ref">;
|
||||
type MenuRadioGroup = ReturnType<typeof MenuRadioGroup>;
|
||||
export default MenuRadioGroup;
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
<script lang="ts">
|
||||
import { boxWith, mergeProps } from "svelte-toolbelt";
|
||||
import type { MenuRadioItemProps } from "../types.js";
|
||||
import { MenuRadioItemState } from "../menu.svelte.js";
|
||||
import { createId } from "../../../internal/create-id.js";
|
||||
import { noop } from "../../../internal/noop.js";
|
||||
|
||||
const uid = $props.id();
|
||||
|
||||
let {
|
||||
children,
|
||||
child,
|
||||
ref = $bindable(null),
|
||||
value,
|
||||
onSelect = noop,
|
||||
id = createId(uid),
|
||||
disabled = false,
|
||||
closeOnSelect = true,
|
||||
...restProps
|
||||
}: MenuRadioItemProps = $props();
|
||||
|
||||
const radioItemState = MenuRadioItemState.create({
|
||||
value: boxWith(() => value),
|
||||
id: boxWith(() => id),
|
||||
disabled: boxWith(() => disabled),
|
||||
onSelect: boxWith(() => handleSelect),
|
||||
ref: boxWith(
|
||||
() => ref,
|
||||
(v) => (ref = v)
|
||||
),
|
||||
closeOnSelect: boxWith(() => closeOnSelect),
|
||||
});
|
||||
|
||||
function handleSelect(e: Event) {
|
||||
onSelect(e);
|
||||
if (e.defaultPrevented) return;
|
||||
radioItemState.selectValue();
|
||||
}
|
||||
|
||||
const mergedProps = $derived(mergeProps(restProps, radioItemState.props));
|
||||
</script>
|
||||
|
||||
{#if child}
|
||||
{@render child({ props: mergedProps, checked: radioItemState.isChecked })}
|
||||
{:else}
|
||||
<div {...mergedProps}>
|
||||
{@render children?.({ checked: radioItemState.isChecked })}
|
||||
</div>
|
||||
{/if}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import type { MenuRadioItemProps } from "../types.js";
|
||||
declare const MenuRadioItem: import("svelte").Component<MenuRadioItemProps, {}, "ref">;
|
||||
type MenuRadioItem = ReturnType<typeof MenuRadioItem>;
|
||||
export default MenuRadioItem;
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
<script lang="ts">
|
||||
import { boxWith, mergeProps } from "svelte-toolbelt";
|
||||
import type { MenuSeparatorProps } from "../types.js";
|
||||
import { MenuSeparatorState } from "../menu.svelte.js";
|
||||
import { createId } from "../../../internal/create-id.js";
|
||||
|
||||
const uid = $props.id();
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
id = createId(uid),
|
||||
child,
|
||||
children,
|
||||
...restProps
|
||||
}: MenuSeparatorProps = $props();
|
||||
|
||||
const separatorState = MenuSeparatorState.create({
|
||||
id: boxWith(() => id),
|
||||
ref: boxWith(
|
||||
() => ref,
|
||||
(v) => (ref = v)
|
||||
),
|
||||
});
|
||||
|
||||
const mergedProps = $derived(mergeProps(restProps, separatorState.props));
|
||||
</script>
|
||||
|
||||
{#if child}
|
||||
{@render child({ props: mergedProps })}
|
||||
{:else}
|
||||
<div {...mergedProps}>
|
||||
{@render children?.()}
|
||||
</div>
|
||||
{/if}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import type { MenuSeparatorProps } from "../types.js";
|
||||
declare const MenuSeparator: import("svelte").Component<MenuSeparatorProps, {}, "ref">;
|
||||
type MenuSeparator = ReturnType<typeof MenuSeparator>;
|
||||
export default MenuSeparator;
|
||||
+176
@@ -0,0 +1,176 @@
|
||||
<script lang="ts">
|
||||
import { afterTick, boxWith, mergeProps } from "svelte-toolbelt";
|
||||
import type { MenuSubContentStaticProps } from "../types.js";
|
||||
import { MenuContentState } from "../menu.svelte.js";
|
||||
import { SUB_CLOSE_KEYS } from "../utils.js";
|
||||
import { createId } from "../../../internal/create-id.js";
|
||||
import PopperLayer from "../../utilities/popper-layer/popper-layer.svelte";
|
||||
import { noop } from "../../../internal/noop.js";
|
||||
import { isHTMLElement } from "../../../internal/is.js";
|
||||
import { getFloatingContentCSSVars } from "../../../internal/floating-svelte/floating-utils.svelte.js";
|
||||
import PopperLayerForceMount from "../../utilities/popper-layer/popper-layer-force-mount.svelte";
|
||||
|
||||
const uid = $props.id();
|
||||
|
||||
let {
|
||||
id = createId(uid),
|
||||
ref = $bindable(null),
|
||||
children,
|
||||
child,
|
||||
loop = true,
|
||||
onInteractOutside = noop,
|
||||
forceMount = false,
|
||||
onEscapeKeydown = noop,
|
||||
interactOutsideBehavior = "defer-otherwise-close",
|
||||
escapeKeydownBehavior = "defer-otherwise-close",
|
||||
onOpenAutoFocus: onOpenAutoFocusProp = noop,
|
||||
onCloseAutoFocus: onCloseAutoFocusProp = noop,
|
||||
onFocusOutside = noop,
|
||||
trapFocus = false,
|
||||
style,
|
||||
...restProps
|
||||
}: MenuSubContentStaticProps = $props();
|
||||
|
||||
const subContentState = MenuContentState.create({
|
||||
id: boxWith(() => id),
|
||||
loop: boxWith(() => loop),
|
||||
ref: boxWith(
|
||||
() => ref,
|
||||
(v) => (ref = v)
|
||||
),
|
||||
onCloseAutoFocus: boxWith(() => handleCloseAutoFocus),
|
||||
isSub: true,
|
||||
});
|
||||
|
||||
function onkeydown(e: KeyboardEvent) {
|
||||
const isKeyDownInside = (e.currentTarget as HTMLElement).contains(e.target as HTMLElement);
|
||||
const isCloseKey = SUB_CLOSE_KEYS[
|
||||
subContentState.parentMenu.root.opts.dir.current
|
||||
].includes(e.key);
|
||||
if (isKeyDownInside && isCloseKey) {
|
||||
subContentState.parentMenu.onClose();
|
||||
const triggerNode = subContentState.parentMenu.triggerNode;
|
||||
triggerNode?.focus();
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
const dataAttr = $derived(subContentState.parentMenu.root.getBitsAttr("sub-content"));
|
||||
|
||||
const mergedProps = $derived(
|
||||
mergeProps(restProps, subContentState.props, {
|
||||
onkeydown,
|
||||
[dataAttr]: "",
|
||||
})
|
||||
);
|
||||
|
||||
function handleOpenAutoFocus(e: Event) {
|
||||
onOpenAutoFocusProp(e);
|
||||
if (e.defaultPrevented) return;
|
||||
afterTick(() => {
|
||||
e.preventDefault();
|
||||
if (subContentState.parentMenu.root.isUsingKeyboard) {
|
||||
const subContentEl = subContentState.parentMenu.contentNode;
|
||||
subContentEl?.focus();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function handleCloseAutoFocus(e: Event) {
|
||||
onCloseAutoFocusProp(e);
|
||||
if (e.defaultPrevented) return;
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
function handleInteractOutside(e: PointerEvent) {
|
||||
onInteractOutside(e);
|
||||
if (e.defaultPrevented) return;
|
||||
subContentState.parentMenu.onClose();
|
||||
}
|
||||
|
||||
function handleEscapeKeydown(e: KeyboardEvent) {
|
||||
onEscapeKeydown(e);
|
||||
if (e.defaultPrevented) return;
|
||||
subContentState.parentMenu.onClose();
|
||||
}
|
||||
|
||||
function handleOnFocusOutside(e: FocusEvent) {
|
||||
onFocusOutside(e);
|
||||
if (e.defaultPrevented) return;
|
||||
// We prevent closing when the trigger is focused to avoid triggering a re-open animation
|
||||
// on pointer interaction.
|
||||
if (!isHTMLElement(e.target)) return;
|
||||
if (e.target.id !== subContentState.parentMenu.triggerNode?.id) {
|
||||
subContentState.parentMenu.onClose();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if forceMount}
|
||||
<PopperLayerForceMount
|
||||
{...mergedProps}
|
||||
ref={subContentState.opts.ref}
|
||||
{interactOutsideBehavior}
|
||||
{escapeKeydownBehavior}
|
||||
onOpenAutoFocus={handleOpenAutoFocus}
|
||||
enabled={subContentState.parentMenu.opts.open.current}
|
||||
onInteractOutside={handleInteractOutside}
|
||||
onEscapeKeydown={handleEscapeKeydown}
|
||||
onFocusOutside={handleOnFocusOutside}
|
||||
preventScroll={false}
|
||||
{loop}
|
||||
{trapFocus}
|
||||
isStatic
|
||||
shouldRender={subContentState.shouldRender}
|
||||
>
|
||||
{#snippet popper({ props })}
|
||||
{@const finalProps = mergeProps(
|
||||
props,
|
||||
mergedProps,
|
||||
{ style: getFloatingContentCSSVars("menu") },
|
||||
{ style }
|
||||
)}
|
||||
{#if child}
|
||||
{@render child({ props: finalProps, ...subContentState.snippetProps })}
|
||||
{:else}
|
||||
<div {...finalProps}>
|
||||
{@render children?.()}
|
||||
</div>
|
||||
{/if}
|
||||
{/snippet}
|
||||
</PopperLayerForceMount>
|
||||
{:else if !forceMount}
|
||||
<PopperLayer
|
||||
{...mergedProps}
|
||||
ref={subContentState.opts.ref}
|
||||
{interactOutsideBehavior}
|
||||
{escapeKeydownBehavior}
|
||||
onCloseAutoFocus={handleCloseAutoFocus}
|
||||
onOpenAutoFocus={handleOpenAutoFocus}
|
||||
open={subContentState.parentMenu.opts.open.current}
|
||||
onInteractOutside={handleInteractOutside}
|
||||
onEscapeKeydown={handleEscapeKeydown}
|
||||
onFocusOutside={handleOnFocusOutside}
|
||||
preventScroll={false}
|
||||
{loop}
|
||||
{trapFocus}
|
||||
isStatic
|
||||
shouldRender={subContentState.shouldRender}
|
||||
>
|
||||
{#snippet popper({ props })}
|
||||
{@const finalProps = mergeProps(
|
||||
props,
|
||||
mergedProps,
|
||||
{ style: getFloatingContentCSSVars("menu") },
|
||||
{ style }
|
||||
)}
|
||||
{#if child}
|
||||
{@render child({ props: finalProps, ...subContentState.snippetProps })}
|
||||
{:else}
|
||||
<div {...finalProps}>
|
||||
{@render children?.()}
|
||||
</div>
|
||||
{/if}
|
||||
{/snippet}
|
||||
</PopperLayer>
|
||||
{/if}
|
||||
Generated
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
import type { MenuSubContentStaticProps } from "../types.js";
|
||||
declare const MenuSubContentStatic: import("svelte").Component<MenuSubContentStaticProps, {}, "ref">;
|
||||
type MenuSubContentStatic = ReturnType<typeof MenuSubContentStatic>;
|
||||
export default MenuSubContentStatic;
|
||||
+188
@@ -0,0 +1,188 @@
|
||||
<script lang="ts">
|
||||
import { boxWith, mergeProps } from "svelte-toolbelt";
|
||||
import type { MenuSubContentProps } from "../types.js";
|
||||
import { MenuOpenEvent, MenuContentState } from "../menu.svelte.js";
|
||||
import { SUB_CLOSE_KEYS } from "../utils.js";
|
||||
import { createId } from "../../../internal/create-id.js";
|
||||
import PopperLayer from "../../utilities/popper-layer/popper-layer.svelte";
|
||||
import { noop } from "../../../internal/noop.js";
|
||||
import { isHTMLElement } from "../../../internal/is.js";
|
||||
import { getFloatingContentCSSVars } from "../../../internal/floating-svelte/floating-utils.svelte.js";
|
||||
import PopperLayerForceMount from "../../utilities/popper-layer/popper-layer-force-mount.svelte";
|
||||
|
||||
const uid = $props.id();
|
||||
|
||||
let {
|
||||
id = createId(uid),
|
||||
ref = $bindable(null),
|
||||
children,
|
||||
child,
|
||||
loop = true,
|
||||
onInteractOutside = noop,
|
||||
forceMount = false,
|
||||
onEscapeKeydown = noop,
|
||||
interactOutsideBehavior = "defer-otherwise-close",
|
||||
escapeKeydownBehavior = "defer-otherwise-close",
|
||||
onOpenAutoFocus: onOpenAutoFocusProp = noop,
|
||||
onCloseAutoFocus: onCloseAutoFocusProp = noop,
|
||||
onFocusOutside = noop,
|
||||
side = "right",
|
||||
trapFocus = false,
|
||||
style,
|
||||
...restProps
|
||||
}: MenuSubContentProps = $props();
|
||||
|
||||
const subContentState = MenuContentState.create({
|
||||
id: boxWith(() => id),
|
||||
loop: boxWith(() => loop),
|
||||
ref: boxWith(
|
||||
() => ref,
|
||||
(v) => (ref = v)
|
||||
),
|
||||
isSub: true,
|
||||
onCloseAutoFocus: boxWith(() => handleCloseAutoFocus),
|
||||
});
|
||||
|
||||
function onkeydown(e: KeyboardEvent) {
|
||||
const isKeyDownInside = (e.currentTarget as HTMLElement).contains(e.target as HTMLElement);
|
||||
const isCloseKey = SUB_CLOSE_KEYS[
|
||||
subContentState.parentMenu.root.opts.dir.current
|
||||
].includes(e.key);
|
||||
if (isKeyDownInside && isCloseKey) {
|
||||
subContentState.parentMenu.onClose();
|
||||
const triggerNode = subContentState.parentMenu.triggerNode;
|
||||
triggerNode?.focus();
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
const dataAttr = $derived(subContentState.parentMenu.root.getBitsAttr("sub-content"));
|
||||
|
||||
const mergedProps = $derived(
|
||||
mergeProps(restProps, subContentState.props, {
|
||||
side,
|
||||
onkeydown,
|
||||
[dataAttr]: "",
|
||||
})
|
||||
);
|
||||
|
||||
function handleOpenAutoFocus(e: Event) {
|
||||
onOpenAutoFocusProp(e);
|
||||
if (e.defaultPrevented) return;
|
||||
e.preventDefault();
|
||||
if (
|
||||
subContentState.parentMenu.root.isUsingKeyboard &&
|
||||
subContentState.parentMenu.contentNode
|
||||
) {
|
||||
MenuOpenEvent.dispatch(subContentState.parentMenu.contentNode);
|
||||
}
|
||||
}
|
||||
|
||||
function handleCloseAutoFocus(e: Event) {
|
||||
onCloseAutoFocusProp(e);
|
||||
if (e.defaultPrevented) return;
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
function handleInteractOutside(e: PointerEvent) {
|
||||
onInteractOutside(e);
|
||||
if (e.defaultPrevented) return;
|
||||
subContentState.parentMenu.onClose();
|
||||
}
|
||||
|
||||
function handleEscapeKeydown(e: KeyboardEvent) {
|
||||
onEscapeKeydown(e);
|
||||
if (e.defaultPrevented) return;
|
||||
subContentState.parentMenu.onClose();
|
||||
}
|
||||
|
||||
function handleOnFocusOutside(e: FocusEvent) {
|
||||
onFocusOutside(e);
|
||||
if (e.defaultPrevented) return;
|
||||
// We prevent closing when the trigger is focused to avoid triggering a re-open animation
|
||||
// on pointer interaction.
|
||||
if (!isHTMLElement(e.target)) return;
|
||||
if (e.target.id !== subContentState.parentMenu.triggerNode?.id) {
|
||||
subContentState.parentMenu.onClose();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if forceMount}
|
||||
<PopperLayerForceMount
|
||||
{...mergedProps}
|
||||
ref={subContentState.opts.ref}
|
||||
{interactOutsideBehavior}
|
||||
{escapeKeydownBehavior}
|
||||
onOpenAutoFocus={handleOpenAutoFocus}
|
||||
enabled={subContentState.parentMenu.opts.open.current}
|
||||
onInteractOutside={handleInteractOutside}
|
||||
onEscapeKeydown={handleEscapeKeydown}
|
||||
onFocusOutside={handleOnFocusOutside}
|
||||
preventScroll={false}
|
||||
{loop}
|
||||
{trapFocus}
|
||||
shouldRender={subContentState.shouldRender}
|
||||
>
|
||||
{#snippet popper({ props, wrapperProps })}
|
||||
{@const finalProps = mergeProps(
|
||||
props,
|
||||
mergedProps,
|
||||
{ style: getFloatingContentCSSVars("menu") },
|
||||
{ style }
|
||||
)}
|
||||
{#if child}
|
||||
{@render child({
|
||||
props: finalProps,
|
||||
wrapperProps,
|
||||
...subContentState.snippetProps,
|
||||
})}
|
||||
{:else}
|
||||
<div {...wrapperProps}>
|
||||
<div {...finalProps}>
|
||||
{@render children?.()}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{/snippet}
|
||||
</PopperLayerForceMount>
|
||||
{:else if !forceMount}
|
||||
<PopperLayer
|
||||
{...mergedProps}
|
||||
ref={subContentState.opts.ref}
|
||||
{interactOutsideBehavior}
|
||||
{escapeKeydownBehavior}
|
||||
onCloseAutoFocus={handleCloseAutoFocus}
|
||||
onOpenAutoFocus={handleOpenAutoFocus}
|
||||
open={subContentState.parentMenu.opts.open.current}
|
||||
onInteractOutside={handleInteractOutside}
|
||||
onEscapeKeydown={handleEscapeKeydown}
|
||||
onFocusOutside={handleOnFocusOutside}
|
||||
preventScroll={false}
|
||||
{loop}
|
||||
{trapFocus}
|
||||
shouldRender={subContentState.shouldRender}
|
||||
>
|
||||
{#snippet popper({ props, wrapperProps })}
|
||||
{@const finalProps = mergeProps(
|
||||
props,
|
||||
mergedProps,
|
||||
{ style: getFloatingContentCSSVars("menu") },
|
||||
{ style }
|
||||
)}
|
||||
{#if child}
|
||||
{@render child({
|
||||
props: finalProps,
|
||||
wrapperProps,
|
||||
...subContentState.snippetProps,
|
||||
})}
|
||||
{:else}
|
||||
<div {...wrapperProps}>
|
||||
<div {...finalProps}>
|
||||
{@render children?.()}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{/snippet}
|
||||
</PopperLayer>
|
||||
{/if}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import type { MenuSubContentProps } from "../types.js";
|
||||
declare const MenuSubContent: import("svelte").Component<MenuSubContentProps, {}, "ref">;
|
||||
type MenuSubContent = ReturnType<typeof MenuSubContent>;
|
||||
export default MenuSubContent;
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
<script lang="ts">
|
||||
import { boxWith, mergeProps } from "svelte-toolbelt";
|
||||
import type { MenuSubTriggerProps } from "../types.js";
|
||||
import { MenuSubTriggerState } from "../menu.svelte.js";
|
||||
import FloatingLayerAnchor from "../../utilities/floating-layer/components/floating-layer-anchor.svelte";
|
||||
import { noop } from "../../../internal/noop.js";
|
||||
import { createId } from "../../../internal/create-id.js";
|
||||
|
||||
const uid = $props.id();
|
||||
|
||||
let {
|
||||
id = createId(uid),
|
||||
disabled = false,
|
||||
ref = $bindable(null),
|
||||
children,
|
||||
child,
|
||||
onSelect = noop,
|
||||
openDelay = 100,
|
||||
...restProps
|
||||
}: MenuSubTriggerProps = $props();
|
||||
|
||||
const subTriggerState = MenuSubTriggerState.create({
|
||||
disabled: boxWith(() => disabled),
|
||||
onSelect: boxWith(() => onSelect),
|
||||
id: boxWith(() => id),
|
||||
ref: boxWith(
|
||||
() => ref,
|
||||
(v) => (ref = v)
|
||||
),
|
||||
openDelay: boxWith(() => openDelay),
|
||||
});
|
||||
|
||||
const mergedProps = $derived(mergeProps(restProps, subTriggerState.props));
|
||||
</script>
|
||||
|
||||
<FloatingLayerAnchor {id} ref={subTriggerState.opts.ref}>
|
||||
{#if child}
|
||||
{@render child({ props: mergedProps })}
|
||||
{:else}
|
||||
<div {...mergedProps}>
|
||||
{@render children?.()}
|
||||
</div>
|
||||
{/if}
|
||||
</FloatingLayerAnchor>
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import type { MenuSubTriggerProps } from "../types.js";
|
||||
declare const MenuSubTrigger: import("svelte").Component<MenuSubTriggerProps, {}, "ref">;
|
||||
type MenuSubTrigger = ReturnType<typeof MenuSubTrigger>;
|
||||
export default MenuSubTrigger;
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
<script lang="ts">
|
||||
import { boxWith } from "svelte-toolbelt";
|
||||
import type { MenuSubProps } from "../types.js";
|
||||
import { MenuSubmenuState } from "../menu.svelte.js";
|
||||
import FloatingLayer from "../../utilities/floating-layer/components/floating-layer.svelte";
|
||||
import { noop } from "../../../internal/noop.js";
|
||||
|
||||
let {
|
||||
open = $bindable(false),
|
||||
onOpenChange = noop,
|
||||
onOpenChangeComplete = noop,
|
||||
children,
|
||||
}: MenuSubProps = $props();
|
||||
|
||||
MenuSubmenuState.create({
|
||||
open: boxWith(
|
||||
() => open,
|
||||
(v) => {
|
||||
open = v;
|
||||
onOpenChange?.(v);
|
||||
}
|
||||
),
|
||||
onOpenChangeComplete: boxWith(() => onOpenChangeComplete),
|
||||
});
|
||||
</script>
|
||||
|
||||
<FloatingLayer>
|
||||
{@render children?.()}
|
||||
</FloatingLayer>
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
declare const MenuSub: import("svelte").Component<import("../types.js").MenuSubPropsWithoutHTML, {}, "open">;
|
||||
type MenuSub = ReturnType<typeof MenuSub>;
|
||||
export default MenuSub;
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
<script lang="ts">
|
||||
import { boxWith, mergeProps } from "svelte-toolbelt";
|
||||
import type { MenuTriggerProps } from "../types.js";
|
||||
import { DropdownMenuTriggerState } from "../menu.svelte.js";
|
||||
import { createId } from "../../../internal/create-id.js";
|
||||
import FloatingLayerAnchor from "../../utilities/floating-layer/components/floating-layer-anchor.svelte";
|
||||
|
||||
const uid = $props.id();
|
||||
|
||||
let {
|
||||
id = createId(uid),
|
||||
ref = $bindable(null),
|
||||
child,
|
||||
children,
|
||||
disabled = false,
|
||||
type = "button",
|
||||
...restProps
|
||||
}: MenuTriggerProps = $props();
|
||||
|
||||
const triggerState = DropdownMenuTriggerState.create({
|
||||
id: boxWith(() => id),
|
||||
disabled: boxWith(() => disabled ?? false),
|
||||
ref: boxWith(
|
||||
() => ref,
|
||||
(v) => (ref = v)
|
||||
),
|
||||
});
|
||||
|
||||
const mergedProps = $derived(mergeProps(restProps, triggerState.props, { type }));
|
||||
</script>
|
||||
|
||||
<FloatingLayerAnchor {id} ref={triggerState.opts.ref}>
|
||||
{#if child}
|
||||
{@render child({ props: mergedProps })}
|
||||
{:else}
|
||||
<button {...mergedProps}>
|
||||
{@render children?.()}
|
||||
</button>
|
||||
{/if}
|
||||
</FloatingLayerAnchor>
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import type { MenuTriggerProps } from "../types.js";
|
||||
declare const MenuTrigger: import("svelte").Component<MenuTriggerProps, {}, "ref">;
|
||||
type MenuTrigger = ReturnType<typeof MenuTrigger>;
|
||||
export default MenuTrigger;
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
<script lang="ts">
|
||||
import { boxWith } from "svelte-toolbelt";
|
||||
import type { MenuRootProps } from "../types.js";
|
||||
import { MenuMenuState, MenuRootState } from "../menu.svelte.js";
|
||||
import { noop } from "../../../internal/noop.js";
|
||||
import FloatingLayer from "../../utilities/floating-layer/components/floating-layer.svelte";
|
||||
|
||||
let {
|
||||
open = $bindable(false),
|
||||
dir = "ltr",
|
||||
onOpenChange = noop,
|
||||
onOpenChangeComplete = noop,
|
||||
_internal_variant: variant = "dropdown-menu",
|
||||
children,
|
||||
}: MenuRootProps & {
|
||||
_internal_variant?: "context-menu" | "dropdown-menu" | "menubar";
|
||||
} = $props();
|
||||
|
||||
const root = MenuRootState.create({
|
||||
variant: boxWith(() => variant),
|
||||
dir: boxWith(() => dir),
|
||||
onClose: () => {
|
||||
open = false;
|
||||
onOpenChange(false);
|
||||
},
|
||||
});
|
||||
|
||||
MenuMenuState.create(
|
||||
{
|
||||
open: boxWith(
|
||||
() => open,
|
||||
(v) => {
|
||||
open = v;
|
||||
onOpenChange(v);
|
||||
}
|
||||
),
|
||||
onOpenChangeComplete: boxWith(() => onOpenChangeComplete),
|
||||
},
|
||||
root
|
||||
);
|
||||
</script>
|
||||
|
||||
<FloatingLayer>
|
||||
{@render children?.()}
|
||||
</FloatingLayer>
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
import type { MenuRootProps } from "../types.js";
|
||||
type $$ComponentProps = MenuRootProps & {
|
||||
_internal_variant?: "context-menu" | "dropdown-menu" | "menubar";
|
||||
};
|
||||
declare const Menu: import("svelte").Component<$$ComponentProps, {}, "open">;
|
||||
type Menu = ReturnType<typeof Menu>;
|
||||
export default Menu;
|
||||
Reference in New Issue
Block a user