mirror of
https://github.com/ankitects/anki.git
synced 2025-09-24 16:56:36 -04:00
Replace svelte-contextmenu with a custom implementation
Keyboard navigation is to be handled.
This commit is contained in:
parent
b1771895c5
commit
01fd4df9cb
8 changed files with 138 additions and 16 deletions
|
@ -77,8 +77,7 @@
|
|||
"lodash-es": "^4.17.21",
|
||||
"lru-cache": "^10.2.0",
|
||||
"marked": "^5.1.0",
|
||||
"mathjax": "^3.1.2",
|
||||
"svelte-contextmenu": "^1.0.2"
|
||||
"mathjax": "^3.1.2"
|
||||
},
|
||||
"resolutions": {
|
||||
"canvas": "npm:empty-npm-package@1.0.0",
|
||||
|
|
82
ts/lib/context-menu/ContextMenu.svelte
Normal file
82
ts/lib/context-menu/ContextMenu.svelte
Normal file
|
@ -0,0 +1,82 @@
|
|||
<!-- Copyright: Ankitects Pty Ltd and contributors -->
|
||||
<!-- License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html -->
|
||||
|
||||
<script lang="ts">
|
||||
import { tick } from "svelte";
|
||||
import type { ContextMenuMouseEvent } from "./types";
|
||||
|
||||
let visible = $state(false);
|
||||
let x = $state(0);
|
||||
let y = $state(0);
|
||||
let contextMenuElement = $state<HTMLDivElement>();
|
||||
|
||||
const { children } = $props();
|
||||
|
||||
export async function show(event: ContextMenuMouseEvent) {
|
||||
event.preventDefault();
|
||||
|
||||
x = event.clientX;
|
||||
y = event.clientY;
|
||||
visible = true;
|
||||
|
||||
await tick();
|
||||
const rect = contextMenuElement!.getBoundingClientRect();
|
||||
const viewportWidth = window.innerWidth;
|
||||
const viewportHeight = window.innerHeight;
|
||||
|
||||
if (x + rect.width > viewportWidth) {
|
||||
x = viewportWidth - rect.width;
|
||||
}
|
||||
if (y + rect.height > viewportHeight) {
|
||||
y = viewportHeight - rect.height;
|
||||
}
|
||||
|
||||
x = Math.max(0, x);
|
||||
y = Math.max(0, y);
|
||||
}
|
||||
|
||||
function hide() {
|
||||
visible = false;
|
||||
}
|
||||
|
||||
function handleClickOutside(event: MouseEvent) {
|
||||
if (
|
||||
visible &&
|
||||
contextMenuElement &&
|
||||
!contextMenuElement.contains(event.target as Node)
|
||||
) {
|
||||
hide();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:document on:click={handleClickOutside} />
|
||||
|
||||
{#if visible}
|
||||
<div
|
||||
bind:this={contextMenuElement}
|
||||
class="context-menu"
|
||||
style="left: {x}px; top: {y}px;"
|
||||
role="menu"
|
||||
tabindex="0"
|
||||
onclick={hide}
|
||||
onkeydown={hide}
|
||||
>
|
||||
{@render children?.()}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style lang="scss">
|
||||
.context-menu {
|
||||
position: fixed;
|
||||
background: var(--canvas);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
||||
padding: 4px 0;
|
||||
min-width: 120px;
|
||||
z-index: 1000;
|
||||
font-size: 13px;
|
||||
outline: none;
|
||||
}
|
||||
</style>
|
33
ts/lib/context-menu/Item.svelte
Normal file
33
ts/lib/context-menu/Item.svelte
Normal file
|
@ -0,0 +1,33 @@
|
|||
<!-- Copyright: Ankitects Pty Ltd and contributors -->
|
||||
<!-- License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html -->
|
||||
|
||||
<script lang="ts">
|
||||
const { click, children } = $props();
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="context-menu-item"
|
||||
onclick={click}
|
||||
onkeydown={click}
|
||||
role="menuitem"
|
||||
tabindex="-1"
|
||||
>
|
||||
{@render children?.()}
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.context-menu-item {
|
||||
padding: 8px 16px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
white-space: nowrap;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--highlight-bg);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: var(--highlight-bg);
|
||||
}
|
||||
}
|
||||
</style>
|
6
ts/lib/context-menu/index.ts
Normal file
6
ts/lib/context-menu/index.ts
Normal file
|
@ -0,0 +1,6 @@
|
|||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
export { default as ContextMenu } from "./ContextMenu.svelte";
|
||||
export { default as Item } from "./Item.svelte";
|
||||
export type { ContextMenuAPI, ContextMenuMouseEvent } from "./types";
|
12
ts/lib/context-menu/types.ts
Normal file
12
ts/lib/context-menu/types.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
export interface ContextMenuMouseEvent {
|
||||
clientX: number;
|
||||
clientY: number;
|
||||
preventDefault(): void;
|
||||
}
|
||||
|
||||
export interface ContextMenuAPI {
|
||||
show(event: ContextMenuMouseEvent): void;
|
||||
}
|
|
@ -14,7 +14,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
import LabelContainer from "./LabelContainer.svelte";
|
||||
import LabelName from "./LabelName.svelte";
|
||||
import { EditorState, type EditorMode } from "./types";
|
||||
import ContextMenu, { Item } from "svelte-contextmenu";
|
||||
import { ContextMenu, Item } from "$lib/context-menu";
|
||||
|
||||
export interface NoteEditorAPI {
|
||||
fields: EditorFieldAPI[];
|
||||
|
@ -1226,7 +1226,7 @@ components and functionality for general note editing.
|
|||
<ContextMenu bind:this={contextMenu}>
|
||||
{#each contextMenuItems as item}
|
||||
<Item
|
||||
on:click={() => {
|
||||
click={() => {
|
||||
item.action();
|
||||
contextMenuInput?.focus();
|
||||
}}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
import type { ContextMenu, ContextMenuMouseEvent } from "$lib/context-menu";
|
||||
|
||||
import { openMedia, showInMediaFolder } from "@generated/backend";
|
||||
import * as tr from "@generated/ftl";
|
||||
import { bridgeCommand } from "@tslib/bridgecommand";
|
||||
import { getSelection } from "@tslib/cross-browser";
|
||||
import type ContextMenu from "svelte-contextmenu";
|
||||
import type { ContextMenuMouseEvent } from "svelte-contextmenu/ContextMenuMouseEvent";
|
||||
import { get } from "svelte/store";
|
||||
import type { EditingInputAPI } from "./EditingArea.svelte";
|
||||
import type { NoteEditorAPI } from "./NoteEditor.svelte";
|
||||
|
@ -114,8 +114,6 @@ export function setupContextMenu(): [
|
|||
if (contextMenuItems.length > 0) {
|
||||
contextMenu?.show(event);
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
return [onContextMenu, contextMenuItems];
|
||||
|
|
|
@ -1761,7 +1761,6 @@ __metadata:
|
|||
sass: "npm:<1.77"
|
||||
svelte: "npm:^5.34.9"
|
||||
svelte-check: "npm:^4.2.2"
|
||||
svelte-contextmenu: "npm:^1.0.2"
|
||||
svelte-preprocess: "npm:^6.0.3"
|
||||
svelte-preprocess-esbuild: "npm:^3.0.1"
|
||||
svgo: "npm:^3.2.0"
|
||||
|
@ -6229,13 +6228,6 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"svelte-contextmenu@npm:^1.0.2":
|
||||
version: 1.0.2
|
||||
resolution: "svelte-contextmenu@npm:1.0.2"
|
||||
checksum: 10c0/33cf79540337862278927f4b732b5d97f2c029348666ebcd3105b5c08bed54498a1d66f61b0212c18c204942cf54c9f6ce5ed509981d9f19f99f9334d8961cdf
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"svelte-eslint-parser@npm:^0.43.0":
|
||||
version: 0.43.0
|
||||
resolution: "svelte-eslint-parser@npm:0.43.0"
|
||||
|
|
Loading…
Reference in a new issue