Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement #46 #47

Merged
merged 3 commits into from
Sep 4, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -11,6 +11,7 @@
[Menu Definition](#menu-definition)\
[Item Types](#item-types) \
[API](#api) \
[Custom Events](#custom-events) \
[Customize](#customize) \
[Contributing](#contributing)

@@ -88,7 +89,8 @@ var menuDefinition = [

### Heading Item

This is a heading item which displays a `text` and optionally shows a `tooltip` when hovering over it. If you need finer control over the content of the menu item, you can supply your own HTML string by using the `html` property instead of `text`. Alternatively you can also supply an HTMLElement JavaScript Object. For all properties you can supply the value directly or a factory function which will be called just before the menu is opened (i.e. on right click). You can also supply a URL or Data URL to an image used as icon for the menu item. Recommended resolution is 18×18px.
This is a heading item which displays a `text` and optionally shows a `tooltip` when hovering over it. If you need finer control over the content of the menu item, you can supply your own HTML string by using the `html` property instead of `text`. Alternatively you can also supply an HTMLElement JavaScript Object. For all properties you can supply the value directly or a factory function which will be called just before the menu is opened (i.e. on right click). You can also supply a URL or Data URL to an image used as icon for the menu item. Recommended resolution is 18×18px. \
For more information about the `EventRegistry`, see [Custom Events](#custom-events).

```typescript
{
@@ -98,6 +100,7 @@ This is a heading item which displays a `text` and optionally shows a `tooltip`
element?: HTMLElement | () => HTMLElement,
icon?: string | () => string,
style?: string | () => string,
events?: EventRegistry | () => EventRegistry,
}
```

@@ -228,6 +231,32 @@ ctxmenu.hide()
```
Hide any open context menu.

## Custom Events

Every Menu Item has an optional `events` property:
```typescript
{
events?: EventRegistry | () => EventRegistry
}
```

The `EventRegistry` is a map of event handlers. For each event you can either specify the event listener directly, or an object containing the `listener` and an optional `options` ([EventListenerOptions](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#syntax)) object:

```typescript
{
text: "Hover me!",
events: {
mouseenter: (e) => e.target.style.animation = "blinker 1s linear infinite",
mouseleave: {
listener: (e) => e.target.style.animation = "",
options: {
passive: true
}
}
}
}
```

## Customize

ctxmenu.js uses the following css classes which you might want to overwrite:
9 changes: 8 additions & 1 deletion docs/index.html
Original file line number Diff line number Diff line change
@@ -14,7 +14,8 @@
height: 100%;
margin: 0;
}
body{

body {
font-family: "Ubuntu";
font-size: 22px;
padding-top: 65px;
@@ -130,6 +131,12 @@
padding-inline-start: 20px;
}
}

@keyframes blinker {
50% {
opacity: 0;
}
}
</style>
<link rel="shortcut icon" type="image/x-icon" href="favicon.png">
<meta charset="utf8" />
4 changes: 4 additions & 0 deletions src/elementFactory.ts
Original file line number Diff line number Diff line change
@@ -87,4 +87,8 @@ function generateBaseItemContent(item: CTXMHeading, li: HTMLLIElement) {
li.classList.add("icon");
li.innerHTML += `<img class="icon" src="${getProp(item.icon)}" />`;
}
for (const [event, handler] of Object.entries(getProp(item.events) || {})) {
const { listener, options } = typeof handler === "function" ? { listener: handler, options: {} as EventListenerOptions } : handler;
li.addEventListener<any>(event, listener, options);
}
}
11 changes: 11 additions & 0 deletions src/interfaces.ts
Original file line number Diff line number Diff line change
@@ -6,6 +6,15 @@ export interface CTXMDivider {
isDivider: true;
}

export type CTXMItemEventListener<K extends keyof HTMLElementEventMap> = (this: HTMLLIElement, ev: HTMLElementEventMap[K]) => any;

export type CTXMItemEventRegistry = {
[K in keyof HTMLElementEventMap]?: CTXMItemEventListener<K> | {
listener: CTXMItemEventListener<K>,
options?: AddEventListenerOptions
};
}

/**
* This is a heading item which displays a text and optionally shows a tooltip when hovering over it.
*
@@ -24,6 +33,8 @@ export interface CTXMHeading {
icon?: ValueOrFunction<string>;
/** inline attribute appended to the `<li>` Element */
style?: ValueOrFunction<string>;
/** A record of event listeners */
events?: ValueOrFunction<CTXMItemEventRegistry>;
}

export interface CTXMInteractive extends CTXMHeading {
4 changes: 2 additions & 2 deletions src/position.ts
Original file line number Diff line number Diff line change
@@ -19,7 +19,7 @@ export function resetDirections() {
export function setPosition(container: HTMLUListElement, parentOrEvent: HTMLElement | MouseEvent): void {
// restrict menu size to viewport size
const scale = getScale();
const { width, height } = window.visualViewport;
const { width, height } = window.visualViewport!;
Object.assign(container.style, {
maxHeight: (height / scale.y) + "px",
maxWidth: (width / scale.x) + "px",
@@ -74,7 +74,7 @@ export function setPosition(container: HTMLUListElement, parentOrEvent: HTMLElem

/** returns a safe position inside the viewport, given the desired position */
function getPosition(rect: Rect, pos: Point): Point {
const { width, height } = window.visualViewport;
const { width, height } = window.visualViewport!;
const hasTransform = document.body.style.transform !== "";
const { left, top } = hasTransform ? document.body.getBoundingClientRect() : { left: 0, top: 0 };
const scale = getScale();
12 changes: 11 additions & 1 deletion test/demo.ts
Original file line number Diff line number Diff line change
@@ -131,7 +131,17 @@
]
},
{ isDivider: true },
{ text: "Event specific stuff" }
{ text: "Event specific stuff" },
{
text: "Hover me!",
action: () => {/** */ },
events: {
mouseenter: (_e) => document.querySelector("h1")!.style.animation = "blinker 1s linear infinite",
mouseleave: {
listener: (_e) => document.querySelector("h1")!.style.animation = "",
}
}
}
], function (m, e) {
m.push({
text: "e.g. Cursor Position: X:" + e.clientX + " / Y:" + e.clientY,