quilt-vanilla 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/dist/actions.d.ts +17 -0
  2. package/dist/actions.d.ts.map +1 -0
  3. package/dist/actions.js +146 -0
  4. package/dist/actions.js.map +1 -0
  5. package/dist/command-registry.d.ts +39 -0
  6. package/dist/command-registry.d.ts.map +1 -0
  7. package/dist/command-registry.js +202 -0
  8. package/dist/command-registry.js.map +1 -0
  9. package/dist/index.d.ts +3 -1
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +2 -0
  12. package/dist/index.js.map +1 -1
  13. package/dist/menu.d.ts +9 -3
  14. package/dist/menu.d.ts.map +1 -1
  15. package/dist/menu.js +110 -37
  16. package/dist/menu.js.map +1 -1
  17. package/dist/renderer.d.ts.map +1 -1
  18. package/dist/renderer.js +42 -8
  19. package/dist/renderer.js.map +1 -1
  20. package/dist/shortcut-registration.d.ts +10 -0
  21. package/dist/shortcut-registration.d.ts.map +1 -0
  22. package/dist/shortcut-registration.js +105 -0
  23. package/dist/shortcut-registration.js.map +1 -0
  24. package/dist/shortcuts.d.ts +7 -6
  25. package/dist/shortcuts.d.ts.map +1 -1
  26. package/dist/shortcuts.js +27 -50
  27. package/dist/shortcuts.js.map +1 -1
  28. package/dist/styles.css +25 -9
  29. package/dist/tabs.d.ts.map +1 -1
  30. package/dist/tabs.js +10 -12
  31. package/dist/tabs.js.map +1 -1
  32. package/dist/types.d.ts +52 -5
  33. package/dist/types.d.ts.map +1 -1
  34. package/dist/types.js.map +1 -1
  35. package/dist/workspace-api.d.ts +20 -2
  36. package/dist/workspace-api.d.ts.map +1 -1
  37. package/dist/workspace-api.js +64 -0
  38. package/dist/workspace-api.js.map +1 -1
  39. package/package.json +2 -2
  40. package/src/actions.ts +163 -0
  41. package/src/command-registry.ts +248 -0
  42. package/src/index.ts +15 -0
  43. package/src/menu.ts +123 -43
  44. package/src/renderer.ts +48 -7
  45. package/src/shortcut-registration.ts +120 -0
  46. package/src/shortcuts.ts +43 -64
  47. package/src/styles.css +25 -9
  48. package/src/tabs.ts +9 -11
  49. package/src/types.ts +74 -5
  50. package/src/workspace-api.ts +83 -1
@@ -0,0 +1,17 @@
1
+ import type { Group, Pane } from 'quilt-core';
2
+ import type { ActionContext, CommandId, ResolvedLayoutOptions, WorkspaceAction } from './types.js';
3
+ import type { CommandRegistry } from './command-registry.js';
4
+ export declare function createActions(options: ResolvedLayoutOptions, dependencies: {
5
+ registry: CommandRegistry;
6
+ context(): ActionContext;
7
+ disposed(): boolean;
8
+ create(action: WorkspaceAction, group: Group, pane: Pane | undefined): void;
9
+ close(id: string, kind?: 'pane' | 'group'): Promise<boolean>;
10
+ popout(id: string): Promise<boolean>;
11
+ report(error: unknown): void;
12
+ }): {
13
+ canExecuteAction: (action: CommandId, context?: ActionContext) => boolean;
14
+ executeAction: (action: CommandId, context?: ActionContext) => Promise<boolean>;
15
+ getShortcuts: () => readonly import("./types.js").RegisteredShortcut[];
16
+ };
17
+ //# sourceMappingURL=actions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../src/actions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EACV,aAAa,EACb,SAAS,EAET,qBAAqB,EACrB,eAAe,EAChB,MAAM,YAAY,CAAC;AAEpB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE7D,wBAAgB,aAAa,CAC3B,OAAO,EAAE,qBAAqB,EAC9B,YAAY,EAAE;IACZ,QAAQ,EAAE,eAAe,CAAC;IAC1B,OAAO,IAAI,aAAa,CAAC;IACzB,QAAQ,IAAI,OAAO,CAAC;IACpB,MAAM,CAAC,MAAM,EAAE,eAAe,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,GAAG,SAAS,GAAG,IAAI,CAAC;IAC5E,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7D,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACrC,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;CAC9B;+BA0BiC,SAAS,YAAY,aAAa,KAAG,OAAO;4BA8CzC,SAAS,YAAY,aAAa,KAAG,OAAO,CAAC,OAAO,CAAC;;EAoE3F"}
@@ -0,0 +1,146 @@
1
+ import { findNode, findParent, groups, paneIds } from 'quilt-core';
2
+ import { isWorkspaceAction } from './shortcut-registration.js';
3
+ export function createActions(options, dependencies) {
4
+ function resolve(context) {
5
+ const layout = options.store.getSnapshot();
6
+ const target = context?.groupId !== undefined || context?.paneId !== undefined
7
+ ? context
8
+ : dependencies.context();
9
+ const id = target.groupId ??
10
+ (target.paneId === undefined
11
+ ? undefined
12
+ : groups(layout.root).find((group) => group.panes.includes(target.paneId))?.id);
13
+ const node = id === undefined ? undefined : findNode(layout.root, id);
14
+ const group = node?.kind === 'group' ? node : undefined;
15
+ const paneId = target.paneId ?? group?.active;
16
+ const pane = paneId ? layout.panes[paneId] : undefined;
17
+ const valid = !(target.groupId !== undefined && !group) &&
18
+ !(target.paneId !== undefined && (!pane || !group?.panes.includes(target.paneId)));
19
+ const commandContext = {
20
+ ...(group ? { groupId: group.id } : {}),
21
+ ...(pane ? { paneId: pane.id } : {}),
22
+ };
23
+ return { layout, group, pane, valid, commandContext };
24
+ }
25
+ function canExecuteAction(action, context) {
26
+ if (dependencies.disposed())
27
+ return false;
28
+ const { layout, group, pane, valid, commandContext } = resolve(context);
29
+ if (!valid)
30
+ return false;
31
+ if (!isWorkspaceAction(action)) {
32
+ const entry = dependencies.registry.getCommand(action);
33
+ if (!entry || entry.controller.signal.aborted)
34
+ return false;
35
+ try {
36
+ const input = Object.freeze({
37
+ ...commandContext,
38
+ signal: entry.controller.signal,
39
+ });
40
+ return (entry.definition.enabled?.(input) ?? true) && !entry.controller.signal.aborted;
41
+ }
42
+ catch (error) {
43
+ dependencies.report(error);
44
+ return false;
45
+ }
46
+ }
47
+ if (action === 'restoreClosedTab')
48
+ return options.store.canRestoreClosedTab();
49
+ if (!group)
50
+ return false;
51
+ const allowed = (cap) => group.panes.every((id) => options.store.can(id, cap));
52
+ switch (action) {
53
+ case 'addTab':
54
+ return !!options.tabs?.list().length && allowed('move');
55
+ case 'splitLeft':
56
+ case 'splitRight':
57
+ case 'splitUp':
58
+ case 'splitDown':
59
+ return (!group.panes.length || !!options.tabs?.list().length) && allowed('split');
60
+ case 'closeActiveTab':
61
+ return !!pane && options.store.can(pane.id, 'close');
62
+ case 'closePane':
63
+ return !!group.panes.length && allowed('close');
64
+ case 'closeEmptyPane':
65
+ return !group.panes.length && group.id !== layout.root.id;
66
+ case 'popout':
67
+ return options.popouts !== false && !!pane && options.store.can(pane.id, 'popout');
68
+ case 'joinSiblingRegion': {
69
+ const parent = findParent(layout.root, group.id);
70
+ return !!parent && paneIds(parent).every((id) => options.store.can(id, 'join'));
71
+ }
72
+ default:
73
+ return true;
74
+ }
75
+ }
76
+ async function executeAction(action, context) {
77
+ try {
78
+ if (!canExecuteAction(action, context))
79
+ return false;
80
+ const { layout, group, pane, commandContext } = resolve(context);
81
+ if (!isWorkspaceAction(action)) {
82
+ const entry = dependencies.registry.getCommand(action);
83
+ if (!entry || entry.controller.signal.aborted)
84
+ return false;
85
+ const result = await entry.definition.execute(Object.freeze({ ...commandContext, signal: entry.controller.signal }));
86
+ return result !== false && !entry.controller.signal.aborted;
87
+ }
88
+ switch (action) {
89
+ case 'restoreClosedTab':
90
+ options.store.restoreClosedTab();
91
+ break;
92
+ case 'maximize':
93
+ options.store.maximize(layout.maximized === group.id ? null : group.id);
94
+ break;
95
+ case 'addTab':
96
+ case 'splitLeft':
97
+ case 'splitRight':
98
+ case 'splitUp':
99
+ case 'splitDown':
100
+ dependencies.create(action, group, pane);
101
+ break;
102
+ case 'closeActiveTab':
103
+ return await dependencies.close(pane.id);
104
+ case 'closePane':
105
+ return await dependencies.close(group.id, 'group');
106
+ case 'closeEmptyPane':
107
+ options.store.removeEmptyGroup(group.id);
108
+ break;
109
+ case 'popout':
110
+ return await dependencies.popout(pane.id);
111
+ case 'joinSiblingRegion':
112
+ options.store.join(group.id, { source: 'user' });
113
+ break;
114
+ case 'tabOrientationDefault':
115
+ options.store.setTabPlacement(group.id, undefined);
116
+ break;
117
+ case 'tabOrientationHorizontal':
118
+ options.store.setTabPlacement(group.id, 'top');
119
+ break;
120
+ case 'tabOrientationVertical':
121
+ options.store.setTabPlacement(group.id, 'left');
122
+ break;
123
+ case 'tabDisplayDefault':
124
+ options.store.setTabDisplay(group.id, undefined);
125
+ break;
126
+ case 'tabDisplayAutomatic':
127
+ options.store.setTabDisplay(group.id, 'automatic');
128
+ break;
129
+ case 'tabDisplayCompact':
130
+ options.store.setTabDisplay(group.id, 'compact');
131
+ break;
132
+ }
133
+ return true;
134
+ }
135
+ catch (error) {
136
+ dependencies.report(error);
137
+ return false;
138
+ }
139
+ }
140
+ return {
141
+ canExecuteAction,
142
+ executeAction,
143
+ getShortcuts: () => dependencies.registry.getShortcuts(),
144
+ };
145
+ }
146
+ //# sourceMappingURL=actions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actions.js","sourceRoot":"","sources":["../src/actions.ts"],"names":[],"mappings":"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","sourcesContent":["import { findNode, findParent, groups, paneIds } from 'quilt-core';\nimport type { Group, Pane } from 'quilt-core';\nimport type {\n ActionContext,\n CommandId,\n CommandContext,\n ResolvedLayoutOptions,\n WorkspaceAction,\n} from './types.js';\nimport { isWorkspaceAction } from './shortcut-registration.js';\nimport type { CommandRegistry } from './command-registry.js';\n\nexport function createActions(\n options: ResolvedLayoutOptions,\n dependencies: {\n registry: CommandRegistry;\n context(): ActionContext;\n disposed(): boolean;\n create(action: WorkspaceAction, group: Group, pane: Pane | undefined): void;\n close(id: string, kind?: 'pane' | 'group'): Promise<boolean>;\n popout(id: string): Promise<boolean>;\n report(error: unknown): void;\n },\n) {\n function resolve(context?: ActionContext) {\n const layout = options.store.getSnapshot();\n const target =\n context?.groupId !== undefined || context?.paneId !== undefined\n ? context\n : dependencies.context();\n const id =\n target.groupId ??\n (target.paneId === undefined\n ? undefined\n : groups(layout.root).find((group) => group.panes.includes(target.paneId!))?.id);\n const node = id === undefined ? undefined : findNode(layout.root, id);\n const group = node?.kind === 'group' ? node : undefined;\n const paneId = target.paneId ?? group?.active;\n const pane = paneId ? layout.panes[paneId] : undefined;\n const valid =\n !(target.groupId !== undefined && !group) &&\n !(target.paneId !== undefined && (!pane || !group?.panes.includes(target.paneId)));\n const commandContext = {\n ...(group ? { groupId: group.id } : {}),\n ...(pane ? { paneId: pane.id } : {}),\n };\n return { layout, group, pane, valid, commandContext };\n }\n function canExecuteAction(action: CommandId, context?: ActionContext): boolean {\n if (dependencies.disposed()) return false;\n const { layout, group, pane, valid, commandContext } = resolve(context);\n if (!valid) return false;\n if (!isWorkspaceAction(action)) {\n const entry = dependencies.registry.getCommand(action);\n if (!entry || entry.controller.signal.aborted) return false;\n try {\n const input: CommandContext = Object.freeze({\n ...commandContext,\n signal: entry.controller.signal,\n });\n return (entry.definition.enabled?.(input) ?? true) && !entry.controller.signal.aborted;\n } catch (error) {\n dependencies.report(error);\n return false;\n }\n }\n if (action === 'restoreClosedTab') return options.store.canRestoreClosedTab();\n if (!group) return false;\n const allowed = (cap: 'split' | 'move' | 'close') =>\n group.panes.every((id) => options.store.can(id, cap));\n switch (action) {\n case 'addTab':\n return !!options.tabs?.list().length && allowed('move');\n case 'splitLeft':\n case 'splitRight':\n case 'splitUp':\n case 'splitDown':\n return (!group.panes.length || !!options.tabs?.list().length) && allowed('split');\n case 'closeActiveTab':\n return !!pane && options.store.can(pane.id, 'close');\n case 'closePane':\n return !!group.panes.length && allowed('close');\n case 'closeEmptyPane':\n return !group.panes.length && group.id !== layout.root.id;\n case 'popout':\n return options.popouts !== false && !!pane && options.store.can(pane.id, 'popout');\n case 'joinSiblingRegion': {\n const parent = findParent(layout.root, group.id);\n return !!parent && paneIds(parent).every((id) => options.store.can(id, 'join'));\n }\n default:\n return true;\n }\n }\n async function executeAction(action: CommandId, context?: ActionContext): Promise<boolean> {\n try {\n if (!canExecuteAction(action, context)) return false;\n const { layout, group, pane, commandContext } = resolve(context);\n if (!isWorkspaceAction(action)) {\n const entry = dependencies.registry.getCommand(action);\n if (!entry || entry.controller.signal.aborted) return false;\n const result = await entry.definition.execute(\n Object.freeze({ ...commandContext, signal: entry.controller.signal }),\n );\n return result !== false && !entry.controller.signal.aborted;\n }\n switch (action) {\n case 'restoreClosedTab':\n options.store.restoreClosedTab();\n break;\n case 'maximize':\n options.store.maximize(layout.maximized === group!.id ? null : group!.id);\n break;\n case 'addTab':\n case 'splitLeft':\n case 'splitRight':\n case 'splitUp':\n case 'splitDown':\n dependencies.create(action, group!, pane);\n break;\n case 'closeActiveTab':\n return await dependencies.close(pane!.id);\n case 'closePane':\n return await dependencies.close(group!.id, 'group');\n case 'closeEmptyPane':\n options.store.removeEmptyGroup(group!.id);\n break;\n case 'popout':\n return await dependencies.popout(pane!.id);\n case 'joinSiblingRegion':\n options.store.join(group!.id, { source: 'user' });\n break;\n case 'tabOrientationDefault':\n options.store.setTabPlacement(group!.id, undefined);\n break;\n case 'tabOrientationHorizontal':\n options.store.setTabPlacement(group!.id, 'top');\n break;\n case 'tabOrientationVertical':\n options.store.setTabPlacement(group!.id, 'left');\n break;\n case 'tabDisplayDefault':\n options.store.setTabDisplay(group!.id, undefined);\n break;\n case 'tabDisplayAutomatic':\n options.store.setTabDisplay(group!.id, 'automatic');\n break;\n case 'tabDisplayCompact':\n options.store.setTabDisplay(group!.id, 'compact');\n break;\n }\n return true;\n } catch (error) {\n dependencies.report(error);\n return false;\n }\n }\n return {\n canExecuteAction,\n executeAction,\n getShortcuts: () => dependencies.registry.getShortcuts(),\n };\n}\n"]}
@@ -0,0 +1,39 @@
1
+ import type { CommandId, CommandRegistration, RegisteredCommand, RegisteredShortcut, ShortcutRegistration, ShortcutConflict, LayoutOptionUpdates } from './types.js';
2
+ export declare class ShortcutConflictError extends Error {
3
+ readonly conflicts: readonly ShortcutConflict[];
4
+ readonly code = "SHORTCUT_CONFLICT";
5
+ constructor(conflicts: readonly ShortcutConflict[]);
6
+ }
7
+ type CommandEntry = {
8
+ definition: Readonly<CommandRegistration>;
9
+ controller: AbortController;
10
+ };
11
+ type Settings = Pick<LayoutOptionUpdates, 'commands' | 'shortcuts' | 'shortcutConflictPolicy' | 'onShortcutConflict'>;
12
+ /** Per-workspace state shared by the menu, keyboard listener, and public API. */
13
+ export declare class CommandRegistry {
14
+ private report;
15
+ private commands;
16
+ private bindings;
17
+ private policy;
18
+ private warn;
19
+ private listeners;
20
+ private disposed;
21
+ constructor(settings: Settings, report: (error: unknown) => void);
22
+ private alive;
23
+ private entry;
24
+ private ordered;
25
+ private conflicts;
26
+ /** Validate now; the renderer commits after validating its other options. */
27
+ prepare(next: Settings): () => void;
28
+ private commit;
29
+ registerShortcut(action: CommandId, registration: ShortcutRegistration): () => void;
30
+ registerCommand(command: CommandRegistration): () => void;
31
+ getCommand(id: CommandId): CommandEntry | undefined;
32
+ getCommands(): readonly RegisteredCommand[];
33
+ getShortcuts(): readonly RegisteredShortcut[];
34
+ getShortcutConflicts(): readonly ShortcutConflict[];
35
+ subscribe(listener: () => void): () => void;
36
+ dispose(): void;
37
+ }
38
+ export {};
39
+ //# sourceMappingURL=command-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-registry.d.ts","sourceRoot":"","sources":["../src/command-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EAET,mBAAmB,EACnB,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,gBAAgB,EAGhB,mBAAmB,EACpB,MAAM,YAAY,CAAC;AAQpB,qBAAa,qBAAsB,SAAQ,KAAK;IAElC,QAAQ,CAAC,SAAS,EAAE,SAAS,gBAAgB,EAAE;IAD3D,QAAQ,CAAC,IAAI,uBAAuB;IACpC,YAAqB,SAAS,EAAE,SAAS,gBAAgB,EAAE,EAK1D;CACF;AACD,KAAK,YAAY,GAAG;IAAE,UAAU,EAAE,QAAQ,CAAC,mBAAmB,CAAC,CAAC;IAAC,UAAU,EAAE,eAAe,CAAA;CAAE,CAAC;AAC/F,KAAK,QAAQ,GAAG,IAAI,CAClB,mBAAmB,EACnB,UAAU,GAAG,WAAW,GAAG,wBAAwB,GAAG,oBAAoB,CAC3E,CAAC;AAEF,iFAAiF;AACjF,qBAAa,eAAe;IASxB,OAAO,CAAC,MAAM;IARhB,OAAO,CAAC,QAAQ,CAA4C;IAC5D,OAAO,CAAC,QAAQ,CAA4C;IAC5D,OAAO,CAAC,MAAM,CAAsC;IACpD,OAAO,CAAC,IAAI,CAA0C;IACtD,OAAO,CAAC,SAAS,CAAyB;IAC1C,OAAO,CAAC,QAAQ,CAAS;IACzB,YACE,QAAQ,EAAE,QAAQ,EACV,MAAM,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,EAGzC;IACD,OAAO,CAAC,KAAK;IAGb,OAAO,CAAC,KAAK;IAab,OAAO,CAAC,OAAO;IAWf,OAAO,CAAC,SAAS;IA8BjB,6EAA6E;IAC7E,OAAO,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,IAAI,CAqClC;IACD,OAAO,CAAC,MAAM;IAsCd,gBAAgB,CAAC,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,oBAAoB,GAAG,MAAM,IAAI,CAmBlF;IACD,eAAe,CAAC,OAAO,EAAE,mBAAmB,GAAG,MAAM,IAAI,CAaxD;IACD,UAAU,CAAC,EAAE,EAAE,SAAS,4BAEvB;IACD,WAAW,IAAI,SAAS,iBAAiB,EAAE,CAM1C;IACD,YAAY,kCAEX;IACD,oBAAoB,gCAEnB;IACD,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,cAK7B;IACD,OAAO,SAQN;CACF"}
@@ -0,0 +1,202 @@
1
+ import { actionOrder, isWorkspaceAction, registeredShortcuts, formatShortcut, } from './shortcut-registration.js';
2
+ export class ShortcutConflictError extends Error {
3
+ conflicts;
4
+ code = 'SHORTCUT_CONFLICT';
5
+ constructor(conflicts) {
6
+ super(`Conflicting shortcuts: ${conflicts.map(({ binding, actions }) => `${formatShortcut(binding)} (${actions.join(', ')})`).join('; ')}`);
7
+ this.conflicts = conflicts;
8
+ this.name = 'ShortcutConflictError';
9
+ }
10
+ }
11
+ /** Per-workspace state shared by the menu, keyboard listener, and public API. */
12
+ export class CommandRegistry {
13
+ report;
14
+ commands = new Map();
15
+ bindings = new Map();
16
+ policy = 'priority';
17
+ warn;
18
+ listeners = new Set();
19
+ disposed = false;
20
+ constructor(settings, report) {
21
+ this.report = report;
22
+ this.prepare(settings)();
23
+ }
24
+ alive() {
25
+ if (this.disposed)
26
+ throw new Error('Command registry has been disposed');
27
+ }
28
+ entry(command) {
29
+ if (!command ||
30
+ typeof command.id !== 'string' ||
31
+ !/^[^.\s]+(?:\.[^.\s]+)+$/.test(command.id) ||
32
+ typeof command.label !== 'string' ||
33
+ !command.label.trim() ||
34
+ typeof command.execute !== 'function' ||
35
+ (command.enabled !== undefined && typeof command.enabled !== 'function'))
36
+ throw new Error('A custom command needs a namespaced id, label, and execute callback');
37
+ return { definition: Object.freeze({ ...command }), controller: new AbortController() };
38
+ }
39
+ ordered(bindings = this.bindings, commands = this.commands) {
40
+ return Object.freeze([...actionOrder, ...commands.keys()].flatMap((id) => {
41
+ const entry = bindings.get(id);
42
+ return entry?.bindings.length ? [entry] : [];
43
+ }));
44
+ }
45
+ conflicts(bindings = this.bindings, commands = this.commands) {
46
+ const keys = new Map();
47
+ for (const entry of this.ordered(bindings, commands))
48
+ for (const binding of entry.bindings) {
49
+ const normalized = Object.freeze({ ...binding, key: binding.key.toLowerCase() });
50
+ const key = JSON.stringify([
51
+ normalized.key,
52
+ !!binding.ctrl,
53
+ !!binding.alt,
54
+ !!binding.shift,
55
+ !!binding.meta,
56
+ ]);
57
+ const item = keys.get(key) ?? { binding: normalized, actions: [] };
58
+ if (!item.actions.includes(entry.action))
59
+ item.actions.push(entry.action);
60
+ keys.set(key, item);
61
+ }
62
+ return Object.freeze([...keys.values()]
63
+ .filter((item) => item.actions.length > 1)
64
+ .map((item) => Object.freeze({ binding: item.binding, actions: Object.freeze(item.actions) })));
65
+ }
66
+ /** Validate now; the renderer commits after validating its other options. */
67
+ prepare(next) {
68
+ this.alive();
69
+ let commands = this.commands;
70
+ if ('commands' in next) {
71
+ commands = new Map();
72
+ for (const command of next.commands ?? []) {
73
+ const entry = this.entry(command);
74
+ if (commands.has(command.id))
75
+ throw new Error(`Duplicate command: ${command.id}`);
76
+ const previous = this.commands.get(command.id);
77
+ commands.set(command.id, previous &&
78
+ previous.definition.execute === command.execute &&
79
+ previous.definition.enabled === command.enabled
80
+ ? { definition: entry.definition, controller: previous.controller }
81
+ : entry);
82
+ }
83
+ }
84
+ let bindings = new Map(this.bindings);
85
+ for (const id of bindings.keys())
86
+ if (!isWorkspaceAction(id) && !commands.has(id))
87
+ bindings.delete(id);
88
+ if ('shortcuts' in next)
89
+ bindings = new Map(registeredShortcuts({ shortcuts: next.shortcuts }, [...commands.keys()]).map((entry) => [
90
+ entry.action,
91
+ entry,
92
+ ]));
93
+ const policy = 'shortcutConflictPolicy' in next ? (next.shortcutConflictPolicy ?? 'priority') : this.policy;
94
+ if (!['priority', 'warn', 'error'].includes(policy))
95
+ throw new Error('Invalid shortcut conflict policy');
96
+ const warn = 'onShortcutConflict' in next ? next.onShortcutConflict : this.warn;
97
+ const conflicts = this.conflicts(bindings, commands);
98
+ if (policy === 'error' && conflicts.length)
99
+ throw new ShortcutConflictError(conflicts);
100
+ return () => this.commit(commands, bindings, policy, warn);
101
+ }
102
+ commit(commands, bindings, policy = this.policy, warn = this.warn) {
103
+ const before = JSON.stringify(this.getShortcutConflicts());
104
+ const previousPolicy = this.policy;
105
+ const liveControllers = new Set([...commands.values()].map((entry) => entry.controller));
106
+ const removed = [...this.commands.values()].filter((entry) => !liveControllers.has(entry.controller));
107
+ this.commands = commands;
108
+ this.bindings = bindings;
109
+ this.policy = policy;
110
+ this.warn = warn;
111
+ for (const entry of removed)
112
+ entry.controller.abort();
113
+ for (const listener of [...this.listeners]) {
114
+ try {
115
+ listener();
116
+ }
117
+ catch (error) {
118
+ this.report(error);
119
+ }
120
+ }
121
+ const conflicts = this.getShortcutConflicts();
122
+ if (policy === 'warn' &&
123
+ conflicts.length &&
124
+ (before !== JSON.stringify(conflicts) || previousPolicy !== policy)) {
125
+ try {
126
+ if (warn)
127
+ warn(conflicts);
128
+ else
129
+ console.warn(new ShortcutConflictError(conflicts));
130
+ }
131
+ catch (error) {
132
+ this.report(error);
133
+ }
134
+ }
135
+ }
136
+ registerShortcut(action, registration) {
137
+ this.alive();
138
+ if (!isWorkspaceAction(action) && !this.commands.has(action))
139
+ throw new Error(`Unknown shortcut command: ${action}`);
140
+ const normalized = registeredShortcuts({ shortcuts: { [action]: registration } }, [
141
+ ...this.commands.keys(),
142
+ ])[0];
143
+ const token = normalized ?? Object.freeze({ action, bindings: Object.freeze([]), handling: 'quilt' });
144
+ const bindings = new Map(this.bindings).set(action, token);
145
+ const conflicts = this.conflicts(bindings);
146
+ if (this.policy === 'error' && conflicts.length)
147
+ throw new ShortcutConflictError(conflicts);
148
+ this.commit(this.commands, bindings);
149
+ return () => {
150
+ if (this.disposed || this.bindings.get(action) !== token)
151
+ return;
152
+ const remaining = new Map(this.bindings);
153
+ remaining.delete(action);
154
+ this.commit(this.commands, remaining);
155
+ };
156
+ }
157
+ registerCommand(command) {
158
+ this.alive();
159
+ const entry = this.entry(command);
160
+ if (this.commands.has(command.id))
161
+ throw new Error(`Duplicate command: ${command.id}`);
162
+ this.commit(new Map(this.commands).set(command.id, entry), this.bindings);
163
+ return () => {
164
+ if (this.disposed || this.commands.get(command.id) !== entry)
165
+ return;
166
+ const commands = new Map(this.commands), bindings = new Map(this.bindings);
167
+ commands.delete(command.id);
168
+ bindings.delete(command.id);
169
+ this.commit(commands, bindings);
170
+ };
171
+ }
172
+ getCommand(id) {
173
+ return isWorkspaceAction(id) ? undefined : this.commands.get(id);
174
+ }
175
+ getCommands() {
176
+ return Object.freeze([...this.commands.values()].map(({ definition }) => Object.freeze({ id: definition.id, label: definition.label })));
177
+ }
178
+ getShortcuts() {
179
+ return this.ordered();
180
+ }
181
+ getShortcutConflicts() {
182
+ return this.conflicts();
183
+ }
184
+ subscribe(listener) {
185
+ this.listeners.add(listener);
186
+ return () => {
187
+ this.listeners.delete(listener);
188
+ };
189
+ }
190
+ dispose() {
191
+ if (this.disposed)
192
+ return;
193
+ this.disposed = true;
194
+ const entries = [...this.commands.values()];
195
+ this.commands.clear();
196
+ this.bindings.clear();
197
+ this.listeners.clear();
198
+ for (const entry of entries)
199
+ entry.controller.abort();
200
+ }
201
+ }
202
+ //# sourceMappingURL=command-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-registry.js","sourceRoot":"","sources":["../src/command-registry.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n CommandId,\n CustomCommandId,\n CommandRegistration,\n RegisteredCommand,\n RegisteredShortcut,\n ShortcutRegistration,\n ShortcutConflict,\n ShortcutConflictPolicy,\n WorkspaceSettings,\n LayoutOptionUpdates,\n} from './types.js';\nimport {\n actionOrder,\n isWorkspaceAction,\n registeredShortcuts,\n formatShortcut,\n} from './shortcut-registration.js';\n\nexport class ShortcutConflictError extends Error {\n readonly code = 'SHORTCUT_CONFLICT';\n constructor(readonly conflicts: readonly ShortcutConflict[]) {\n super(\n `Conflicting shortcuts: ${conflicts.map(({ binding, actions }) => `${formatShortcut(binding)} (${actions.join(', ')})`).join('; ')}`,\n );\n this.name = 'ShortcutConflictError';\n }\n}\ntype CommandEntry = { definition: Readonly<CommandRegistration>; controller: AbortController };\ntype Settings = Pick<\n LayoutOptionUpdates,\n 'commands' | 'shortcuts' | 'shortcutConflictPolicy' | 'onShortcutConflict'\n>;\n\n/** Per-workspace state shared by the menu, keyboard listener, and public API. */\nexport class CommandRegistry {\n private commands = new Map<CustomCommandId, CommandEntry>();\n private bindings = new Map<CommandId, RegisteredShortcut>();\n private policy: ShortcutConflictPolicy = 'priority';\n private warn: WorkspaceSettings['onShortcutConflict'];\n private listeners = new Set<() => void>();\n private disposed = false;\n constructor(\n settings: Settings,\n private report: (error: unknown) => void,\n ) {\n this.prepare(settings)();\n }\n private alive() {\n if (this.disposed) throw new Error('Command registry has been disposed');\n }\n private entry(command: CommandRegistration): CommandEntry {\n if (\n !command ||\n typeof command.id !== 'string' ||\n !/^[^.\\s]+(?:\\.[^.\\s]+)+$/.test(command.id) ||\n typeof command.label !== 'string' ||\n !command.label.trim() ||\n typeof command.execute !== 'function' ||\n (command.enabled !== undefined && typeof command.enabled !== 'function')\n )\n throw new Error('A custom command needs a namespaced id, label, and execute callback');\n return { definition: Object.freeze({ ...command }), controller: new AbortController() };\n }\n private ordered(\n bindings = this.bindings,\n commands = this.commands,\n ): readonly RegisteredShortcut[] {\n return Object.freeze(\n [...actionOrder, ...commands.keys()].flatMap((id) => {\n const entry = bindings.get(id);\n return entry?.bindings.length ? [entry] : [];\n }),\n );\n }\n private conflicts(\n bindings = this.bindings,\n commands = this.commands,\n ): readonly ShortcutConflict[] {\n const keys = new Map<\n string,\n { binding: RegisteredShortcut['bindings'][number]; actions: CommandId[] }\n >();\n for (const entry of this.ordered(bindings, commands))\n for (const binding of entry.bindings) {\n const normalized = Object.freeze({ ...binding, key: binding.key.toLowerCase() });\n const key = JSON.stringify([\n normalized.key,\n !!binding.ctrl,\n !!binding.alt,\n !!binding.shift,\n !!binding.meta,\n ]);\n const item = keys.get(key) ?? { binding: normalized, actions: [] };\n if (!item.actions.includes(entry.action)) item.actions.push(entry.action);\n keys.set(key, item);\n }\n return Object.freeze(\n [...keys.values()]\n .filter((item) => item.actions.length > 1)\n .map((item) =>\n Object.freeze({ binding: item.binding, actions: Object.freeze(item.actions) }),\n ),\n );\n }\n /** Validate now; the renderer commits after validating its other options. */\n prepare(next: Settings): () => void {\n this.alive();\n let commands = this.commands;\n if ('commands' in next) {\n commands = new Map();\n for (const command of next.commands ?? []) {\n const entry = this.entry(command);\n if (commands.has(command.id)) throw new Error(`Duplicate command: ${command.id}`);\n const previous = this.commands.get(command.id);\n commands.set(\n command.id,\n previous &&\n previous.definition.execute === command.execute &&\n previous.definition.enabled === command.enabled\n ? { definition: entry.definition, controller: previous.controller }\n : entry,\n );\n }\n }\n let bindings = new Map(this.bindings);\n for (const id of bindings.keys())\n if (!isWorkspaceAction(id) && !commands.has(id)) bindings.delete(id);\n if ('shortcuts' in next)\n bindings = new Map(\n registeredShortcuts({ shortcuts: next.shortcuts }, [...commands.keys()]).map((entry) => [\n entry.action,\n entry,\n ]),\n );\n const policy =\n 'shortcutConflictPolicy' in next ? (next.shortcutConflictPolicy ?? 'priority') : this.policy;\n if (!['priority', 'warn', 'error'].includes(policy))\n throw new Error('Invalid shortcut conflict policy');\n const warn = 'onShortcutConflict' in next ? next.onShortcutConflict : this.warn;\n const conflicts = this.conflicts(bindings, commands);\n if (policy === 'error' && conflicts.length) throw new ShortcutConflictError(conflicts);\n return () => this.commit(commands, bindings, policy, warn);\n }\n private commit(\n commands: Map<CustomCommandId, CommandEntry>,\n bindings: Map<CommandId, RegisteredShortcut>,\n policy = this.policy,\n warn = this.warn,\n ) {\n const before = JSON.stringify(this.getShortcutConflicts());\n const previousPolicy = this.policy;\n const liveControllers = new Set([...commands.values()].map((entry) => entry.controller));\n const removed = [...this.commands.values()].filter(\n (entry) => !liveControllers.has(entry.controller),\n );\n this.commands = commands;\n this.bindings = bindings;\n this.policy = policy;\n this.warn = warn;\n for (const entry of removed) entry.controller.abort();\n for (const listener of [...this.listeners]) {\n try {\n listener();\n } catch (error) {\n this.report(error);\n }\n }\n const conflicts = this.getShortcutConflicts();\n if (\n policy === 'warn' &&\n conflicts.length &&\n (before !== JSON.stringify(conflicts) || previousPolicy !== policy)\n ) {\n try {\n if (warn) warn(conflicts);\n else console.warn(new ShortcutConflictError(conflicts));\n } catch (error) {\n this.report(error);\n }\n }\n }\n registerShortcut(action: CommandId, registration: ShortcutRegistration): () => void {\n this.alive();\n if (!isWorkspaceAction(action) && !this.commands.has(action))\n throw new Error(`Unknown shortcut command: ${action}`);\n const normalized = registeredShortcuts({ shortcuts: { [action]: registration } }, [\n ...this.commands.keys(),\n ])[0];\n const token: RegisteredShortcut =\n normalized ?? Object.freeze({ action, bindings: Object.freeze([]), handling: 'quilt' });\n const bindings = new Map(this.bindings).set(action, token);\n const conflicts = this.conflicts(bindings);\n if (this.policy === 'error' && conflicts.length) throw new ShortcutConflictError(conflicts);\n this.commit(this.commands, bindings);\n return () => {\n if (this.disposed || this.bindings.get(action) !== token) return;\n const remaining = new Map(this.bindings);\n remaining.delete(action);\n this.commit(this.commands, remaining);\n };\n }\n registerCommand(command: CommandRegistration): () => void {\n this.alive();\n const entry = this.entry(command);\n if (this.commands.has(command.id)) throw new Error(`Duplicate command: ${command.id}`);\n this.commit(new Map(this.commands).set(command.id, entry), this.bindings);\n return () => {\n if (this.disposed || this.commands.get(command.id) !== entry) return;\n const commands = new Map(this.commands),\n bindings = new Map(this.bindings);\n commands.delete(command.id);\n bindings.delete(command.id);\n this.commit(commands, bindings);\n };\n }\n getCommand(id: CommandId) {\n return isWorkspaceAction(id) ? undefined : this.commands.get(id);\n }\n getCommands(): readonly RegisteredCommand[] {\n return Object.freeze(\n [...this.commands.values()].map(({ definition }) =>\n Object.freeze({ id: definition.id, label: definition.label }),\n ),\n );\n }\n getShortcuts() {\n return this.ordered();\n }\n getShortcutConflicts() {\n return this.conflicts();\n }\n subscribe(listener: () => void) {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n }\n dispose() {\n if (this.disposed) return;\n this.disposed = true;\n const entries = [...this.commands.values()];\n this.commands.clear();\n this.bindings.clear();\n this.listeners.clear();\n for (const entry of entries) entry.controller.abort();\n }\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { Workspace } from './workspace-api.js';
2
2
  export type { WorkspaceHandle, WorkspaceOptions, WorkspaceOptionUpdates, WorkspaceEvents, WorkspaceChange, PaneHandle, PaneType, PaneTypes, AddPaneOptions, CloseOptions, } from './workspace-api.js';
3
- export type { PaneContext, PaneView, PaneRenderer, TabBarStyle, TabBarOptions, InitialConfiguration, WorkspaceSettings, KeyBinding, CloseRequest, } from './types.js';
3
+ export type { PaneContext, PaneView, PaneRenderer, TabBarStyle, TabBarOptions, InitialConfiguration, WorkspaceSettings, KeyBinding, WorkspaceAction, CommandId, CustomCommandId, CommandContext, CommandRegistration, RegisteredCommand, ShortcutConflict, ShortcutConflictPolicy, ActionContext, RegisteredShortcut, ShortcutRegistration, CloseRequest, } from './types.js';
4
4
  export { TabRegistry } from './registry.js';
5
5
  export type { TabRegistration } from './registry.js';
6
6
  export { themes, themeFamilies } from './theme.js';
@@ -14,4 +14,6 @@ export type { WorkspacePreset } from './workspace.js';
14
14
  export { themeProperties } from './theme.js';
15
15
  export { defaultMessages } from './messages.js';
16
16
  export type { Messages } from './messages.js';
17
+ export { formatShortcut } from './shortcut-registration.js';
18
+ export { ShortcutConflictError } from './command-registry.js';
17
19
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,YAAY,EACV,eAAe,EACf,gBAAgB,EAChB,sBAAsB,EACtB,eAAe,EACf,eAAe,EACf,UAAU,EACV,QAAQ,EACR,SAAS,EACT,cAAc,EACd,YAAY,GACb,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,WAAW,EACX,QAAQ,EACR,YAAY,EACZ,WAAW,EACX,aAAa,EACb,oBAAoB,EACpB,iBAAiB,EACjB,UAAU,EACV,YAAY,GACb,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACnD,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC9E,YAAY,EACV,YAAY,EACZ,IAAI,EACJ,UAAU,EACV,IAAI,EACJ,IAAI,EACJ,KAAK,EACL,KAAK,EACL,IAAI,EACJ,eAAe,EACf,MAAM,EACN,MAAM,IAAI,cAAc,EACxB,KAAK,EACL,cAAc,EACd,MAAM,EACN,MAAM,EACN,WAAW,GACZ,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5D,YAAY,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,YAAY,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,YAAY,EACV,eAAe,EACf,gBAAgB,EAChB,sBAAsB,EACtB,eAAe,EACf,eAAe,EACf,UAAU,EACV,QAAQ,EACR,SAAS,EACT,cAAc,EACd,YAAY,GACb,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,WAAW,EACX,QAAQ,EACR,YAAY,EACZ,WAAW,EACX,aAAa,EACb,oBAAoB,EACpB,iBAAiB,EACjB,UAAU,EACV,eAAe,EACf,SAAS,EACT,eAAe,EACf,cAAc,EACd,mBAAmB,EACnB,iBAAiB,EACjB,gBAAgB,EAChB,sBAAsB,EACtB,aAAa,EACb,kBAAkB,EAClB,oBAAoB,EACpB,YAAY,GACb,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACnD,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC9E,YAAY,EACV,YAAY,EACZ,IAAI,EACJ,UAAU,EACV,IAAI,EACJ,IAAI,EACJ,KAAK,EACL,KAAK,EACL,IAAI,EACJ,eAAe,EACf,MAAM,EACN,MAAM,IAAI,cAAc,EACxB,KAAK,EACL,cAAc,EACd,MAAM,EACN,MAAM,EACN,WAAW,GACZ,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5D,YAAY,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,YAAY,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAE5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC"}
package/dist/index.js CHANGED
@@ -6,4 +6,6 @@ export { PaneRegistry } from './registry.js';
6
6
  export { parseWorkspace, dockLayout } from './workspace.js';
7
7
  export { themeProperties } from './theme.js';
8
8
  export { defaultMessages } from './messages.js';
9
+ export { formatShortcut } from './shortcut-registration.js';
10
+ export { ShortcutConflictError } from './command-registry.js';
9
11
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAyB/C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEnD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAmB9E,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE7C,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE5D,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC","sourcesContent":["export { Workspace } from './workspace-api.js';\nexport type {\n WorkspaceHandle,\n WorkspaceOptions,\n WorkspaceOptionUpdates,\n WorkspaceEvents,\n WorkspaceChange,\n PaneHandle,\n PaneType,\n PaneTypes,\n AddPaneOptions,\n CloseOptions,\n} from './workspace-api.js';\nexport type {\n PaneContext,\n PaneView,\n PaneRenderer,\n TabBarStyle,\n TabBarOptions,\n InitialConfiguration,\n WorkspaceSettings,\n KeyBinding,\n CloseRequest,\n} from './types.js';\n\nexport { TabRegistry } from './registry.js';\nexport type { TabRegistration } from './registry.js';\nexport { themes, themeFamilies } from './theme.js';\nexport type { LayoutTheme } from './theme.js';\nexport { LayoutError, createLayout, parseLayout, validate } from 'quilt-core';\nexport type {\n AutoCollapse,\n Json,\n Capability,\n Axis,\n Pane,\n Group,\n Split,\n Node,\n WindowPlacement,\n Popout,\n Layout as LayoutSnapshot,\n Issue,\n CommandOptions,\n Change,\n Bounds,\n JoinOptions,\n} from 'quilt-core';\nexport { PaneRegistry } from './registry.js';\nexport type { PaneRegistration } from './registry.js';\nexport { parseWorkspace, dockLayout } from './workspace.js';\nexport type { WorkspacePreset } from './workspace.js';\nexport { themeProperties } from './theme.js';\nexport { defaultMessages } from './messages.js';\nexport type { Messages } from './messages.js';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAoC/C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEnD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAmB9E,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE7C,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE5D,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAGhD,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAE5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC","sourcesContent":["export { Workspace } from './workspace-api.js';\nexport type {\n WorkspaceHandle,\n WorkspaceOptions,\n WorkspaceOptionUpdates,\n WorkspaceEvents,\n WorkspaceChange,\n PaneHandle,\n PaneType,\n PaneTypes,\n AddPaneOptions,\n CloseOptions,\n} from './workspace-api.js';\nexport type {\n PaneContext,\n PaneView,\n PaneRenderer,\n TabBarStyle,\n TabBarOptions,\n InitialConfiguration,\n WorkspaceSettings,\n KeyBinding,\n WorkspaceAction,\n CommandId,\n CustomCommandId,\n CommandContext,\n CommandRegistration,\n RegisteredCommand,\n ShortcutConflict,\n ShortcutConflictPolicy,\n ActionContext,\n RegisteredShortcut,\n ShortcutRegistration,\n CloseRequest,\n} from './types.js';\n\nexport { TabRegistry } from './registry.js';\nexport type { TabRegistration } from './registry.js';\nexport { themes, themeFamilies } from './theme.js';\nexport type { LayoutTheme } from './theme.js';\nexport { LayoutError, createLayout, parseLayout, validate } from 'quilt-core';\nexport type {\n AutoCollapse,\n Json,\n Capability,\n Axis,\n Pane,\n Group,\n Split,\n Node,\n WindowPlacement,\n Popout,\n Layout as LayoutSnapshot,\n Issue,\n CommandOptions,\n Change,\n Bounds,\n JoinOptions,\n} from 'quilt-core';\nexport { PaneRegistry } from './registry.js';\nexport type { PaneRegistration } from './registry.js';\nexport { parseWorkspace, dockLayout } from './workspace.js';\nexport type { WorkspacePreset } from './workspace.js';\nexport { themeProperties } from './theme.js';\nexport { defaultMessages } from './messages.js';\nexport type { Messages } from './messages.js';\n\nexport { formatShortcut } from './shortcut-registration.js';\n\nexport { ShortcutConflictError } from './command-registry.js';\n"]}
package/dist/menu.d.ts CHANGED
@@ -1,7 +1,13 @@
1
1
  import type { Group, Pane } from 'quilt-core';
2
- import type { ResolvedLayoutOptions } from './types.js';
3
- import type { Windows } from './windows.js';
4
- export declare function createPaneMenu(root: HTMLElement, options: ResolvedLayoutOptions, windows: Pick<Windows, 'open'>, refresh: () => void, report: (e: unknown) => void, requestClose: (id: string, kind?: 'pane' | 'group') => Promise<boolean>): {
2
+ import type { ResolvedLayoutOptions, ActionContext } from './types.js';
3
+ import type { createActions } from './actions.js';
4
+ export declare function createPaneMenu(root: HTMLElement, options: ResolvedLayoutOptions, refresh: () => void, report: (e: unknown) => void, actions: ReturnType<typeof createActions>): {
5
+ getShortcutTarget: () => {
6
+ dialog: HTMLDialogElement;
7
+ context: ActionContext;
8
+ close(): void;
9
+ } | undefined;
10
+ refreshShortcuts: () => void;
5
11
  open: (anchor: HTMLElement, pane: Pane | undefined, group: Group, direction?: 'left' | 'right' | 'top' | 'bottom', ratio?: number, groupActions?: boolean, addTab?: boolean) => void;
6
12
  addTab(anchor: HTMLElement, group: Group): void;
7
13
  openEmpty(anchor: HTMLElement, group: Group): void;
@@ -1 +1 @@
1
- {"version":3,"file":"menu.d.ts","sourceRoot":"","sources":["../src/menu.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C,wBAAgB,cAAc,CAC5B,IAAI,EAAE,WAAW,EACjB,OAAO,EAAE,qBAAqB,EAC9B,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,EAC9B,OAAO,EAAE,MAAM,IAAI,EACnB,MAAM,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,EAC5B,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC;mBAsB7D,WAAW,QACb,IAAI,GAAG,SAAS,SACf,KAAK,cACA,MAAM,GAAG,OAAO,GAAG,KAAK,GAAG,QAAQ;mBAybhC,WAAW,SAAS,KAAK;sBAYtB,WAAW,SAAS,KAAK;;EAW9C"}
1
+ {"version":3,"file":"menu.d.ts","sourceRoot":"","sources":["../src/menu.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAE,qBAAqB,EAAmB,aAAa,EAAE,MAAM,YAAY,CAAC;AACxF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAGlD,wBAAgB,cAAc,CAC5B,IAAI,EAAE,WAAW,EACjB,OAAO,EAAE,qBAAqB,EAC9B,OAAO,EAAE,MAAM,IAAI,EACnB,MAAM,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,EAC5B,OAAO,EAAE,UAAU,CAAC,OAAO,aAAa,CAAC;;gBAM7B,iBAAiB;iBAAW,aAAa;iBAAW,IAAI;;;mBAkB1D,WAAW,QACb,IAAI,GAAG,SAAS,SACf,KAAK,cACA,MAAM,GAAG,OAAO,GAAG,KAAK,GAAG,QAAQ;mBAugBhC,WAAW,SAAS,KAAK;sBAYtB,WAAW,SAAS,KAAK;;EAW9C"}