cleaning ShortcutManager
This commit is contained in:
Generated
+6
-6
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import {ShortcutKeys} from "@opendaw/lib-dom"
|
||||
import {Shortcut} from "@opendaw/lib-dom"
|
||||
|
||||
export type ShortcutDefinition = { keys: ShortcutKeys, description: string }
|
||||
export type ShortcutDefinition = { keys: Shortcut, description: string }
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
component
|
||||
display: flex
|
||||
flex-direction: column
|
||||
row-gap: 1em
|
||||
row-gap: 0.5em
|
||||
outline: none
|
||||
height: 280px
|
||||
overflow: hidden auto
|
||||
|
||||
@@ -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<ShortcutKeys> => {
|
||||
original: ShortcutDefinition): Promise<Shortcut> => {
|
||||
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,
|
||||
<h3 style={{color: Colors.orange.toString()}}>Shortcut for "{original.description}"</h3>
|
||||
<div style={{color: Colors.blue.toString(), height: "1.25em"}} onConnect={element => {
|
||||
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 (
|
||||
<div className={className} onInit={element => {
|
||||
const update = () => replaceChildren(element, Objects.entries(contexts).map(([name, shortcuts], index) => (
|
||||
<details className="context" open={index === 0}>
|
||||
<details className="context"
|
||||
open={lastOpenIndex === index}
|
||||
onInit={element => element.ontoggle = () => {
|
||||
if (element.open) {lastOpenIndex = index}
|
||||
}}>
|
||||
<summary><h3>{name}</h3></summary>
|
||||
<div className="shortcuts">
|
||||
{Objects.entries(shortcuts).map(([key, entry]) => (
|
||||
|
||||
@@ -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<ShortcutEntry> {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<ShortcutKeys> {
|
||||
const conflicts: Array<ShortcutKeys> = []
|
||||
hasConflicts(): ReadonlyArray<Shortcut> {
|
||||
const conflicts: Array<Shortcut> = []
|
||||
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<ShortcutKeys> {
|
||||
static fromJSON(value: JSONValue): Option<Shortcut> {
|
||||
if (typeof value !== "object" || value === null || Array.isArray(value)) {return Option.None}
|
||||
const {code, ctrl, shift, alt} = value as Record<string, unknown>
|
||||
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<ShortcutKeys> {
|
||||
static fromEvent(event: KeyboardEvent): Option<Shortcut> {
|
||||
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<string, string | [mac: string, other: string]> = {
|
||||
@@ -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
|
||||
}
|
||||
+1
-1
@@ -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
|
||||
Reference in New Issue
Block a user