mirror of
https://github.com/carbon-design-system/carbon-components-svelte.git
synced 2025-09-15 18:31:06 +00:00
Support custom target(s) for ContextMenu
(#916)
* feat(context-menu): add target prop to selectively trigger context menu * feat(context-menu): include clicked element in "open" event detail * docs(context-menu): add target, multiple target examples
This commit is contained in:
parent
d8f8ac2b73
commit
ccc733f3f7
8 changed files with 261 additions and 52 deletions
|
@ -1,4 +1,15 @@
|
|||
<script>
|
||||
/**
|
||||
* @event {HTMLElement} open
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @type {null | HTMLElement | HTMLElement[]}
|
||||
*/
|
||||
export let target = null;
|
||||
|
||||
/**
|
||||
* Set to `true` to open the menu
|
||||
* Either `x` and `y` must be greater than zero
|
||||
|
@ -15,6 +26,7 @@
|
|||
export let ref = null;
|
||||
|
||||
import {
|
||||
onMount,
|
||||
setContext,
|
||||
getContext,
|
||||
afterUpdate,
|
||||
|
@ -34,6 +46,7 @@
|
|||
let prevX = 0;
|
||||
let prevY = 0;
|
||||
let focusIndex = -1;
|
||||
let openDetail = null;
|
||||
|
||||
function close() {
|
||||
open = false;
|
||||
|
@ -44,43 +57,8 @@
|
|||
focusIndex = -1;
|
||||
}
|
||||
|
||||
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");
|
||||
} else {
|
||||
dispatch("close");
|
||||
}
|
||||
|
||||
if (!$hasPopup && options[focusIndex]) options[focusIndex].focus();
|
||||
});
|
||||
|
||||
$: level = !ctx ? 1 : 2;
|
||||
$: currentIndex.set(focusIndex);
|
||||
</script>
|
||||
|
||||
<svelte:window
|
||||
on:contextmenu|preventDefault="{(e) => {
|
||||
if (level > 1) return;
|
||||
if (!ref) return;
|
||||
|
||||
/** @type {(e: MouseEvent) => void} */
|
||||
function openMenu(e) {
|
||||
const { height, width } = ref.getBoundingClientRect();
|
||||
|
||||
if (open || x === 0) {
|
||||
|
@ -102,6 +80,69 @@
|
|||
}
|
||||
position.set([x, y]);
|
||||
open = true;
|
||||
openDetail = e.target;
|
||||
}
|
||||
|
||||
$: if (target != null) {
|
||||
if (Array.isArray(target)) {
|
||||
target.forEach((node) => node?.addEventListener("contextmenu", openMenu));
|
||||
} else {
|
||||
target.addEventListener("contextmenu", openMenu);
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
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);
|
||||
</script>
|
||||
|
||||
<svelte:window
|
||||
on:contextmenu|preventDefault="{(e) => {
|
||||
if (target != null) return;
|
||||
if (level > 1) return;
|
||||
if (!ref) return;
|
||||
openMenu(e);
|
||||
}}"
|
||||
on:click="{(e) => {
|
||||
if (!open) return;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue