From ef91d7976196c59279e1558f4d42a6f9fe4fad88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Michelle?= Date: Tue, 23 Dec 2025 16:51:41 +0100 Subject: [PATCH] cleaning ShortcutManager --- package-lock.json | 12 ++--- .../studio/src/shortcuts/GlobalShortcuts.ts | 54 +++++++++---------- .../src/shortcuts/ShortcutDefinition.ts | 4 +- .../src/shortcuts/ShortcutDefinitions.ts | 4 +- .../ui/components/ShortcutManagerView.sass | 2 +- .../src/ui/components/ShortcutManagerView.tsx | 14 +++-- packages/lib/dom/src/shortcut-manager.ts | 34 ++++++------ scripts/clean.sh | 2 +- 8 files changed, 66 insertions(+), 60 deletions(-) diff --git a/package-lock.json b/package-lock.json index 98a9d184..26e9b8ac 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5778,9 +5778,9 @@ "license": "MIT" }, "node_modules/fastq": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", - "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", "license": "ISC", "dependencies": { "reusify": "^1.0.4" @@ -7893,9 +7893,9 @@ } }, "node_modules/lib0": { - "version": "0.2.115", - "resolved": "https://registry.npmjs.org/lib0/-/lib0-0.2.115.tgz", - "integrity": "sha512-noaW4yNp6hCjOgDnWWxW0vGXE3kZQI5Kqiwz+jIWXavI9J9WyfJ9zjsbQlQlgjIbHBrvlA/x3TSIXBUJj+0L6g==", + "version": "0.2.116", + "resolved": "https://registry.npmjs.org/lib0/-/lib0-0.2.116.tgz", + "integrity": "sha512-4zsosjzmt33rx5XjmFVYUAeLNh+BTeDTiwGdLt4muxiir2btsc60Nal0EvkvDRizg+pnlK1q+BtYi7M+d4eStw==", "license": "MIT", "dependencies": { "isomorphic.js": "^0.2.4" diff --git a/packages/app/studio/src/shortcuts/GlobalShortcuts.ts b/packages/app/studio/src/shortcuts/GlobalShortcuts.ts index 1a391eb8..5d509c0d 100644 --- a/packages/app/studio/src/shortcuts/GlobalShortcuts.ts +++ b/packages/app/studio/src/shortcuts/GlobalShortcuts.ts @@ -1,4 +1,4 @@ -import {Key, ShortcutKeys} from "@opendaw/lib-dom" +import {Key, Shortcut} from "@opendaw/lib-dom" import {ShortcutValidator} from "@/shortcuts/ShortcutValidator" import {ShortcutDefinitions} from "@/shortcuts/ShortcutDefinitions" @@ -7,107 +7,107 @@ const ctrl = true export const GlobalShortcutsFactory = ShortcutValidator.validate({ "project-undo": { - keys: ShortcutKeys.of(Key.KeyZ, {ctrl}), + keys: Shortcut.of(Key.KeyZ, {ctrl}), description: "Undo last action" }, "project-redo": { - keys: ShortcutKeys.of(Key.KeyZ, {ctrl, shift}), + keys: Shortcut.of(Key.KeyZ, {ctrl, shift}), description: "Redo last action" }, "project-open": { - keys: ShortcutKeys.of(Key.KeyO, {ctrl}), + keys: Shortcut.of(Key.KeyO, {ctrl}), description: "Open project from local storage" }, "project-save": { - keys: ShortcutKeys.of(Key.KeyS, {ctrl}), + keys: Shortcut.of(Key.KeyS, {ctrl}), description: "Save project to local storage" }, "project-save-as": { - keys: ShortcutKeys.of(Key.KeyS, {ctrl, shift}), + keys: Shortcut.of(Key.KeyS, {ctrl, shift}), description: "Save project as new file" }, "toggle-playback": { - keys: ShortcutKeys.of(Key.Space), + keys: Shortcut.of(Key.Space), description: "Start or pause playback" }, "toggle-software-keyboard": { - keys: ShortcutKeys.of(Key.KeyK, {ctrl}), + keys: Shortcut.of(Key.KeyK, {ctrl}), description: "Show or hide software keyboard" }, "toggle-device-panel": { - keys: ShortcutKeys.of(Key.KeyD, {shift}), + keys: Shortcut.of(Key.KeyD, {shift}), description: "Show or hide device panel" }, "toggle-content-editor-panel": { - keys: ShortcutKeys.of(Key.KeyE, {shift}), + keys: Shortcut.of(Key.KeyE, {shift}), description: "Show or hide content editor" }, "toggle-browser-panel": { - keys: ShortcutKeys.of(Key.KeyB, {shift}), + keys: Shortcut.of(Key.KeyB, {shift}), description: "Show or hide browser panel" }, "toggle-tempo-track": { - keys: ShortcutKeys.of(Key.KeyT, {shift}), + keys: Shortcut.of(Key.KeyT, {shift}), description: "Show or hide tempo track" }, "toggle-markers-track": { - keys: ShortcutKeys.of(Key.KeyM, {shift}), + keys: Shortcut.of(Key.KeyM, {shift}), description: "Show or hide markers track" }, "toggle-clips": { - keys: ShortcutKeys.of(Key.KeyC, {shift}), + keys: Shortcut.of(Key.KeyC, {shift}), description: "Show or hide clips" }, "toggle-follow-cursor": { - keys: ShortcutKeys.of(Key.KeyF, {shift}), + keys: Shortcut.of(Key.KeyF, {shift}), description: "Toggle follow playhead" }, "toggle-metronome": { - keys: ShortcutKeys.of(Key.KeyM, {ctrl}), + keys: Shortcut.of(Key.KeyM, {ctrl}), description: "Enable or disable metronome" }, "copy-device": { - keys: ShortcutKeys.of(Key.KeyD, {ctrl}), + keys: Shortcut.of(Key.KeyD, {ctrl}), description: "Duplicate selected device" }, "workspace-next-screen": { - keys: ShortcutKeys.of(Key.Tab), + keys: Shortcut.of(Key.Tab), description: "Switch to next screen" }, "workspace-prev-screen": { - keys: ShortcutKeys.of(Key.Tab, {shift}), + keys: Shortcut.of(Key.Tab, {shift}), description: "Switch to previous screen" }, "workspace-screen-dashboard": { - keys: ShortcutKeys.of(Key.Digit0, {shift}), + keys: Shortcut.of(Key.Digit0, {shift}), description: "Go to dashboard" }, "workspace-screen-default": { - keys: ShortcutKeys.of(Key.Digit1, {shift}), + keys: Shortcut.of(Key.Digit1, {shift}), description: "Go to arrangement view" }, "workspace-screen-mixer": { - keys: ShortcutKeys.of(Key.Digit2, {shift}), + keys: Shortcut.of(Key.Digit2, {shift}), description: "Go to mixer view" }, "workspace-screen-piano": { - keys: ShortcutKeys.of(Key.Digit3, {shift}), + keys: Shortcut.of(Key.Digit3, {shift}), description: "Go to piano roll" }, "workspace-screen-project": { - keys: ShortcutKeys.of(Key.Digit4, {shift}), + keys: Shortcut.of(Key.Digit4, {shift}), description: "Go to project settings" }, "workspace-screen-shadertoy": { - keys: ShortcutKeys.of(Key.Digit5, {shift}), + keys: Shortcut.of(Key.Digit5, {shift}), description: "Go to shader visualizer" }, "workspace-screen-meter": { - keys: ShortcutKeys.of(Key.Digit6, {shift}), + keys: Shortcut.of(Key.Digit6, {shift}), description: "Go to meter view" }, "show-preferences": { - keys: ShortcutKeys.of(Key.Comma, {ctrl}), + keys: Shortcut.of(Key.Comma, {ctrl}), description: "Open preferences" } }) diff --git a/packages/app/studio/src/shortcuts/ShortcutDefinition.ts b/packages/app/studio/src/shortcuts/ShortcutDefinition.ts index c9ff83d8..09a781a2 100644 --- a/packages/app/studio/src/shortcuts/ShortcutDefinition.ts +++ b/packages/app/studio/src/shortcuts/ShortcutDefinition.ts @@ -1,3 +1,3 @@ -import {ShortcutKeys} from "@opendaw/lib-dom" +import {Shortcut} from "@opendaw/lib-dom" -export type ShortcutDefinition = { keys: ShortcutKeys, description: string } \ No newline at end of file +export type ShortcutDefinition = { keys: Shortcut, description: string } \ No newline at end of file diff --git a/packages/app/studio/src/shortcuts/ShortcutDefinitions.ts b/packages/app/studio/src/shortcuts/ShortcutDefinitions.ts index 31358234..ec099c98 100644 --- a/packages/app/studio/src/shortcuts/ShortcutDefinitions.ts +++ b/packages/app/studio/src/shortcuts/ShortcutDefinitions.ts @@ -1,4 +1,4 @@ -import {ShortcutKeys} from "@opendaw/lib-dom" +import {Shortcut} from "@opendaw/lib-dom" import {ShortcutDefinition} from "@/shortcuts/ShortcutDefinition" import {isAbsent, JSONValue} from "@opendaw/lib-std" @@ -32,7 +32,7 @@ export namespace ShortcutDefinitions { for (const [key, value] of Object.entries(values) as Array<[string, JSONValue]>) { const def = defs[key] if (isAbsent(def)) {continue} - ShortcutKeys.fromJSON(value).ifSome(keys => def.keys.overrideWith(keys)) + Shortcut.fromJSON(value).ifSome(keys => def.keys.overrideWith(keys)) } } } \ No newline at end of file diff --git a/packages/app/studio/src/ui/components/ShortcutManagerView.sass b/packages/app/studio/src/ui/components/ShortcutManagerView.sass index 599db017..51b0311b 100644 --- a/packages/app/studio/src/ui/components/ShortcutManagerView.sass +++ b/packages/app/studio/src/ui/components/ShortcutManagerView.sass @@ -1,7 +1,7 @@ component display: flex flex-direction: column - row-gap: 1em + row-gap: 0.5em outline: none height: 280px overflow: hidden auto diff --git a/packages/app/studio/src/ui/components/ShortcutManagerView.tsx b/packages/app/studio/src/ui/components/ShortcutManagerView.tsx index f532fd39..f3400a07 100644 --- a/packages/app/studio/src/ui/components/ShortcutManagerView.tsx +++ b/packages/app/studio/src/ui/components/ShortcutManagerView.tsx @@ -1,5 +1,5 @@ import css from "./ShortcutManagerView.sass?inline" -import {Events, Html, ShortcutKeys} from "@opendaw/lib-dom" +import {Events, Html, Shortcut} from "@opendaw/lib-dom" import {DefaultObservableValue, isAbsent, Lifecycle, Notifier, Objects, Terminator} from "@opendaw/lib-std" import {createElement, replaceChildren} from "@opendaw/lib-jsx" import {Dialogs} from "@/ui/components/dialogs" @@ -17,7 +17,7 @@ type Construct = { } const editShortcut = async (definitions: ShortcutDefinitions, - original: ShortcutDefinition): Promise => { + original: ShortcutDefinition): Promise => { const lifecycle = new Terminator() const abortController = new AbortController() const shortcut = lifecycle.own(new DefaultObservableValue(original.keys)) @@ -28,7 +28,7 @@ const editShortcut = async (definitions: ShortcutDefinitions,

Shortcut for "{original.description}"

{ lifecycle.own(Events.subscribe(Surface.get(element).owner, "keydown", event => { - ShortcutKeys.fromEvent(event).ifSome(newShortcut => { + Shortcut.fromEvent(event).ifSome(newShortcut => { shortcut.setValue(newShortcut) element.textContent = newShortcut.format() }) @@ -59,11 +59,17 @@ const editShortcut = async (definitions: ShortcutDefinitions, }).then(() => shortcut.getValue(), () => original.keys).finally(() => lifecycle.terminate()) } +let lastOpenIndex = 0 + export const ShortcutManagerView = ({lifecycle, contexts, updateNotifier}: Construct) => { return (
{ const update = () => replaceChildren(element, Objects.entries(contexts).map(([name, shortcuts], index) => ( -
+
element.ontoggle = () => { + if (element.open) {lastOpenIndex = index} + }}>

{name}

{Objects.entries(shortcuts).map(([key, entry]) => ( diff --git a/packages/lib/dom/src/shortcut-manager.ts b/packages/lib/dom/src/shortcut-manager.ts index 32750999..e201b6fc 100644 --- a/packages/lib/dom/src/shortcut-manager.ts +++ b/packages/lib/dom/src/shortcut-manager.ts @@ -40,7 +40,7 @@ export class ShortcutManager { } } - hasConflict(keys: ShortcutKeys): boolean { + hasConflict(keys: Shortcut): boolean { if (this.global.hasConflict(keys)) {return true} return this.#contexts.some(ctx => ctx.hasConflict(keys)) } @@ -77,7 +77,7 @@ export class ShortcutContext { get active(): boolean {return this.#isActive()} get shortcuts(): ReadonlyArray {return this.#shortcuts} - register(keys: ShortcutKeys, action: Exec, options?: ShortcutOptions): Subscription { + register(keys: Shortcut, action: Exec, options?: ShortcutOptions): Subscription { const entry: ShortcutEntry = {keys: keys, action, options: options ?? ShortcutOptions.Default} const index = BinarySearch.leftMostMapped( this.#shortcuts, entry.options.priority, NumberComparator, ({options: {priority}}) => priority) @@ -85,12 +85,12 @@ export class ShortcutContext { return this.#terminator.own({terminate: () => this.#shortcuts.splice(this.#shortcuts.indexOf(entry), 1)}) } - hasConflict(keys: ShortcutKeys): boolean { + hasConflict(keys: Shortcut): boolean { return this.#shortcuts.some(entry => entry.keys.equals(keys)) } - hasConflicts(): ReadonlyArray { - const conflicts: Array = [] + hasConflicts(): ReadonlyArray { + const conflicts: Array = [] for (let i = 0; i < this.#shortcuts.length; i++) { const keys = this.#shortcuts[i].keys if (conflicts.some(other => other.equals(keys))) {continue} @@ -107,22 +107,22 @@ export class ShortcutContext { terminate(): void {this.#terminator.terminate()} } -export class ShortcutKeys { - static of(code: string, modifiers?: { ctrl?: boolean, shift?: boolean, alt?: boolean }): ShortcutKeys { - return new ShortcutKeys(code, modifiers?.ctrl, modifiers?.shift, modifiers?.alt) +export class Shortcut { + static of(code: string, modifiers?: { ctrl?: boolean, shift?: boolean, alt?: boolean }): Shortcut { + return new Shortcut(code, modifiers?.ctrl, modifiers?.shift, modifiers?.alt) } - static fromJSON(value: JSONValue): Option { + static fromJSON(value: JSONValue): Option { if (typeof value !== "object" || value === null || Array.isArray(value)) {return Option.None} const {code, ctrl, shift, alt} = value as Record if (typeof code !== "string") {return Option.None} if (typeof ctrl !== "boolean") {return Option.None} if (typeof shift !== "boolean") {return Option.None} if (typeof alt !== "boolean") {return Option.None} - return Option.wrap(new ShortcutKeys(code, ctrl, shift, alt)) + return Option.wrap(new Shortcut(code, ctrl, shift, alt)) } - static fromEvent(event: KeyboardEvent): Option { + static fromEvent(event: KeyboardEvent): Option { const code = event.code if (code.startsWith("Shift") || code.startsWith("Control") @@ -132,7 +132,7 @@ export class ShortcutKeys { ) { return Option.None } - return Option.wrap(new ShortcutKeys(code, Keyboard.isControlKey(event), event.shiftKey, event.altKey)) + return Option.wrap(new Shortcut(code, Keyboard.isControlKey(event), event.shiftKey, event.altKey)) } static readonly #keyNames: Record = { @@ -187,7 +187,7 @@ export class ShortcutKeys { get shift(): boolean {return this.#shift} get alt(): boolean {return this.#alt} - equals(other: ShortcutKeys): boolean { + equals(other: Shortcut): boolean { return this.#code === other.#code && this.#ctrl === other.#ctrl && this.#shift === other.#shift @@ -206,11 +206,11 @@ export class ShortcutKeys { if (this.#shift) {parts.push(Browser.isMacOS() ? "⇧" : "Shift")} if (this.#alt) {parts.push(Browser.isMacOS() ? "⌥" : "Alt")} if (this.#ctrl) {parts.push(Browser.isMacOS() ? "⌘" : "Ctrl")} - parts.push(ShortcutKeys.#formatKey(this.#code)) + parts.push(Shortcut.#formatKey(this.#code)) return parts.join(Browser.isMacOS() ? "" : "+") } - overrideWith(keys: ShortcutKeys): void { + overrideWith(keys: Shortcut): void { this.#code = keys.#code this.#ctrl = keys.#ctrl this.#shift = keys.#shift @@ -219,7 +219,7 @@ export class ShortcutKeys { toJSON(): JSONValue {return {code: this.#code, ctrl: this.#ctrl, shift: this.#shift, alt: this.#alt}} - copy(): ShortcutKeys {return new ShortcutKeys(this.#code, this.#ctrl, this.#shift, this.#alt)} + copy(): Shortcut {return new Shortcut(this.#code, this.#ctrl, this.#shift, this.#alt)} toString(): string {return `{ShortcutKeys ${this.format()}}`} } @@ -247,7 +247,7 @@ export class ShortcutOptions { } type ShortcutEntry = { - readonly keys: ShortcutKeys + readonly keys: Shortcut readonly action: Exec readonly options: ShortcutOptions } \ No newline at end of file diff --git a/scripts/clean.sh b/scripts/clean.sh index 8310bdf2..9b2c9c75 100755 --- a/scripts/clean.sh +++ b/scripts/clean.sh @@ -11,6 +11,6 @@ echo "Removing package-lock.json..." find . -name package-lock.json -type f -delete 2>/dev/null || true echo "Removing .turbo..." -find . -name .turbo -type d -prune -exec rm -rf {} + 2>/dev/null || true +rm -rf .turbo packages/*/.turbo 2>/dev/null || true rm -rf packages/studio/boxes/src/* 2>/dev/null || true \ No newline at end of file