diff --git a/COMPONENT_INDEX.md b/COMPONENT_INDEX.md index 6e435199..04383f3c 100644 --- a/COMPONENT_INDEX.md +++ b/COMPONENT_INDEX.md @@ -780,12 +780,13 @@ None. ### Props -| Prop name | Kind | Reactive | Type | Default value | Description | -| :-------- | :--------------- | :------- | :---------------------------------------- | ------------------ | -------------------------------------------------------------------------------- | -| ref | let | Yes | null | HTMLUListElement | null | Obtain a reference to the unordered list HTML element | -| y | let | Yes | number | 0 | Specify the vertical offset of the menu position | -| x | let | Yes | number | 0 | Specify the horizontal offset of the menu position | -| open | let | Yes | boolean | false | Set to `true` to open the menu
Either `x` and `y` must be greater than zero | +| Prop name | Kind | Reactive | Type | Default value | Description | +| :-------- | :--------------- | :------- | :-------------------------------------------------------- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------- | +| ref | let | Yes | null | HTMLUListElement | null | Obtain a reference to the unordered list HTML element | +| y | let | Yes | number | 0 | Specify the vertical offset of the menu position | +| x | let | Yes | number | 0 | Specify the horizontal offset of the menu position | +| open | let | Yes | boolean | false | Set to `true` to open the menu
Either `x` and `y` must be greater than zero | +| target | let | No | null | HTMLElement | HTMLElement[] | null | Specify an element or list of elements to trigger the context menu.
If no element is specified, the context menu applies to the entire window | ### Slots @@ -795,12 +796,12 @@ None. ### Events -| Event name | Type | Detail | -| :--------- | :--------- | :----- | -| click | forwarded | -- | -| keydown | forwarded | -- | -| open | dispatched | -- | -| close | dispatched | -- | +| Event name | Type | Detail | +| :--------- | :--------- | :----------------------- | +| open | dispatched | HTMLElement | +| click | forwarded | -- | +| keydown | forwarded | -- | +| close | dispatched | -- | ## `ContextMenuDivider` diff --git a/docs/src/COMPONENT_API.json b/docs/src/COMPONENT_API.json index 41a03e33..7bc1b87a 100644 --- a/docs/src/COMPONENT_API.json +++ b/docs/src/COMPONENT_API.json @@ -1809,6 +1809,17 @@ "moduleName": "ContextMenu", "filePath": "src/ContextMenu/ContextMenu.svelte", "props": [ + { + "name": "target", + "kind": "let", + "description": "Specify an element or list of elements to trigger the context menu.\nIf no element is specified, the context menu applies to the entire window", + "type": "null | HTMLElement | HTMLElement[]", + "value": "null", + "isFunction": false, + "isFunctionDeclaration": false, + "constant": false, + "reactive": false + }, { "name": "open", "kind": "let", @@ -1856,9 +1867,9 @@ ], "slots": [{ "name": "__default__", "default": true, "slot_props": "{}" }], "events": [ + { "type": "dispatched", "name": "open", "detail": "HTMLElement" }, { "type": "forwarded", "name": "click", "element": "ul" }, { "type": "forwarded", "name": "keydown", "element": "ul" }, - { "type": "dispatched", "name": "open" }, { "type": "dispatched", "name": "close" } ], "typedefs": [], diff --git a/docs/src/pages/components/ContextMenu.svx b/docs/src/pages/components/ContextMenu.svx index d195fd63..a37e7a32 100644 --- a/docs/src/pages/components/ContextMenu.svx +++ b/docs/src/pages/components/ContextMenu.svx @@ -9,9 +9,23 @@ components: ["ContextMenu", "ContextMenuGroup", "ContextMenuRadioGroup", "Contex In the examples, right click anywhere within the iframe. ### Default + +By default, the context menu will trigger when right clicking anywhere in the `window`. +### Custom target + +Specify a custom `HTMLElement` using the `target` prop. + + + +### Multiple targets + +The `target` prop also accepts an array of elements. + + + ### Radio groups \ No newline at end of file diff --git a/docs/src/pages/framed/ContextMenu/ContextMenuTarget.svelte b/docs/src/pages/framed/ContextMenu/ContextMenuTarget.svelte new file mode 100644 index 00000000..87b4d8a6 --- /dev/null +++ b/docs/src/pages/framed/ContextMenu/ContextMenuTarget.svelte @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Right click this element

+
+ + diff --git a/docs/src/pages/framed/ContextMenu/ContextMenuTargets.svelte b/docs/src/pages/framed/ContextMenu/ContextMenuTargets.svelte new file mode 100644 index 00000000..aa51e7de --- /dev/null +++ b/docs/src/pages/framed/ContextMenu/ContextMenuTargets.svelte @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Right click this element

+

... or this one

+
+ + diff --git a/src/ContextMenu/ContextMenu.svelte b/src/ContextMenu/ContextMenu.svelte index b6bc144a..c1490844 100644 --- a/src/ContextMenu/ContextMenu.svelte +++ b/src/ContextMenu/ContextMenu.svelte @@ -1,4 +1,15 @@ - - { + return () => { + if (target != null) { + if (Array.isArray(target)) { + target.forEach((node) => + node?.removeEventListener("contextmenu", openMenu) + ); + } else { + target.removeEventListener("contextmenu", openMenu); + } + } + }; + }); + + setContext("ContextMenu", { + menuOffsetX, + currentIndex, + position, + close, + setPopup: (popup) => { + hasPopup.set(popup); + }, + }); + + afterUpdate(() => { + if (open) { + options = [...ref.querySelectorAll("li[data-nested='false']")]; + + if (level === 1) { + if (prevX !== x || prevY !== y) ref.focus(); + prevX = x; + prevY = y; + } + + dispatch("open", openDetail); + } else { + dispatch("close"); + } + + if (!$hasPopup && options[focusIndex]) options[focusIndex].focus(); + }); + + $: level = !ctx ? 1 : 2; + $: currentIndex.set(focusIndex); + + + - + { + /** + * Specify an element or list of elements to trigger the context menu. + * If no element is specified, the context menu applies to the entire window + * @default null + */ + target?: null | HTMLElement | HTMLElement[]; + /** * Set to `true` to open the menu * Either `x` and `y` must be greater than zero @@ -32,9 +39,9 @@ export interface ContextMenuProps export default class ContextMenu extends SvelteComponentTyped< ContextMenuProps, { + open: CustomEvent; click: WindowEventMap["click"]; keydown: WindowEventMap["keydown"]; - open: CustomEvent; close: CustomEvent; }, { default: {} }