INIT
This commit is contained in:
Generated
Vendored
+135
@@ -0,0 +1,135 @@
|
||||
<script lang="ts">
|
||||
import { boxWith, mergeProps } from "svelte-toolbelt";
|
||||
import type { ContextMenuContentStaticProps } from "../types.js";
|
||||
import { CONTEXT_MENU_TRIGGER_ATTR, MenuContentState } from "../../menu/menu.svelte.js";
|
||||
import { useId } from "../../../internal/use-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";
|
||||
|
||||
let {
|
||||
id = useId(),
|
||||
child,
|
||||
children,
|
||||
ref = $bindable(null),
|
||||
loop = true,
|
||||
onInteractOutside = noop,
|
||||
onCloseAutoFocus = noop,
|
||||
preventScroll = true,
|
||||
// we need to explicitly pass this prop to the PopperLayer to override
|
||||
// the default menu behavior of handling outside interactions on the trigger
|
||||
onEscapeKeydown = noop,
|
||||
forceMount = false,
|
||||
style,
|
||||
...restProps
|
||||
}: ContextMenuContentStaticProps = $props();
|
||||
|
||||
const contentState = MenuContentState.create({
|
||||
id: boxWith(() => id),
|
||||
loop: boxWith(() => loop),
|
||||
ref: boxWith(
|
||||
() => ref,
|
||||
(v) => (ref = v)
|
||||
),
|
||||
onCloseAutoFocus: boxWith(() => onCloseAutoFocus),
|
||||
});
|
||||
|
||||
const mergedProps = $derived(mergeProps(restProps, contentState.props));
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
function isValidEvent(e: PointerEvent) {
|
||||
if ("button" in e && e.button === 2) {
|
||||
const target = e.target as HTMLElement;
|
||||
if (!target) return false;
|
||||
const isAnotherContextTrigger =
|
||||
target.closest(`[${CONTEXT_MENU_TRIGGER_ATTR}]`) !==
|
||||
contentState.parentMenu.triggerNode;
|
||||
return isAnotherContextTrigger;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if forceMount}
|
||||
<PopperLayerForceMount
|
||||
{...mergedProps}
|
||||
{...contentState.popperProps}
|
||||
ref={contentState.opts.ref}
|
||||
isStatic
|
||||
side="right"
|
||||
sideOffset={2}
|
||||
align="start"
|
||||
enabled={contentState.parentMenu.opts.open.current}
|
||||
{preventScroll}
|
||||
onInteractOutside={handleInteractOutside}
|
||||
onEscapeKeydown={handleEscapeKeydown}
|
||||
{isValidEvent}
|
||||
trapFocus
|
||||
{loop}
|
||||
{forceMount}
|
||||
{id}
|
||||
shouldRender={contentState.shouldRender}
|
||||
>
|
||||
{#snippet popper({ props })}
|
||||
{@const finalProps = mergeProps(
|
||||
props,
|
||||
{ style: getFloatingContentCSSVars("context-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}
|
||||
isStatic
|
||||
side="right"
|
||||
sideOffset={2}
|
||||
align="start"
|
||||
open={contentState.parentMenu.opts.open.current}
|
||||
{preventScroll}
|
||||
onInteractOutside={handleInteractOutside}
|
||||
onEscapeKeydown={handleEscapeKeydown}
|
||||
{isValidEvent}
|
||||
trapFocus
|
||||
{loop}
|
||||
forceMount={false}
|
||||
{id}
|
||||
shouldRender={contentState.shouldRender}
|
||||
>
|
||||
{#snippet popper({ props })}
|
||||
{@const finalProps = mergeProps(
|
||||
props,
|
||||
{ style: getFloatingContentCSSVars("context-menu") },
|
||||
{ style }
|
||||
)}
|
||||
{#if child}
|
||||
{@render child({ props: finalProps, ...contentState.snippetProps })}
|
||||
{:else}
|
||||
<div {...finalProps}>
|
||||
{@render children?.()}
|
||||
</div>
|
||||
{/if}
|
||||
{/snippet}
|
||||
</PopperLayer>
|
||||
{/if}
|
||||
Generated
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
import type { ContextMenuContentStaticProps } from "../types.js";
|
||||
declare const ContextMenuContentStatic: import("svelte").Component<ContextMenuContentStaticProps, {}, "ref">;
|
||||
type ContextMenuContentStatic = ReturnType<typeof ContextMenuContentStatic>;
|
||||
export default ContextMenuContentStatic;
|
||||
Generated
Vendored
+138
@@ -0,0 +1,138 @@
|
||||
<script lang="ts">
|
||||
import { boxWith, mergeProps } from "svelte-toolbelt";
|
||||
import type { ContextMenuContentProps } from "../types.js";
|
||||
import { CONTEXT_MENU_TRIGGER_ATTR, MenuContentState } from "../../menu/menu.svelte.js";
|
||||
import { useId } from "../../../internal/use-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";
|
||||
|
||||
let {
|
||||
id = useId(),
|
||||
child,
|
||||
children,
|
||||
ref = $bindable(null),
|
||||
loop = true,
|
||||
onInteractOutside = noop,
|
||||
onCloseAutoFocus = noop,
|
||||
onOpenAutoFocus = noop,
|
||||
preventScroll = true,
|
||||
side = "right",
|
||||
sideOffset = 2,
|
||||
align = "start",
|
||||
// we need to explicitly pass this prop to the PopperLayer to override
|
||||
// the default menu behavior of handling outside interactions on the trigger
|
||||
onEscapeKeydown = noop,
|
||||
forceMount = false,
|
||||
trapFocus = false,
|
||||
style,
|
||||
...restProps
|
||||
}: ContextMenuContentProps = $props();
|
||||
|
||||
const contentState = MenuContentState.create({
|
||||
id: boxWith(() => id),
|
||||
loop: boxWith(() => loop),
|
||||
ref: boxWith(
|
||||
() => ref,
|
||||
(v) => (ref = v)
|
||||
),
|
||||
onCloseAutoFocus: boxWith(() => onCloseAutoFocus),
|
||||
});
|
||||
|
||||
const mergedProps = $derived(
|
||||
mergeProps(restProps, contentState.props, {
|
||||
side,
|
||||
sideOffset,
|
||||
align,
|
||||
onOpenAutoFocus,
|
||||
isValidEvent,
|
||||
trapFocus,
|
||||
loop,
|
||||
id,
|
||||
ref: contentState.opts.ref,
|
||||
preventScroll,
|
||||
onInteractOutside: handleInteractOutside,
|
||||
onEscapeKeydown: handleEscapeKeydown,
|
||||
shouldRender: contentState.shouldRender,
|
||||
})
|
||||
);
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
function isValidEvent(e: PointerEvent) {
|
||||
if ("button" in e && e.button === 2) {
|
||||
const target = e.target as HTMLElement;
|
||||
if (!target) return false;
|
||||
const isAnotherContextTrigger =
|
||||
target.closest(`[${CONTEXT_MENU_TRIGGER_ATTR}]`) !==
|
||||
contentState.parentMenu.triggerNode;
|
||||
return isAnotherContextTrigger;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if forceMount}
|
||||
<PopperLayerForceMount
|
||||
{...mergedProps}
|
||||
{...contentState.popperProps}
|
||||
enabled={contentState.parentMenu.opts.open.current}
|
||||
>
|
||||
{#snippet popper({ props, wrapperProps })}
|
||||
{@const finalProps = mergeProps(
|
||||
props,
|
||||
{ style: getFloatingContentCSSVars("context-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}
|
||||
open={contentState.parentMenu.opts.open.current}
|
||||
>
|
||||
{#snippet popper({ props, wrapperProps })}
|
||||
{@const finalProps = mergeProps(
|
||||
props,
|
||||
{ style: getFloatingContentCSSVars("context-menu") },
|
||||
{ style }
|
||||
)}
|
||||
{#if child}
|
||||
{@render child({ props: finalProps, wrapperProps, ...contentState.snippetProps })}
|
||||
{:else}
|
||||
<div {...wrapperProps}>
|
||||
<div {...finalProps}>
|
||||
{@render children?.()}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{/snippet}
|
||||
</PopperLayer>
|
||||
{/if}
|
||||
Generated
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
declare const ContextMenuContent: import("svelte").Component<import("../../menu/types.js").MenuContentProps, {}, "ref">;
|
||||
type ContextMenuContent = ReturnType<typeof ContextMenuContent>;
|
||||
export default ContextMenuContent;
|
||||
Generated
Vendored
+47
@@ -0,0 +1,47 @@
|
||||
<script lang="ts">
|
||||
import { boxWith, mergeProps } from "svelte-toolbelt";
|
||||
import type { ContextMenuTriggerProps } from "../types.js";
|
||||
import { ContextMenuTriggerState } from "../../menu/menu.svelte.js";
|
||||
import { useId } from "../../../internal/use-id.js";
|
||||
import { FloatingLayer } from "../../utilities/floating-layer/index.js";
|
||||
|
||||
let {
|
||||
id = useId(),
|
||||
ref = $bindable(null),
|
||||
child,
|
||||
children,
|
||||
disabled = false,
|
||||
...restProps
|
||||
}: ContextMenuTriggerProps = $props();
|
||||
|
||||
const triggerState = ContextMenuTriggerState.create({
|
||||
id: boxWith(() => id),
|
||||
disabled: boxWith(() => disabled),
|
||||
ref: boxWith(
|
||||
() => ref,
|
||||
(v) => (ref = v)
|
||||
),
|
||||
});
|
||||
|
||||
const mergedProps = $derived(
|
||||
mergeProps(
|
||||
restProps,
|
||||
triggerState.props,
|
||||
{ style: { pointerEvents: "auto" } },
|
||||
{
|
||||
style: restProps.style,
|
||||
tabindex: restProps.tabindex,
|
||||
}
|
||||
)
|
||||
);
|
||||
</script>
|
||||
|
||||
<FloatingLayer.Anchor {id} virtualEl={triggerState.virtualElement} ref={triggerState.opts.ref}>
|
||||
{#if child}
|
||||
{@render child({ props: mergedProps })}
|
||||
{:else}
|
||||
<div {...mergedProps}>
|
||||
{@render children?.()}
|
||||
</div>
|
||||
{/if}
|
||||
</FloatingLayer.Anchor>
|
||||
Generated
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
import type { ContextMenuTriggerProps } from "../types.js";
|
||||
declare const ContextMenuTrigger: import("svelte").Component<ContextMenuTriggerProps, {}, "ref">;
|
||||
type ContextMenuTrigger = ReturnType<typeof ContextMenuTrigger>;
|
||||
export default ContextMenuTrigger;
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
<script lang="ts">
|
||||
import { boxWith } from "svelte-toolbelt";
|
||||
import type { ContextMenuRootProps } from "../types.js";
|
||||
import FloatingLayer from "../../utilities/floating-layer/components/floating-layer.svelte";
|
||||
import { noop } from "../../../internal/noop.js";
|
||||
import { MenuMenuState, MenuRootState } from "../../menu/menu.svelte.js";
|
||||
|
||||
let {
|
||||
open = $bindable(false),
|
||||
dir = "ltr",
|
||||
onOpenChange = noop,
|
||||
onOpenChangeComplete = noop,
|
||||
children,
|
||||
}: ContextMenuRootProps = $props();
|
||||
|
||||
const root = MenuRootState.create({
|
||||
variant: boxWith(() => "context-menu"),
|
||||
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>
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
declare const ContextMenu: import("svelte").Component<import("../types.js").ContextMenuRootPropsWithoutHTML, {}, "open">;
|
||||
type ContextMenu = ReturnType<typeof ContextMenu>;
|
||||
export default ContextMenu;
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
export { default as Root } from "./components/context-menu.svelte";
|
||||
export { default as Sub } from "../menu/components/menu-sub.svelte";
|
||||
export { default as Item } from "../menu/components/menu-item.svelte";
|
||||
export { default as Group } from "../menu/components/menu-group.svelte";
|
||||
export { default as GroupHeading } from "../menu/components/menu-group-heading.svelte";
|
||||
export { default as Arrow } from "../menu/components/menu-arrow.svelte";
|
||||
export { default as Content } from "./components/context-menu-content.svelte";
|
||||
export { default as ContentStatic } from "./components/context-menu-content-static.svelte";
|
||||
export { default as Trigger } from "./components/context-menu-trigger.svelte";
|
||||
export { default as RadioItem } from "../menu/components/menu-radio-item.svelte";
|
||||
export { default as Separator } from "../menu/components/menu-separator.svelte";
|
||||
export { default as RadioGroup } from "../menu/components/menu-radio-group.svelte";
|
||||
export { default as SubContent } from "../menu/components/menu-sub-content.svelte";
|
||||
export { default as SubContentStatic } from "../menu/components/menu-sub-content-static.svelte";
|
||||
export { default as SubTrigger } from "../menu/components/menu-sub-trigger.svelte";
|
||||
export { default as CheckboxItem } from "../menu/components/menu-checkbox-item.svelte";
|
||||
export { default as Portal } from "../utilities/portal/portal.svelte";
|
||||
export { default as CheckboxGroup } from "../menu/components/menu-checkbox-group.svelte";
|
||||
export type { ContextMenuArrowProps as ArrowProps, ContextMenuCheckboxItemProps as CheckboxItemProps, ContextMenuGroupProps as GroupProps, ContextMenuItemProps as ItemProps, ContextMenuGroupHeadingProps as GroupHeadingProps, ContextMenuRootProps as RootProps, ContextMenuRadioGroupProps as RadioGroupProps, ContextMenuRadioItemProps as RadioItemProps, ContextMenuSeparatorProps as SeparatorProps, ContextMenuSubContentProps as SubContentProps, ContextMenuSubContentStaticProps as SubContentStaticProps, ContextMenuSubProps as SubProps, ContextMenuSubTriggerProps as SubTriggerProps, ContextMenuContentProps as ContentProps, ContextMenuContentStaticProps as ContentStaticProps, ContextMenuTriggerProps as TriggerProps, ContextMenuPortalProps as PortalProps, ContextMenuCheckboxGroupProps as CheckboxGroupProps, } from "./types.js";
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
export { default as Root } from "./components/context-menu.svelte";
|
||||
export { default as Sub } from "../menu/components/menu-sub.svelte";
|
||||
export { default as Item } from "../menu/components/menu-item.svelte";
|
||||
export { default as Group } from "../menu/components/menu-group.svelte";
|
||||
export { default as GroupHeading } from "../menu/components/menu-group-heading.svelte";
|
||||
export { default as Arrow } from "../menu/components/menu-arrow.svelte";
|
||||
export { default as Content } from "./components/context-menu-content.svelte";
|
||||
export { default as ContentStatic } from "./components/context-menu-content-static.svelte";
|
||||
export { default as Trigger } from "./components/context-menu-trigger.svelte";
|
||||
export { default as RadioItem } from "../menu/components/menu-radio-item.svelte";
|
||||
export { default as Separator } from "../menu/components/menu-separator.svelte";
|
||||
export { default as RadioGroup } from "../menu/components/menu-radio-group.svelte";
|
||||
export { default as SubContent } from "../menu/components/menu-sub-content.svelte";
|
||||
export { default as SubContentStatic } from "../menu/components/menu-sub-content-static.svelte";
|
||||
export { default as SubTrigger } from "../menu/components/menu-sub-trigger.svelte";
|
||||
export { default as CheckboxItem } from "../menu/components/menu-checkbox-item.svelte";
|
||||
export { default as Portal } from "../utilities/portal/portal.svelte";
|
||||
export { default as CheckboxGroup } from "../menu/components/menu-checkbox-group.svelte";
|
||||
+1
@@ -0,0 +1 @@
|
||||
export * as ContextMenu from "./exports.js";
|
||||
+1
@@ -0,0 +1 @@
|
||||
export * as ContextMenu from "./exports.js";
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
import type { MenuContentProps, MenuContentPropsWithoutHTML } from "../menu/types.js";
|
||||
import type { WithChild, Without } from "../../internal/types.js";
|
||||
import type { BitsPrimitiveDivAttributes } from "../../shared/attributes.js";
|
||||
export type ContextMenuContentPropsWithoutHTML = MenuContentPropsWithoutHTML;
|
||||
export type ContextMenuContentProps = MenuContentProps;
|
||||
export type ContextMenuTriggerPropsWithoutHTML = WithChild<{
|
||||
/**
|
||||
* Whether the context menu trigger is disabled. If disabled, the trigger will not
|
||||
* open the menu when right-clicked.
|
||||
*/
|
||||
disabled?: boolean;
|
||||
}>;
|
||||
export type ContextMenuTriggerProps = ContextMenuTriggerPropsWithoutHTML & Without<BitsPrimitiveDivAttributes, ContextMenuTriggerPropsWithoutHTML>;
|
||||
export type { MenuArrowProps as ContextMenuArrowProps, MenuContentStaticProps as ContextMenuContentStaticProps, MenuCheckboxItemProps as ContextMenuCheckboxItemProps, MenuGroupProps as ContextMenuGroupProps, MenuItemProps as ContextMenuItemProps, MenuGroupHeadingProps as ContextMenuGroupHeadingProps, MenuRootProps as ContextMenuRootProps, MenuRadioGroupProps as ContextMenuRadioGroupProps, MenuRadioItemProps as ContextMenuRadioItemProps, MenuSeparatorProps as ContextMenuSeparatorProps, MenuSubContentProps as ContextMenuSubContentProps, MenuSubContentStaticProps as ContextMenuSubContentStaticProps, MenuSubProps as ContextMenuSubProps, MenuSubTriggerProps as ContextMenuSubTriggerProps, MenuPortalProps as ContextMenuPortalProps, MenuCheckboxGroupProps as ContextMenuCheckboxGroupProps, } from "../menu/types.js";
|
||||
export type { MenuRootPropsWithoutHTML as ContextMenuRootPropsWithoutHTML, MenuContentStaticPropsWithoutHTML as ContextMenuContentStaticPropsWithoutHTML, MenuArrowPropsWithoutHTML as ContextMenuArrowPropsWithoutHTML, MenuCheckboxItemPropsWithoutHTML as ContextMenuCheckboxItemPropsWithoutHTML, MenuGroupPropsWithoutHTML as ContextMenuGroupPropsWithoutHTML, MenuItemPropsWithoutHTML as ContextMenuItemPropsWithoutHTML, MenuGroupHeadingPropsWithoutHTML as ContextMenuGroupHeadingPropsWithoutHTML, MenuRadioGroupPropsWithoutHTML as ContextMenuRadioGroupPropsWithoutHTML, MenuRadioItemPropsWithoutHTML as ContextMenuRadioItemPropsWithoutHTML, MenuSeparatorPropsWithoutHTML as ContextMenuSeparatorPropsWithoutHTML, MenuSubPropsWithoutHTML as ContextMenuSubPropsWithoutHTML, MenuSubTriggerPropsWithoutHTML as ContextMenuSubTriggerPropsWithoutHTML, MenuSubContentPropsWithoutHTML as ContextMenuSubContentPropsWithoutHTML, MenuSubContentStaticPropsWithoutHTML as ContextMenuSubContentStaticPropsWithoutHTML, MenuPortalPropsWithoutHTML as ContextMenuPortalPropsWithoutHTML, MenuCheckboxGroupPropsWithoutHTML as ContextMenuCheckboxGroupPropsWithoutHTML, } from "../menu/types.js";
|
||||
+1
@@ -0,0 +1 @@
|
||||
export {};
|
||||
Reference in New Issue
Block a user