feat: implement chroma key operation and related keybinds, update workspace panel management

This commit is contained in:
syntaxbullet
2026-07-11 00:09:41 +02:00
parent 51a54dbdb2
commit 556fd685a2
21 changed files with 134 additions and 50 deletions

View File

@@ -17,7 +17,7 @@ describe("command palette input", () => {
expect(dispatched).toEqual([{ commandId: commandIds.commandPaletteOpen, payload: undefined }]);
});
test("ignores unmodified K so the chroma key tool keeps its shortcut", () => {
test("ignores unmodified K so the chroma key operation keeps its shortcut", () => {
const consumed = handleCommandPaletteKey({
event: { key: "k", code: "KeyK", altKey: false, ctrlKey: false, metaKey: false, shiftKey: false },
dispatch: () => undefined as never,

View File

@@ -8,6 +8,7 @@ export { handleKeybind, keybindFromEvent } from "./keyboard";
export { handleCommandPaletteKey } from "./command-palette";
export { handleHistoryKey } from "./history";
export { handleToolKey } from "./tool-keybinds";
export { handleOperationKey } from "./operation-keybinds";
export { findGroup, findLayerInfoInDocument, handleDeleteSelectionKey, resolveLayerDrop } from "./layers-panel";
export type { LayerDropTarget, LayerInfo } from "./layers-panel";
export { handleArtboardSelection } from "./selection";

View File

@@ -0,0 +1,22 @@
import { describe, expect, test } from "bun:test";
import { commandIds } from "@commands/ids";
import type { Dispatch } from "@commands/dispatcher";
import { handleOperationKey } from "./operation-keybinds";
describe("operation keybinds", () => {
test.each([
["g", "generate"],
["k", "chromaKey"],
] as const)("opens the %s operation without selecting a tool", (key, panel) => {
const dispatched: unknown[] = [];
const consumed = handleOperationKey({
event: { key, code: `Key${key.toUpperCase()}`, altKey: false, ctrlKey: false, metaKey: false, shiftKey: false },
dispatch: ((commandId: unknown, payload: unknown) => {
dispatched.push({ commandId, payload });
return undefined;
}) as unknown as Dispatch,
});
expect(consumed).toBe(true);
expect(dispatched).toEqual([{ commandId: commandIds.workspaceSetPanel, payload: { panel } }]);
});
});

View File

@@ -0,0 +1,16 @@
import { commandIds } from "@commands/ids";
import type { Dispatch } from "@commands/dispatcher";
import type { KeybindEvent } from "./keyboard";
const operationKeybinds = {
g: "generate",
k: "chromaKey",
} as const;
export function handleOperationKey(options: { event: KeybindEvent; dispatch: Dispatch }): boolean {
if (options.event.altKey || options.event.ctrlKey || options.event.metaKey) return false;
const panel = operationKeybinds[options.event.key.toLowerCase() as keyof typeof operationKeybinds];
if (!panel) return false;
options.dispatch(commandIds.workspaceSetPanel, { panel });
return true;
}

View File

@@ -3,10 +3,8 @@ import type { Dispatch } from "@commands/dispatcher";
import type { KeybindEvent } from "./keyboard";
const toolKeybinds = {
g: "generate",
b: "brush",
e: "eraser",
k: "chromaKey",
w: "magicWand",
p: "pan",
s: "select",

View File

@@ -16,7 +16,7 @@ import type { PointerInputEvent } from "./pointer";
type TransformHandle = "body" | "nw" | "n" | "ne" | "e" | "se" | "s" | "sw" | "w";
type InputToolId = "select" | "generate" | "brush" | "eraser" | "chromaKey" | "magicWand" | "pan";
type InputToolId = "select" | "brush" | "eraser" | "magicWand" | "pan";
type InputInteractionMode =
| { type: "tool"; tool: InputToolId }