polished the UI a bit. next up: saving changes (and maybe a diff ui as confirmation dialog)

This commit is contained in:
Chris Kruining 2024-10-16 16:13:12 +02:00
parent 1a963a665e
commit 7db65413be
No known key found for this signature in database
GPG key ID: EB894A3560CCCAD2
9 changed files with 323 additions and 117 deletions

View file

@ -0,0 +1,84 @@
import { Accessor, Component, createContext, createEffect, createMemo, createSignal, createUniqueId, For, JSX, ParentComponent, useContext } from "solid-js";
import { CommandType } from "./index";
import css from "./contextMenu.module.css";
interface ContextMenuType {
readonly commands: Accessor<CommandType[]>;
readonly target: Accessor<HTMLElement | undefined>;
show(element: HTMLElement): void;
hide(): void;
}
const ContextMenu = createContext<ContextMenuType>()
const Root: ParentComponent<{ commands: CommandType[] }> = (props) => {
const [target, setTarget] = createSignal<HTMLElement>();
const context = {
commands: createMemo(() => props.commands),
target,
show(element: HTMLElement) {
setTarget(element);
},
hide() {
setTarget(undefined);
},
};
return <ContextMenu.Provider value={context}>
{props.children}
</ContextMenu.Provider>
};
const Menu: Component<{ children: (command: CommandType) => JSX.Element }> = (props) => {
const context = useContext(ContextMenu)!;
const [root, setRoot] = createSignal<HTMLElement>();
createEffect(() => {
const target = context.target();
const menu = root();
if (!menu) {
return;
}
if (target) {
menu.showPopover();
}
else {
menu.hidePopover();
}
});
const onToggle = (e: ToggleEvent) => {
if (e.newState === 'closed') {
context.hide();
}
};
const onCommand = (command: CommandType) => (e: PointerEvent) => {
context.hide();
command();
};
return <ul ref={setRoot} class={css.menu} style={`position-anchor: ${context.target()?.style.getPropertyValue('anchor-name')};`} popover ontoggle={onToggle}>
<For each={context.commands()}>{
command => <li onpointerdown={onCommand(command)}>{props.children(command)}</li>
}</For>
</ul>;
};
const Handle: ParentComponent = (props) => {
const context = useContext(ContextMenu)!;
return <span style={`anchor-name: --context-menu-handle-${createUniqueId()};`} oncontextmenu={(e) => {
e.preventDefault();
context.show(e.target as HTMLElement);
return false;
}}>{props.children}</span>;
};
export const Context = { Root, Menu, Handle };