quilt-vanilla 0.4.0 → 0.6.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 (65) hide show
  1. package/dist/actions.d.ts +6 -3
  2. package/dist/actions.d.ts.map +1 -1
  3. package/dist/actions.js +48 -13
  4. package/dist/actions.js.map +1 -1
  5. package/dist/close.d.ts.map +1 -1
  6. package/dist/close.js +6 -2
  7. package/dist/close.js.map +1 -1
  8. package/dist/command-registry.d.ts +39 -0
  9. package/dist/command-registry.d.ts.map +1 -0
  10. package/dist/command-registry.js +202 -0
  11. package/dist/command-registry.js.map +1 -0
  12. package/dist/corners.d.ts.map +1 -1
  13. package/dist/corners.js +4 -5
  14. package/dist/corners.js.map +1 -1
  15. package/dist/default-shortcuts.d.ts +8 -0
  16. package/dist/default-shortcuts.d.ts.map +1 -0
  17. package/dist/default-shortcuts.js +8 -0
  18. package/dist/default-shortcuts.js.map +1 -0
  19. package/dist/index.d.ts +4 -2
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +2 -0
  22. package/dist/index.js.map +1 -1
  23. package/dist/menu.js +6 -4
  24. package/dist/menu.js.map +1 -1
  25. package/dist/renderer.d.ts.map +1 -1
  26. package/dist/renderer.js +59 -20
  27. package/dist/renderer.js.map +1 -1
  28. package/dist/shortcut-registration.d.ts +3 -2
  29. package/dist/shortcut-registration.d.ts.map +1 -1
  30. package/dist/shortcut-registration.js +14 -4
  31. package/dist/shortcut-registration.js.map +1 -1
  32. package/dist/shortcuts.d.ts +2 -2
  33. package/dist/shortcuts.d.ts.map +1 -1
  34. package/dist/shortcuts.js +2 -3
  35. package/dist/shortcuts.js.map +1 -1
  36. package/dist/styles.css +45 -2
  37. package/dist/tabs.d.ts.map +1 -1
  38. package/dist/tabs.js +7 -4
  39. package/dist/tabs.js.map +1 -1
  40. package/dist/types.d.ts +39 -4
  41. package/dist/types.d.ts.map +1 -1
  42. package/dist/types.js.map +1 -1
  43. package/dist/windows.d.ts.map +1 -1
  44. package/dist/windows.js +2 -2
  45. package/dist/windows.js.map +1 -1
  46. package/dist/workspace-api.d.ts +22 -8
  47. package/dist/workspace-api.d.ts.map +1 -1
  48. package/dist/workspace-api.js +64 -3
  49. package/dist/workspace-api.js.map +1 -1
  50. package/package.json +2 -2
  51. package/src/actions.ts +59 -17
  52. package/src/close.ts +6 -2
  53. package/src/command-registry.ts +248 -0
  54. package/src/corners.ts +4 -9
  55. package/src/default-shortcuts.ts +7 -0
  56. package/src/index.ts +12 -0
  57. package/src/menu.ts +5 -5
  58. package/src/renderer.ts +58 -23
  59. package/src/shortcut-registration.ts +20 -6
  60. package/src/shortcuts.ts +10 -6
  61. package/src/styles.css +45 -2
  62. package/src/tabs.ts +7 -6
  63. package/src/types.ts +39 -4
  64. package/src/windows.ts +2 -1
  65. package/src/workspace-api.ts +88 -10
package/dist/actions.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import type { Group, Pane } from 'quilt-core';
2
- import type { ActionContext, ResolvedLayoutOptions, WorkspaceAction } from './types.js';
2
+ import type { ActionContext, CommandId, ResolvedLayoutOptions, WorkspaceAction } from './types.js';
3
+ import type { CommandRegistry } from './command-registry.js';
3
4
  export declare function createActions(options: ResolvedLayoutOptions, dependencies: {
5
+ registry: CommandRegistry;
4
6
  context(): ActionContext;
5
7
  disposed(): boolean;
6
8
  create(action: WorkspaceAction, group: Group, pane: Pane | undefined): void;
@@ -8,7 +10,8 @@ export declare function createActions(options: ResolvedLayoutOptions, dependenci
8
10
  popout(id: string): Promise<boolean>;
9
11
  report(error: unknown): void;
10
12
  }): {
11
- canExecuteAction: (action: WorkspaceAction, context?: ActionContext) => boolean;
12
- executeAction: (action: WorkspaceAction, context?: ActionContext) => Promise<boolean>;
13
+ canExecuteAction: (action: CommandId, context?: ActionContext) => boolean;
14
+ executeAction: (action: CommandId, context?: ActionContext) => Promise<boolean>;
15
+ getShortcuts: () => readonly import("./types.js").RegisteredShortcut[];
13
16
  };
14
17
  //# sourceMappingURL=actions.d.ts.map
@@ -1 +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,EAAE,aAAa,EAAE,qBAAqB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAGxF,wBAAgB,aAAa,CAC3B,OAAO,EAAE,qBAAqB,EAC9B,YAAY,EAAE;IACZ,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;+BAsBiC,eAAe,YAAY,aAAa,KAAG,OAAO;4BAgC/C,eAAe,YAAY,aAAa,KAAG,OAAO,CAAC,OAAO,CAAC;EAwDjG"}
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;4BAgDzC,SAAS,YAAY,aAAa,KAAG,OAAO,CAAC,OAAO,CAAC;;EAsE3F"}
package/dist/actions.js CHANGED
@@ -1,5 +1,5 @@
1
- import { findNode, findParent, groups, paneIds } from 'quilt-core';
2
- import { actionOrder } from './shortcut-registration.js';
1
+ import { findNode, findParent, groups } from 'quilt-core';
2
+ import { isWorkspaceAction } from './shortcut-registration.js';
3
3
  export function createActions(options, dependencies) {
4
4
  function resolve(context) {
5
5
  const layout = options.store.getSnapshot();
@@ -16,22 +16,44 @@ export function createActions(options, dependencies) {
16
16
  const pane = paneId ? layout.panes[paneId] : undefined;
17
17
  const valid = !(target.groupId !== undefined && !group) &&
18
18
  !(target.paneId !== undefined && (!pane || !group?.panes.includes(target.paneId)));
19
- return { layout, group, pane, valid };
19
+ const commandContext = {
20
+ ...(group ? { groupId: group.id } : {}),
21
+ ...(pane ? { paneId: pane.id } : {}),
22
+ };
23
+ return { layout, group, pane, valid, commandContext };
20
24
  }
21
25
  function canExecuteAction(action, context) {
22
- if (dependencies.disposed() || !actionOrder.includes(action))
26
+ if (dependencies.disposed())
23
27
  return false;
24
- const { layout, group, pane, valid } = resolve(context);
28
+ const { layout, group, pane, valid, commandContext } = resolve(context);
25
29
  if (!valid)
26
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
+ }
27
47
  if (action === 'restoreClosedTab')
28
48
  return options.store.canRestoreClosedTab();
29
49
  if (!group)
30
50
  return false;
31
- const allowed = (cap) => group.panes.every((id) => options.store.can(id, cap));
51
+ const allowed = (cap) => options.store.canNode(group.id, cap);
32
52
  switch (action) {
53
+ case 'maximize':
54
+ return layout.maximized === group.id || allowed('maximize');
33
55
  case 'addTab':
34
- return !!options.tabs?.list().length && allowed('move');
56
+ return !!options.tabs?.list().length && allowed('addTab');
35
57
  case 'splitLeft':
36
58
  case 'splitRight':
37
59
  case 'splitUp':
@@ -42,12 +64,12 @@ export function createActions(options, dependencies) {
42
64
  case 'closePane':
43
65
  return !!group.panes.length && allowed('close');
44
66
  case 'closeEmptyPane':
45
- return !group.panes.length && group.id !== layout.root.id;
67
+ return !group.panes.length && group.id !== layout.root.id && allowed('close');
46
68
  case 'popout':
47
69
  return options.popouts !== false && !!pane && options.store.can(pane.id, 'popout');
48
70
  case 'joinSiblingRegion': {
49
71
  const parent = findParent(layout.root, group.id);
50
- return !!parent && paneIds(parent).every((id) => options.store.can(id, 'join'));
72
+ return !!parent && options.store.canNode(parent.id, 'join');
51
73
  }
52
74
  default:
53
75
  return true;
@@ -57,13 +79,22 @@ export function createActions(options, dependencies) {
57
79
  try {
58
80
  if (!canExecuteAction(action, context))
59
81
  return false;
60
- const { layout, group, pane } = resolve(context);
82
+ const { layout, group, pane, commandContext } = resolve(context);
83
+ if (!isWorkspaceAction(action)) {
84
+ const entry = dependencies.registry.getCommand(action);
85
+ if (!entry || entry.controller.signal.aborted)
86
+ return false;
87
+ const result = await entry.definition.execute(Object.freeze({ ...commandContext, signal: entry.controller.signal }));
88
+ return result !== false && !entry.controller.signal.aborted;
89
+ }
61
90
  switch (action) {
62
91
  case 'restoreClosedTab':
63
92
  options.store.restoreClosedTab();
64
93
  break;
65
94
  case 'maximize':
66
- options.store.maximize(layout.maximized === group.id ? null : group.id);
95
+ options.store.maximize(layout.maximized === group.id ? null : group.id, {
96
+ source: 'user',
97
+ });
67
98
  break;
68
99
  case 'addTab':
69
100
  case 'splitLeft':
@@ -77,7 +108,7 @@ export function createActions(options, dependencies) {
77
108
  case 'closePane':
78
109
  return await dependencies.close(group.id, 'group');
79
110
  case 'closeEmptyPane':
80
- options.store.removeEmptyGroup(group.id);
111
+ options.store.removeEmptyGroup(group.id, { source: 'user' });
81
112
  break;
82
113
  case 'popout':
83
114
  return await dependencies.popout(pane.id);
@@ -110,6 +141,10 @@ export function createActions(options, dependencies) {
110
141
  return false;
111
142
  }
112
143
  }
113
- return { canExecuteAction, executeAction };
144
+ return {
145
+ canExecuteAction,
146
+ executeAction,
147
+ getShortcuts: () => dependencies.registry.getShortcuts(),
148
+ };
114
149
  }
115
150
  //# sourceMappingURL=actions.js.map
@@ -1 +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 { ActionContext, ResolvedLayoutOptions, WorkspaceAction } from './types.js';\nimport { actionOrder } from './shortcut-registration.js';\n\nexport function createActions(\n options: ResolvedLayoutOptions,\n dependencies: {\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 return { layout, group, pane, valid };\n }\n function canExecuteAction(action: WorkspaceAction, context?: ActionContext): boolean {\n if (dependencies.disposed() || !actionOrder.includes(action)) return false;\n const { layout, group, pane, valid } = resolve(context);\n if (!valid) return false;\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: WorkspaceAction, context?: ActionContext): Promise<boolean> {\n try {\n if (!canExecuteAction(action, context)) return false;\n const { layout, group, pane } = resolve(context);\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 { canExecuteAction, executeAction };\n}\n"]}
1
+ {"version":3,"file":"actions.js","sourceRoot":"","sources":["../src/actions.ts"],"names":[],"mappings":"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","sourcesContent":["import { findNode, findParent, groups } 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' | 'addTab' | 'maximize' | 'close') =>\n options.store.canNode(group.id, cap);\n switch (action) {\n case 'maximize':\n return layout.maximized === group.id || allowed('maximize');\n case 'addTab':\n return !!options.tabs?.list().length && allowed('addTab');\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 && allowed('close');\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 && options.store.canNode(parent.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 source: 'user',\n });\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, { source: 'user' });\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"]}
@@ -1 +1 @@
1
- {"version":3,"file":"close.d.ts","sourceRoot":"","sources":["../src/close.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAgB,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACtE,OAAO,EAAM,KAAK,EAAE,MAAM,eAAe,CAAC;AAE1C,wBAAgB,aAAa,CAC3B,IAAI,EAAE,WAAW,EACjB,OAAO,EAAE,qBAAqB,EAC9B,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,QASd,MAAM,SAAQ,MAAM,GAAG,OAAO,KAAY,OAAO,CAAC,OAAO,CAAC,CA0G7E"}
1
+ {"version":3,"file":"close.d.ts","sourceRoot":"","sources":["../src/close.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAgB,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACtE,OAAO,EAAM,KAAK,EAAE,MAAM,eAAe,CAAC;AAE1C,wBAAgB,aAAa,CAC3B,IAAI,EAAE,WAAW,EACjB,OAAO,EAAE,qBAAqB,EAC9B,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,QASd,MAAM,SAAQ,MAAM,GAAG,OAAO,KAAY,OAAO,CAAC,OAAO,CAAC,CA8G7E"}
package/dist/close.js CHANGED
@@ -34,7 +34,9 @@ export function closeRequests(root, options, scope, report) {
34
34
  try {
35
35
  const target = kind === 'group' ? findNode(options.store.getSnapshot().root, id) : undefined;
36
36
  if ((!panes.length && target?.kind !== 'group') ||
37
- panes.some((pane) => !options.store.can(pane.id, 'close')))
37
+ (kind === 'group'
38
+ ? !options.store.canNode(id, 'close')
39
+ : panes.some((pane) => !options.store.can(pane.id, 'close'))))
38
40
  return false;
39
41
  if (requiringConfirmation.length) {
40
42
  const decision = options.confirmClose
@@ -74,7 +76,9 @@ export function closeRequests(root, options, scope, report) {
74
76
  }
75
77
  if (controller.signal.aborted ||
76
78
  signature(collect()) !== signature(panes) ||
77
- panes.some((pane) => !options.store.can(pane.id, 'close')))
79
+ (kind === 'group'
80
+ ? !options.store.canNode(id, 'close')
81
+ : panes.some((pane) => !options.store.can(pane.id, 'close'))))
78
82
  return false;
79
83
  if (kind === 'group')
80
84
  options.store.closeGroup(id, { source: 'user' });
package/dist/close.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"close.js","sourceRoot":"","sources":["../src/close.ts"],"names":[],"mappings":"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","sourcesContent":["import { findNode } from 'quilt-core';\nimport type { Pane } from 'quilt-core';\nimport type { CloseRequest, ResolvedLayoutOptions } from './types.js';\nimport { el, Scope } from './lifetime.js';\nimport { message } from './messages.js';\nexport function closeRequests(\n root: HTMLElement,\n options: ResolvedLayoutOptions,\n scope: Scope,\n report: (error: unknown) => void,\n) {\n let pending: AbortController | undefined;\n let disposed = false;\n scope.add(() => {\n disposed = true;\n pending?.abort();\n });\n const signature = (panes: readonly Pane[]) => JSON.stringify(panes);\n return async (id: string, kind: 'pane' | 'group' = 'pane'): Promise<boolean> => {\n if (pending || disposed) return false;\n const controller = new AbortController();\n pending = controller;\n const collect = (): Pane[] => {\n const snapshot = options.store.getSnapshot();\n const node = kind === 'group' ? findNode(snapshot.root, id) : undefined;\n const ids = kind === 'group' ? (node?.kind === 'group' ? node.panes : []) : [id];\n return ids.map((key) => snapshot.panes[key]).filter((pane): pane is Pane => !!pane);\n };\n const panes = collect();\n const requiringConfirmation = panes.filter(\n (pane) =>\n pane.confirmClose ??\n options.registry?.list().find((entry) => entry.type === pane.type)?.confirmClose ??\n false,\n );\n const request: CloseRequest = {\n panes,\n requiringConfirmation,\n signal: controller.signal,\n ...(kind === 'group' ? { groupId: id } : {}),\n };\n let cleanup = () => {};\n try {\n const target = kind === 'group' ? findNode(options.store.getSnapshot().root, id) : undefined;\n if (\n (!panes.length && target?.kind !== 'group') ||\n panes.some((pane) => !options.store.can(pane.id, 'close'))\n )\n return false;\n if (requiringConfirmation.length) {\n const decision = options.confirmClose\n ? Promise.resolve(options.confirmClose(request))\n : new Promise<boolean>((resolve) => {\n const dialog = el(root.ownerDocument, 'dialog', 'layouts-menu layouts-confirm');\n dialog.setAttribute('aria-label', message(options, 'Close selected panes?'));\n const title = el(\n root.ownerDocument,\n 'h2',\n '',\n message(options, 'Close selected panes?'),\n );\n const list = el(\n root.ownerDocument,\n 'p',\n '',\n requiringConfirmation.map((pane) => pane.title).join(', '),\n );\n const cancel = el(\n root.ownerDocument,\n 'button',\n 'layouts-button',\n message(options, 'Cancel'),\n );\n const close = el(\n root.ownerDocument,\n 'button',\n 'layouts-button',\n message(options, 'Close'),\n );\n cancel.type = close.type = 'button';\n cancel.onclick = () => resolve(false);\n close.onclick = () => resolve(true);\n dialog.oncancel = (event) => {\n event.preventDefault();\n resolve(false);\n };\n dialog.append(title, list, cancel, close);\n root.append(dialog);\n cleanup = () => dialog.remove();\n dialog.showModal();\n cancel.focus();\n });\n const aborted = new Promise<boolean>((resolve) =>\n controller.signal.addEventListener('abort', () => resolve(false), { once: true }),\n );\n const unsubscribe = options.store.subscribe((event) => {\n if (event.action === 'load' || signature(collect()) !== signature(panes))\n controller.abort();\n });\n const previousCleanup = cleanup;\n cleanup = () => {\n unsubscribe();\n previousCleanup();\n };\n if (!(await Promise.race([decision, aborted]))) return false;\n }\n if (\n controller.signal.aborted ||\n signature(collect()) !== signature(panes) ||\n panes.some((pane) => !options.store.can(pane.id, 'close'))\n )\n return false;\n if (kind === 'group') options.store.closeGroup(id, { source: 'user' });\n else options.store.close(id, { source: 'user' });\n return true;\n } catch (error) {\n report(error);\n return false;\n } finally {\n cleanup();\n controller.abort();\n if (pending === controller) pending = undefined;\n }\n };\n}\n"]}
1
+ {"version":3,"file":"close.js","sourceRoot":"","sources":["../src/close.ts"],"names":[],"mappings":"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","sourcesContent":["import { findNode } from 'quilt-core';\nimport type { Pane } from 'quilt-core';\nimport type { CloseRequest, ResolvedLayoutOptions } from './types.js';\nimport { el, Scope } from './lifetime.js';\nimport { message } from './messages.js';\nexport function closeRequests(\n root: HTMLElement,\n options: ResolvedLayoutOptions,\n scope: Scope,\n report: (error: unknown) => void,\n) {\n let pending: AbortController | undefined;\n let disposed = false;\n scope.add(() => {\n disposed = true;\n pending?.abort();\n });\n const signature = (panes: readonly Pane[]) => JSON.stringify(panes);\n return async (id: string, kind: 'pane' | 'group' = 'pane'): Promise<boolean> => {\n if (pending || disposed) return false;\n const controller = new AbortController();\n pending = controller;\n const collect = (): Pane[] => {\n const snapshot = options.store.getSnapshot();\n const node = kind === 'group' ? findNode(snapshot.root, id) : undefined;\n const ids = kind === 'group' ? (node?.kind === 'group' ? node.panes : []) : [id];\n return ids.map((key) => snapshot.panes[key]).filter((pane): pane is Pane => !!pane);\n };\n const panes = collect();\n const requiringConfirmation = panes.filter(\n (pane) =>\n pane.confirmClose ??\n options.registry?.list().find((entry) => entry.type === pane.type)?.confirmClose ??\n false,\n );\n const request: CloseRequest = {\n panes,\n requiringConfirmation,\n signal: controller.signal,\n ...(kind === 'group' ? { groupId: id } : {}),\n };\n let cleanup = () => {};\n try {\n const target = kind === 'group' ? findNode(options.store.getSnapshot().root, id) : undefined;\n if (\n (!panes.length && target?.kind !== 'group') ||\n (kind === 'group'\n ? !options.store.canNode(id, 'close')\n : panes.some((pane) => !options.store.can(pane.id, 'close')))\n )\n return false;\n if (requiringConfirmation.length) {\n const decision = options.confirmClose\n ? Promise.resolve(options.confirmClose(request))\n : new Promise<boolean>((resolve) => {\n const dialog = el(root.ownerDocument, 'dialog', 'layouts-menu layouts-confirm');\n dialog.setAttribute('aria-label', message(options, 'Close selected panes?'));\n const title = el(\n root.ownerDocument,\n 'h2',\n '',\n message(options, 'Close selected panes?'),\n );\n const list = el(\n root.ownerDocument,\n 'p',\n '',\n requiringConfirmation.map((pane) => pane.title).join(', '),\n );\n const cancel = el(\n root.ownerDocument,\n 'button',\n 'layouts-button',\n message(options, 'Cancel'),\n );\n const close = el(\n root.ownerDocument,\n 'button',\n 'layouts-button',\n message(options, 'Close'),\n );\n cancel.type = close.type = 'button';\n cancel.onclick = () => resolve(false);\n close.onclick = () => resolve(true);\n dialog.oncancel = (event) => {\n event.preventDefault();\n resolve(false);\n };\n dialog.append(title, list, cancel, close);\n root.append(dialog);\n cleanup = () => dialog.remove();\n dialog.showModal();\n cancel.focus();\n });\n const aborted = new Promise<boolean>((resolve) =>\n controller.signal.addEventListener('abort', () => resolve(false), { once: true }),\n );\n const unsubscribe = options.store.subscribe((event) => {\n if (event.action === 'load' || signature(collect()) !== signature(panes))\n controller.abort();\n });\n const previousCleanup = cleanup;\n cleanup = () => {\n unsubscribe();\n previousCleanup();\n };\n if (!(await Promise.race([decision, aborted]))) return false;\n }\n if (\n controller.signal.aborted ||\n signature(collect()) !== signature(panes) ||\n (kind === 'group'\n ? !options.store.canNode(id, 'close')\n : panes.some((pane) => !options.store.can(pane.id, 'close')))\n )\n return false;\n if (kind === 'group') options.store.closeGroup(id, { source: 'user' });\n else options.store.close(id, { source: 'user' });\n return true;\n } catch (error) {\n report(error);\n return false;\n } finally {\n cleanup();\n controller.abort();\n if (pending === controller) pending = undefined;\n }\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"]}
@@ -1 +1 @@
1
- {"version":3,"file":"corners.d.ts","sourceRoot":"","sources":["../src/corners.ts"],"names":[],"mappings":"AACA,OAAO,EAAY,MAAM,EAAgC,MAAM,YAAY,CAAC;AAC5E,OAAO,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,EAAM,KAAK,EAAE,MAAM,eAAe,CAAC;AAC1C,KAAK,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,GAAG,QAAQ,CAAC;AACrD,uFAAuF;AACvF,wBAAgB,WAAW,CACzB,IAAI,EAAE,WAAW,EACjB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,qBAAqB,EAC9B,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,GAAG,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,EAC1F,MAAM,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,EAChC,aAAa,GAAE,OAAO,MAAe,QAwQtC"}
1
+ {"version":3,"file":"corners.d.ts","sourceRoot":"","sources":["../src/corners.ts"],"names":[],"mappings":"AACA,OAAO,EAAY,MAAM,EAAgC,MAAM,YAAY,CAAC;AAC5E,OAAO,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,EAAM,KAAK,EAAE,MAAM,eAAe,CAAC;AAC1C,KAAK,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,GAAG,QAAQ,CAAC;AACrD,uFAAuF;AACvF,wBAAgB,WAAW,CACzB,IAAI,EAAE,WAAW,EACjB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,qBAAqB,EAC9B,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,GAAG,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,EAC1F,MAAM,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,EAChC,aAAa,GAAE,OAAO,MAAe,QAmQtC"}
package/dist/corners.js CHANGED
@@ -7,7 +7,7 @@ export function bindCorners(host, id, options, scope, split, report, measureBoun
7
7
  let drag;
8
8
  scope.add(() => drag?.dispose());
9
9
  const initial = findNode(options.store.getSnapshot().root, id);
10
- if (initial?.kind !== 'group' || !initial.panes.every((p) => options.store.can(p, 'split')))
10
+ if (initial?.kind !== 'group' || !options.store.canNode(initial.id, 'split'))
11
11
  return;
12
12
  for (const corner of ['tl', 'tr', 'bl', 'br']) {
13
13
  const handle = el(doc, 'button', 'layouts-corner');
@@ -22,7 +22,7 @@ export function bindCorners(host, id, options, scope, split, report, measureBoun
22
22
  if (start.button !== 0)
23
23
  return;
24
24
  const node = findNode(options.store.getSnapshot().root, id);
25
- if (node?.kind !== 'group' || !node.panes.every((p) => options.store.can(p, 'split')))
25
+ if (node?.kind !== 'group' || !options.store.canNode(node.id, 'split'))
26
26
  return;
27
27
  event.preventDefault();
28
28
  event.stopPropagation();
@@ -95,7 +95,7 @@ export function bindCorners(host, id, options, scope, split, report, measureBoun
95
95
  const max = horizontal ? constraints.maxWidth : constraints.maxHeight;
96
96
  const total = horizontal ? rect.width : rect.height;
97
97
  const disabled = current.kind === 'group' &&
98
- (!current.panes.every((p) => options.store.can(p, 'resize')) || min === max);
98
+ (!options.store.canNode(current.id, 'resize') || min === max);
99
99
  const configuredGap = parseFloat(doc
100
100
  .defaultView.getComputedStyle(host.closest('.layouts'))
101
101
  .getPropertyValue(disabled
@@ -140,8 +140,7 @@ export function bindCorners(host, id, options, scope, split, report, measureBoun
140
140
  return;
141
141
  const receiverId = hovered.dataset.nodeId;
142
142
  const range = joinRange(layout.root, id, receiverId);
143
- if (!range ||
144
- !range.selected.every((g) => g.panes.every((p) => options.store.can(p, 'join'))))
143
+ if (!range || !range.selected.every((g) => options.store.canNode(g.id, 'join')))
145
144
  return;
146
145
  const receiver = findNode(layout.root, receiverId);
147
146
  if (receiver?.kind !== 'group')