mirror of
https://github.com/carbon-design-system/carbon-components-svelte.git
synced 2025-09-20 20:33:02 +00:00
feat(context-menu): add target prop to selectively trigger context menu
This commit is contained in:
parent
d8f8ac2b73
commit
f603106b18
4 changed files with 82 additions and 28 deletions
|
@ -780,12 +780,13 @@ None.
|
||||||
|
|
||||||
### Props
|
### Props
|
||||||
|
|
||||||
| Prop name | Kind | Reactive | Type | Default value | Description |
|
| Prop name | Kind | Reactive | Type | Default value | Description |
|
||||||
| :-------- | :--------------- | :------- | :---------------------------------------- | ------------------ | -------------------------------------------------------------------------------- |
|
| :-------- | :--------------- | :------- | :-------------------------------------------------------- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| ref | <code>let</code> | Yes | <code>null | HTMLUListElement</code> | <code>null</code> | Obtain a reference to the unordered list HTML element |
|
| ref | <code>let</code> | Yes | <code>null | HTMLUListElement</code> | <code>null</code> | Obtain a reference to the unordered list HTML element |
|
||||||
| y | <code>let</code> | Yes | <code>number</code> | <code>0</code> | Specify the vertical offset of the menu position |
|
| y | <code>let</code> | Yes | <code>number</code> | <code>0</code> | Specify the vertical offset of the menu position |
|
||||||
| x | <code>let</code> | Yes | <code>number</code> | <code>0</code> | Specify the horizontal offset of the menu position |
|
| x | <code>let</code> | Yes | <code>number</code> | <code>0</code> | Specify the horizontal offset of the menu position |
|
||||||
| open | <code>let</code> | Yes | <code>boolean</code> | <code>false</code> | Set to `true` to open the menu<br />Either `x` and `y` must be greater than zero |
|
| open | <code>let</code> | Yes | <code>boolean</code> | <code>false</code> | Set to `true` to open the menu<br />Either `x` and `y` must be greater than zero |
|
||||||
|
| target | <code>let</code> | No | <code>null | HTMLElement | HTMLElement[]</code> | <code>null</code> | Specify an element or list of elements to trigger the context menu.<br />If no element is specified, the context menu applies to the entire window |
|
||||||
|
|
||||||
### Slots
|
### Slots
|
||||||
|
|
||||||
|
|
|
@ -1809,6 +1809,17 @@
|
||||||
"moduleName": "ContextMenu",
|
"moduleName": "ContextMenu",
|
||||||
"filePath": "src/ContextMenu/ContextMenu.svelte",
|
"filePath": "src/ContextMenu/ContextMenu.svelte",
|
||||||
"props": [
|
"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",
|
"name": "open",
|
||||||
"kind": "let",
|
"kind": "let",
|
||||||
|
|
|
@ -1,4 +1,11 @@
|
||||||
<script>
|
<script>
|
||||||
|
/**
|
||||||
|
* 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
|
* Set to `true` to open the menu
|
||||||
* Either `x` and `y` must be greater than zero
|
* Either `x` and `y` must be greater than zero
|
||||||
|
@ -15,6 +22,7 @@
|
||||||
export let ref = null;
|
export let ref = null;
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
onMount,
|
||||||
setContext,
|
setContext,
|
||||||
getContext,
|
getContext,
|
||||||
afterUpdate,
|
afterUpdate,
|
||||||
|
@ -44,6 +52,53 @@
|
||||||
focusIndex = -1;
|
focusIndex = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @type {(e: MouseEvent) => void} */
|
||||||
|
function openMenu(e) {
|
||||||
|
const { height, width } = ref.getBoundingClientRect();
|
||||||
|
|
||||||
|
if (open || x === 0) {
|
||||||
|
if (window.innerWidth - width < e.x) {
|
||||||
|
x = e.x - width;
|
||||||
|
} else {
|
||||||
|
x = e.x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (open || y === 0) {
|
||||||
|
menuOffsetX.set(e.x);
|
||||||
|
|
||||||
|
if (window.innerHeight - height < e.y) {
|
||||||
|
y = e.y - height;
|
||||||
|
} else {
|
||||||
|
y = e.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
position.set([x, y]);
|
||||||
|
open = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$: 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", {
|
setContext("ContextMenu", {
|
||||||
menuOffsetX,
|
menuOffsetX,
|
||||||
currentIndex,
|
currentIndex,
|
||||||
|
@ -78,30 +133,10 @@
|
||||||
|
|
||||||
<svelte:window
|
<svelte:window
|
||||||
on:contextmenu|preventDefault="{(e) => {
|
on:contextmenu|preventDefault="{(e) => {
|
||||||
|
if (target != null) return;
|
||||||
if (level > 1) return;
|
if (level > 1) return;
|
||||||
if (!ref) return;
|
if (!ref) return;
|
||||||
|
openMenu(e);
|
||||||
const { height, width } = ref.getBoundingClientRect();
|
|
||||||
|
|
||||||
if (open || x === 0) {
|
|
||||||
if (window.innerWidth - width < e.x) {
|
|
||||||
x = e.x - width;
|
|
||||||
} else {
|
|
||||||
x = e.x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (open || y === 0) {
|
|
||||||
menuOffsetX.set(e.x);
|
|
||||||
|
|
||||||
if (window.innerHeight - height < e.y) {
|
|
||||||
y = e.y - height;
|
|
||||||
} else {
|
|
||||||
y = e.y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
position.set([x, y]);
|
|
||||||
open = true;
|
|
||||||
}}"
|
}}"
|
||||||
on:click="{(e) => {
|
on:click="{(e) => {
|
||||||
if (!open) return;
|
if (!open) return;
|
||||||
|
|
7
types/ContextMenu/ContextMenu.svelte.d.ts
vendored
7
types/ContextMenu/ContextMenu.svelte.d.ts
vendored
|
@ -3,6 +3,13 @@ import { SvelteComponentTyped } from "svelte";
|
||||||
|
|
||||||
export interface ContextMenuProps
|
export interface ContextMenuProps
|
||||||
extends svelte.JSX.HTMLAttributes<HTMLElementTagNameMap["ul"]> {
|
extends svelte.JSX.HTMLAttributes<HTMLElementTagNameMap["ul"]> {
|
||||||
|
/**
|
||||||
|
* 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
|
* Set to `true` to open the menu
|
||||||
* Either `x` and `y` must be greater than zero
|
* Either `x` and `y` must be greater than zero
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue