quilt-vanilla 0.3.0 → 0.4.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.
- package/dist/actions.d.ts +14 -0
- package/dist/actions.d.ts.map +1 -0
- package/dist/actions.js +115 -0
- package/dist/actions.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/menu.d.ts +9 -3
- package/dist/menu.d.ts.map +1 -1
- package/dist/menu.js +110 -37
- package/dist/menu.js.map +1 -1
- package/dist/renderer.d.ts.map +1 -1
- package/dist/renderer.js +35 -8
- package/dist/renderer.js.map +1 -1
- package/dist/shortcut-registration.d.ts +9 -0
- package/dist/shortcut-registration.d.ts.map +1 -0
- package/dist/shortcut-registration.js +95 -0
- package/dist/shortcut-registration.js.map +1 -0
- package/dist/shortcuts.d.ts +7 -6
- package/dist/shortcuts.d.ts.map +1 -1
- package/dist/shortcuts.js +28 -50
- package/dist/shortcuts.js.map +1 -1
- package/dist/styles.css +25 -9
- package/dist/tabs.d.ts.map +1 -1
- package/dist/tabs.js +10 -12
- package/dist/tabs.js.map +1 -1
- package/dist/types.d.ts +21 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/workspace-api.d.ts +8 -2
- package/dist/workspace-api.d.ts.map +1 -1
- package/dist/workspace-api.js +14 -0
- package/dist/workspace-api.js.map +1 -1
- package/package.json +2 -2
- package/src/actions.ts +125 -0
- package/src/index.ts +6 -0
- package/src/menu.ts +123 -43
- package/src/renderer.ts +41 -7
- package/src/shortcut-registration.ts +106 -0
- package/src/shortcuts.ts +38 -63
- package/src/styles.css +25 -9
- package/src/tabs.ts +9 -11
- package/src/types.ts +43 -5
- package/src/workspace-api.ts +23 -1
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Group, Pane } from 'quilt-core';
|
|
2
|
+
import type { ActionContext, ResolvedLayoutOptions, WorkspaceAction } from './types.js';
|
|
3
|
+
export declare function createActions(options: ResolvedLayoutOptions, dependencies: {
|
|
4
|
+
context(): ActionContext;
|
|
5
|
+
disposed(): boolean;
|
|
6
|
+
create(action: WorkspaceAction, group: Group, pane: Pane | undefined): void;
|
|
7
|
+
close(id: string, kind?: 'pane' | 'group'): Promise<boolean>;
|
|
8
|
+
popout(id: string): Promise<boolean>;
|
|
9
|
+
report(error: unknown): void;
|
|
10
|
+
}): {
|
|
11
|
+
canExecuteAction: (action: WorkspaceAction, context?: ActionContext) => boolean;
|
|
12
|
+
executeAction: (action: WorkspaceAction, context?: ActionContext) => Promise<boolean>;
|
|
13
|
+
};
|
|
14
|
+
//# 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,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"}
|
package/dist/actions.js
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { findNode, findParent, groups, paneIds } from 'quilt-core';
|
|
2
|
+
import { actionOrder } 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
|
+
return { layout, group, pane, valid };
|
|
20
|
+
}
|
|
21
|
+
function canExecuteAction(action, context) {
|
|
22
|
+
if (dependencies.disposed() || !actionOrder.includes(action))
|
|
23
|
+
return false;
|
|
24
|
+
const { layout, group, pane, valid } = resolve(context);
|
|
25
|
+
if (!valid)
|
|
26
|
+
return false;
|
|
27
|
+
if (action === 'restoreClosedTab')
|
|
28
|
+
return options.store.canRestoreClosedTab();
|
|
29
|
+
if (!group)
|
|
30
|
+
return false;
|
|
31
|
+
const allowed = (cap) => group.panes.every((id) => options.store.can(id, cap));
|
|
32
|
+
switch (action) {
|
|
33
|
+
case 'addTab':
|
|
34
|
+
return !!options.tabs?.list().length && allowed('move');
|
|
35
|
+
case 'splitLeft':
|
|
36
|
+
case 'splitRight':
|
|
37
|
+
case 'splitUp':
|
|
38
|
+
case 'splitDown':
|
|
39
|
+
return (!group.panes.length || !!options.tabs?.list().length) && allowed('split');
|
|
40
|
+
case 'closeActiveTab':
|
|
41
|
+
return !!pane && options.store.can(pane.id, 'close');
|
|
42
|
+
case 'closePane':
|
|
43
|
+
return !!group.panes.length && allowed('close');
|
|
44
|
+
case 'closeEmptyPane':
|
|
45
|
+
return !group.panes.length && group.id !== layout.root.id;
|
|
46
|
+
case 'popout':
|
|
47
|
+
return options.popouts !== false && !!pane && options.store.can(pane.id, 'popout');
|
|
48
|
+
case 'joinSiblingRegion': {
|
|
49
|
+
const parent = findParent(layout.root, group.id);
|
|
50
|
+
return !!parent && paneIds(parent).every((id) => options.store.can(id, 'join'));
|
|
51
|
+
}
|
|
52
|
+
default:
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
async function executeAction(action, context) {
|
|
57
|
+
try {
|
|
58
|
+
if (!canExecuteAction(action, context))
|
|
59
|
+
return false;
|
|
60
|
+
const { layout, group, pane } = resolve(context);
|
|
61
|
+
switch (action) {
|
|
62
|
+
case 'restoreClosedTab':
|
|
63
|
+
options.store.restoreClosedTab();
|
|
64
|
+
break;
|
|
65
|
+
case 'maximize':
|
|
66
|
+
options.store.maximize(layout.maximized === group.id ? null : group.id);
|
|
67
|
+
break;
|
|
68
|
+
case 'addTab':
|
|
69
|
+
case 'splitLeft':
|
|
70
|
+
case 'splitRight':
|
|
71
|
+
case 'splitUp':
|
|
72
|
+
case 'splitDown':
|
|
73
|
+
dependencies.create(action, group, pane);
|
|
74
|
+
break;
|
|
75
|
+
case 'closeActiveTab':
|
|
76
|
+
return await dependencies.close(pane.id);
|
|
77
|
+
case 'closePane':
|
|
78
|
+
return await dependencies.close(group.id, 'group');
|
|
79
|
+
case 'closeEmptyPane':
|
|
80
|
+
options.store.removeEmptyGroup(group.id);
|
|
81
|
+
break;
|
|
82
|
+
case 'popout':
|
|
83
|
+
return await dependencies.popout(pane.id);
|
|
84
|
+
case 'joinSiblingRegion':
|
|
85
|
+
options.store.join(group.id, { source: 'user' });
|
|
86
|
+
break;
|
|
87
|
+
case 'tabOrientationDefault':
|
|
88
|
+
options.store.setTabPlacement(group.id, undefined);
|
|
89
|
+
break;
|
|
90
|
+
case 'tabOrientationHorizontal':
|
|
91
|
+
options.store.setTabPlacement(group.id, 'top');
|
|
92
|
+
break;
|
|
93
|
+
case 'tabOrientationVertical':
|
|
94
|
+
options.store.setTabPlacement(group.id, 'left');
|
|
95
|
+
break;
|
|
96
|
+
case 'tabDisplayDefault':
|
|
97
|
+
options.store.setTabDisplay(group.id, undefined);
|
|
98
|
+
break;
|
|
99
|
+
case 'tabDisplayAutomatic':
|
|
100
|
+
options.store.setTabDisplay(group.id, 'automatic');
|
|
101
|
+
break;
|
|
102
|
+
case 'tabDisplayCompact':
|
|
103
|
+
options.store.setTabDisplay(group.id, 'compact');
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
dependencies.report(error);
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return { canExecuteAction, executeAction };
|
|
114
|
+
}
|
|
115
|
+
//# 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 { 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"]}
|
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, 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,5 @@ 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';
|
|
17
18
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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,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"}
|
package/dist/index.js
CHANGED
|
@@ -6,4 +6,5 @@ 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';
|
|
9
10
|
//# 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;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AA6B/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","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 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"]}
|
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 {
|
|
4
|
-
export declare function createPaneMenu(root: HTMLElement, options: ResolvedLayoutOptions,
|
|
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;
|
package/dist/menu.d.ts.map
CHANGED
|
@@ -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;
|
|
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"}
|
package/dist/menu.js
CHANGED
|
@@ -2,10 +2,13 @@ import { message } from './messages.js';
|
|
|
2
2
|
import { actionIcon } from './action-icons.js';
|
|
3
3
|
import { fillTabPicker } from './picker.js';
|
|
4
4
|
import { findNode, findParent, groups, paneIds } from 'quilt-core';
|
|
5
|
+
import { registeredShortcuts, formatShortcut, ariaShortcut } from './shortcut-registration.js';
|
|
5
6
|
import { el, Scope } from './lifetime.js';
|
|
6
|
-
export function createPaneMenu(root, options,
|
|
7
|
+
export function createPaneMenu(root, options, refresh, report, actions) {
|
|
7
8
|
const doc = root.ownerDocument, win = doc.defaultView;
|
|
8
9
|
let current;
|
|
10
|
+
let shortcutTarget;
|
|
11
|
+
let refreshShortcuts = () => { };
|
|
9
12
|
const persistentPickers = new Map();
|
|
10
13
|
const act = (fn) => {
|
|
11
14
|
try {
|
|
@@ -15,11 +18,10 @@ export function createPaneMenu(root, options, windows, refresh, report, requestC
|
|
|
15
18
|
report(error);
|
|
16
19
|
}
|
|
17
20
|
};
|
|
18
|
-
function button(text,
|
|
21
|
+
function button(text, label, action) {
|
|
19
22
|
const b = el(doc, 'button', 'layouts-button', text);
|
|
20
23
|
b.type = 'button';
|
|
21
|
-
b.
|
|
22
|
-
b.setAttribute('aria-label', title);
|
|
24
|
+
b.setAttribute('aria-label', label);
|
|
23
25
|
b.onclick = () => act(action);
|
|
24
26
|
return b;
|
|
25
27
|
}
|
|
@@ -38,17 +40,35 @@ export function createPaneMenu(root, options, windows, refresh, report, requestC
|
|
|
38
40
|
? message(options, '{title} actions', { title: pane.title })
|
|
39
41
|
: message(options, 'Empty pane actions'));
|
|
40
42
|
local.add(() => dialog.remove());
|
|
41
|
-
const
|
|
43
|
+
const context = {
|
|
44
|
+
groupId: group.id,
|
|
45
|
+
...(pane && group.panes.includes(pane.id) ? { paneId: pane.id } : {}),
|
|
46
|
+
};
|
|
47
|
+
const hints = [];
|
|
48
|
+
const bindAction = (element, action) => {
|
|
49
|
+
hints.push({ element, action });
|
|
50
|
+
element.disabled = !actions.canExecuteAction(action, context);
|
|
51
|
+
element.onclick = () => {
|
|
52
|
+
local.dispose();
|
|
53
|
+
void actions.executeAction(action, context);
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
const add = (icon, label, enabled, fn, target = dialog) => {
|
|
42
57
|
const b = button(label, label, () => {
|
|
43
58
|
local.dispose();
|
|
44
|
-
|
|
59
|
+
if (typeof fn === 'function')
|
|
60
|
+
act(fn);
|
|
45
61
|
});
|
|
46
62
|
const glyph = el(doc, 'span', 'layouts-tab-icon');
|
|
47
63
|
glyph.setAttribute('aria-hidden', 'true');
|
|
48
64
|
act(() => glyph.append(actionIcon(doc, icon, options)));
|
|
49
65
|
b.replaceChildren(glyph, el(doc, 'span', '', label.replace(/^\+ /, '')));
|
|
50
66
|
b.disabled = !enabled;
|
|
51
|
-
|
|
67
|
+
if (typeof fn === 'string')
|
|
68
|
+
bindAction(b, fn);
|
|
69
|
+
if (target !== dialog)
|
|
70
|
+
b.setAttribute('role', 'menuitem');
|
|
71
|
+
target.append(b);
|
|
52
72
|
return b;
|
|
53
73
|
};
|
|
54
74
|
const allowed = (cap) => group.panes.every((id) => options.store.can(id, cap));
|
|
@@ -151,7 +171,7 @@ export function createPaneMenu(root, options, windows, refresh, report, requestC
|
|
|
151
171
|
create(direction === 'left' || direction === 'right' ? 'horizontal' : 'vertical', direction === 'left' || direction === 'top');
|
|
152
172
|
return;
|
|
153
173
|
}
|
|
154
|
-
add('add-tab', message(options, '+ Add tab'), available && allowed('move'),
|
|
174
|
+
add('add-tab', message(options, '+ Add tab'), available && allowed('move'), 'addTab');
|
|
155
175
|
const canCreate = !group.panes.length || available;
|
|
156
176
|
const flyouts = [];
|
|
157
177
|
let positionMenus = () => { };
|
|
@@ -170,7 +190,14 @@ export function createPaneMenu(root, options, windows, refresh, report, requestC
|
|
|
170
190
|
flyout.setAttribute('role', 'menu');
|
|
171
191
|
flyout.setAttribute('aria-label', label);
|
|
172
192
|
flyouts.push({ trigger, flyout });
|
|
193
|
+
let closeTimer;
|
|
194
|
+
const cancelClose = () => {
|
|
195
|
+
win.clearTimeout(closeTimer);
|
|
196
|
+
closeTimer = undefined;
|
|
197
|
+
};
|
|
198
|
+
local.add(cancelClose);
|
|
173
199
|
const setOpen = (open) => {
|
|
200
|
+
cancelClose();
|
|
174
201
|
if (open) {
|
|
175
202
|
for (const other of flyouts) {
|
|
176
203
|
other.flyout.hidden = true;
|
|
@@ -186,7 +213,11 @@ export function createPaneMenu(root, options, windows, refresh, report, requestC
|
|
|
186
213
|
if (!trigger.disabled)
|
|
187
214
|
setOpen(true);
|
|
188
215
|
});
|
|
189
|
-
|
|
216
|
+
// Allow the pointer to cross the dialog padding or move diagonally into the flyout.
|
|
217
|
+
local.listen(container, 'pointerleave', () => {
|
|
218
|
+
cancelClose();
|
|
219
|
+
closeTimer = win.setTimeout(() => setOpen(false), 300);
|
|
220
|
+
});
|
|
190
221
|
local.listen(trigger, 'keydown', (event) => {
|
|
191
222
|
if (event.key === 'ArrowRight') {
|
|
192
223
|
event.preventDefault();
|
|
@@ -206,16 +237,14 @@ export function createPaneMenu(root, options, windows, refresh, report, requestC
|
|
|
206
237
|
return flyout;
|
|
207
238
|
}
|
|
208
239
|
const flyout = submenu(message(options, 'Split'), 'split-right', canCreate && allowed('split'));
|
|
209
|
-
for (const [label, axis,
|
|
210
|
-
[message(options, 'Split left'), 'horizontal',
|
|
211
|
-
[message(options, 'Split right'), 'horizontal',
|
|
212
|
-
[message(options, 'Split up'), 'vertical',
|
|
213
|
-
[message(options, 'Split down'), 'vertical',
|
|
240
|
+
for (const [label, axis, action] of [
|
|
241
|
+
[message(options, 'Split left'), 'horizontal', 'splitLeft'],
|
|
242
|
+
[message(options, 'Split right'), 'horizontal', 'splitRight'],
|
|
243
|
+
[message(options, 'Split up'), 'vertical', 'splitUp'],
|
|
244
|
+
[message(options, 'Split down'), 'vertical', 'splitDown'],
|
|
214
245
|
]) {
|
|
215
|
-
const option = button(label, label, () => {
|
|
216
|
-
|
|
217
|
-
create(axis, before);
|
|
218
|
-
});
|
|
246
|
+
const option = button(label, label, () => { });
|
|
247
|
+
bindAction(option, action);
|
|
219
248
|
const icon = el(doc, 'span', 'layouts-tab-icon');
|
|
220
249
|
icon.setAttribute('aria-hidden', 'true');
|
|
221
250
|
icon.append(actionIcon(doc, axis === 'horizontal' ? 'split-right' : 'split-below', options));
|
|
@@ -224,7 +253,7 @@ export function createPaneMenu(root, options, windows, refresh, report, requestC
|
|
|
224
253
|
flyout.append(option);
|
|
225
254
|
}
|
|
226
255
|
const joinParent = findParent(options.store.getSnapshot().root, group.id);
|
|
227
|
-
const join = add('join', message(options, 'Join sibling region'), Boolean(joinParent) && paneIds(joinParent).every((id) => options.store.can(id, 'join')),
|
|
256
|
+
const join = add('join', message(options, 'Join sibling region'), Boolean(joinParent) && paneIds(joinParent).every((id) => options.store.can(id, 'join')), 'joinSiblingRegion');
|
|
228
257
|
let preview;
|
|
229
258
|
const clearPreview = () => {
|
|
230
259
|
preview?.dispose();
|
|
@@ -284,12 +313,9 @@ export function createPaneMenu(root, options, windows, refresh, report, requestC
|
|
|
284
313
|
local.listen(join, 'blur', clearPreview);
|
|
285
314
|
add(options.store.getSnapshot().maximized === group.id ? 'restore' : 'maximize', options.store.getSnapshot().maximized === group.id
|
|
286
315
|
? message(options, 'Restore region')
|
|
287
|
-
: message(options, 'Maximize region'), true,
|
|
316
|
+
: message(options, 'Maximize region'), true, 'maximize');
|
|
288
317
|
if (group.panes.length && pane && options.popouts !== false) {
|
|
289
|
-
add('popout', message(options, 'Open in window'), options.store.can(pane.id, 'popout'),
|
|
290
|
-
void windows.open(pane.id);
|
|
291
|
-
refresh();
|
|
292
|
-
});
|
|
318
|
+
add('popout', message(options, 'Open in window'), options.store.can(pane.id, 'popout'), 'popout');
|
|
293
319
|
}
|
|
294
320
|
const orientation = submenu(message(options, 'Tab orientation'), 'tab-orientation');
|
|
295
321
|
for (const [value, label] of [
|
|
@@ -298,10 +324,12 @@ export function createPaneMenu(root, options, windows, refresh, report, requestC
|
|
|
298
324
|
['left', message(options, 'Vertical')],
|
|
299
325
|
]) {
|
|
300
326
|
const selected = group.tabPlacement === value;
|
|
301
|
-
const option = button(label, label, () => {
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
327
|
+
const option = button(label, label, () => { });
|
|
328
|
+
bindAction(option, value === 'top'
|
|
329
|
+
? 'tabOrientationHorizontal'
|
|
330
|
+
: value === 'left'
|
|
331
|
+
? 'tabOrientationVertical'
|
|
332
|
+
: 'tabOrientationDefault');
|
|
305
333
|
option.setAttribute('role', 'menuitemradio');
|
|
306
334
|
option.setAttribute('aria-checked', String(selected));
|
|
307
335
|
const mark = el(doc, 'span', 'layouts-tab-icon', selected ? '✓' : '');
|
|
@@ -316,10 +344,12 @@ export function createPaneMenu(root, options, windows, refresh, report, requestC
|
|
|
316
344
|
['compact', message(options, 'Compact')],
|
|
317
345
|
]) {
|
|
318
346
|
const selected = group.tabDisplay === value;
|
|
319
|
-
const option = button(label, label, () => {
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
347
|
+
const option = button(label, label, () => { });
|
|
348
|
+
bindAction(option, value === 'automatic'
|
|
349
|
+
? 'tabDisplayAutomatic'
|
|
350
|
+
: value === 'compact'
|
|
351
|
+
? 'tabDisplayCompact'
|
|
352
|
+
: 'tabDisplayDefault');
|
|
323
353
|
option.setAttribute('role', 'menuitemradio');
|
|
324
354
|
option.setAttribute('aria-checked', String(selected));
|
|
325
355
|
const mark = el(doc, 'span', 'layouts-tab-icon', selected ? '✓' : '');
|
|
@@ -328,13 +358,14 @@ export function createPaneMenu(root, options, windows, refresh, report, requestC
|
|
|
328
358
|
display.append(option);
|
|
329
359
|
}
|
|
330
360
|
if (group.panes.length && pane) {
|
|
331
|
-
|
|
332
|
-
add('close', message(options, 'Close
|
|
361
|
+
const close = submenu(message(options, 'Close'), 'close');
|
|
362
|
+
add('close', message(options, 'Close active tab'), options.store.can(pane.id, 'close'), 'closeActiveTab', close);
|
|
363
|
+
add('close', message(options, 'Close pane'), group.panes.every((id) => options.store.can(id, 'close')), 'closePane', close);
|
|
333
364
|
}
|
|
334
365
|
else {
|
|
335
|
-
add('close', message(options, 'Close empty pane'), options.store.getSnapshot().root.id !== group.id,
|
|
366
|
+
add('close', message(options, 'Close empty pane'), options.store.getSnapshot().root.id !== group.id, 'closeEmptyPane');
|
|
336
367
|
}
|
|
337
|
-
add('restore', message(options, 'Restore closed tab'), options.store.canRestoreClosedTab(),
|
|
368
|
+
add('restore', message(options, 'Restore closed tab'), options.store.canRestoreClosedTab(), 'restoreClosedTab');
|
|
338
369
|
add('cancel', message(options, 'Cancel'), true, () => { });
|
|
339
370
|
root.append(dialog);
|
|
340
371
|
// Measure after opening: theme density, labels, and available actions change the size.
|
|
@@ -380,8 +411,48 @@ export function createPaneMenu(root, options, windows, refresh, report, requestC
|
|
|
380
411
|
local.dispose();
|
|
381
412
|
}
|
|
382
413
|
});
|
|
414
|
+
const updateHints = () => {
|
|
415
|
+
const registrations = registeredShortcuts(options);
|
|
416
|
+
for (const { element, action } of hints) {
|
|
417
|
+
element.querySelector('.layouts-shortcut')?.remove();
|
|
418
|
+
element.removeAttribute('aria-keyshortcuts');
|
|
419
|
+
element.disabled = !actions.canExecuteAction(action, context);
|
|
420
|
+
const label = element.getAttribute('aria-label') ?? '';
|
|
421
|
+
const registration = registrations.find((entry) => entry.action === action);
|
|
422
|
+
element.removeAttribute('title');
|
|
423
|
+
if (!registration)
|
|
424
|
+
continue;
|
|
425
|
+
const labels = registration.bindings.map((binding) => {
|
|
426
|
+
try {
|
|
427
|
+
return options.formatShortcut?.(binding) ?? formatShortcut(binding);
|
|
428
|
+
}
|
|
429
|
+
catch (error) {
|
|
430
|
+
report(error);
|
|
431
|
+
return formatShortcut(binding);
|
|
432
|
+
}
|
|
433
|
+
});
|
|
434
|
+
const badge = el(doc, 'kbd', 'layouts-shortcut', labels[0]);
|
|
435
|
+
badge.setAttribute('aria-hidden', 'true');
|
|
436
|
+
element.append(badge);
|
|
437
|
+
element.title = `${label} (${labels.join(' / ')})`;
|
|
438
|
+
if (!element.disabled)
|
|
439
|
+
element.setAttribute('aria-keyshortcuts', registration.bindings.map(ariaShortcut).join(' '));
|
|
440
|
+
}
|
|
441
|
+
positionMenus();
|
|
442
|
+
};
|
|
443
|
+
refreshShortcuts = updateHints;
|
|
444
|
+
local.add(() => {
|
|
445
|
+
if (refreshShortcuts === updateHints)
|
|
446
|
+
refreshShortcuts = () => { };
|
|
447
|
+
});
|
|
448
|
+
const target = { dialog, context, close: () => local.dispose() };
|
|
449
|
+
shortcutTarget = target;
|
|
450
|
+
local.add(() => {
|
|
451
|
+
if (shortcutTarget === target)
|
|
452
|
+
shortcutTarget = undefined;
|
|
453
|
+
});
|
|
383
454
|
dialog.showModal();
|
|
384
|
-
|
|
455
|
+
updateHints();
|
|
385
456
|
const observer = new win.ResizeObserver(positionMenus);
|
|
386
457
|
observer.observe(dialog);
|
|
387
458
|
observer.observe(anchor);
|
|
@@ -397,6 +468,8 @@ export function createPaneMenu(root, options, windows, refresh, report, requestC
|
|
|
397
468
|
dialog.focus({ preventScroll: true });
|
|
398
469
|
}
|
|
399
470
|
return {
|
|
471
|
+
getShortcutTarget: () => shortcutTarget,
|
|
472
|
+
refreshShortcuts: () => refreshShortcuts(),
|
|
400
473
|
open,
|
|
401
474
|
addTab(anchor, group) {
|
|
402
475
|
const layout = options.store.getSnapshot();
|