quilt-vanilla 0.2.3 → 0.3.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/README.md +36 -40
- package/dist/chrome-size.d.ts +7 -0
- package/dist/chrome-size.d.ts.map +1 -0
- package/dist/chrome-size.js +86 -0
- package/dist/chrome-size.js.map +1 -0
- package/dist/close.d.ts.map +1 -1
- package/dist/close.js +3 -1
- package/dist/close.js.map +1 -1
- package/dist/corners.d.ts +2 -1
- package/dist/corners.d.ts.map +1 -1
- package/dist/corners.js +2 -2
- package/dist/corners.js.map +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/panes.d.ts.map +1 -1
- package/dist/panes.js +84 -52
- package/dist/panes.js.map +1 -1
- package/dist/registry.d.ts +1 -0
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +4 -3
- package/dist/registry.js.map +1 -1
- package/dist/renderer.d.ts.map +1 -1
- package/dist/renderer.js +94 -29
- package/dist/renderer.js.map +1 -1
- package/dist/resize.d.ts +2 -1
- package/dist/resize.d.ts.map +1 -1
- package/dist/resize.js +2 -2
- package/dist/resize.js.map +1 -1
- package/dist/styles.css +49 -0
- package/dist/types.d.ts +29 -8
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/workspace-api.d.ts +180 -0
- package/dist/workspace-api.d.ts.map +1 -0
- package/dist/workspace-api.js +395 -0
- package/dist/workspace-api.js.map +1 -0
- package/package.json +2 -2
- package/src/chrome-size.ts +99 -0
- package/src/close.ts +6 -1
- package/src/corners.ts +2 -1
- package/src/index.ts +25 -4
- package/src/panes.ts +82 -55
- package/src/registry.ts +6 -4
- package/src/renderer.ts +141 -48
- package/src/resize.ts +2 -1
- package/src/styles.css +49 -0
- package/src/types.ts +24 -9
- package/src/workspace-api.ts +561 -0
package/dist/panes.js
CHANGED
|
@@ -9,66 +9,98 @@ export function mountPane(doc, pane, location, options) {
|
|
|
9
9
|
const renderer = Object.hasOwn(options.renderers ?? {}, pane.type)
|
|
10
10
|
? options.renderers?.[pane.type]
|
|
11
11
|
: undefined;
|
|
12
|
-
let view;
|
|
12
|
+
let view = { dispose() { } };
|
|
13
|
+
let observer;
|
|
14
|
+
let disposed = false;
|
|
15
|
+
const controller = new win.AbortController();
|
|
16
|
+
const cleanups = [];
|
|
17
|
+
const reportCleanup = (error) => {
|
|
18
|
+
try {
|
|
19
|
+
options.onError?.(error);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
/* Finish teardown even if reporting fails. */
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
const run = (callback) => {
|
|
26
|
+
try {
|
|
27
|
+
callback();
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
reportCleanup(error);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
const dispose = () => {
|
|
34
|
+
if (disposed)
|
|
35
|
+
return;
|
|
36
|
+
disposed = true;
|
|
37
|
+
run(() => controller.abort());
|
|
38
|
+
run(() => observer?.disconnect());
|
|
39
|
+
run(() => view.dispose());
|
|
40
|
+
for (const cleanup of cleanups.splice(0).reverse())
|
|
41
|
+
run(cleanup);
|
|
42
|
+
element.remove();
|
|
43
|
+
};
|
|
13
44
|
let result;
|
|
14
45
|
const reportError = (error) => {
|
|
15
46
|
if (result)
|
|
16
47
|
result.failed = true;
|
|
17
48
|
options.onError?.(error);
|
|
18
49
|
};
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
options.onError?.(error);
|
|
43
|
-
}
|
|
50
|
+
try {
|
|
51
|
+
if (renderer)
|
|
52
|
+
view = renderer({
|
|
53
|
+
signal: controller.signal,
|
|
54
|
+
onCleanup(callback) {
|
|
55
|
+
if (disposed)
|
|
56
|
+
run(callback);
|
|
57
|
+
else
|
|
58
|
+
cleanups.push(callback);
|
|
59
|
+
},
|
|
60
|
+
element,
|
|
61
|
+
reportError,
|
|
62
|
+
document: doc,
|
|
63
|
+
window: win,
|
|
64
|
+
pane,
|
|
65
|
+
state: options.getPaneState?.(pane.id),
|
|
66
|
+
location,
|
|
67
|
+
}) ?? { dispose() { } };
|
|
68
|
+
else {
|
|
69
|
+
element.append(el(doc, 'div', 'layouts-placeholder', message(options, 'Unknown pane type: {type}. Register a renderer to display this pane.', {
|
|
70
|
+
type: pane.type,
|
|
71
|
+
})));
|
|
72
|
+
view = { dispose() { } };
|
|
44
73
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
dispose() {
|
|
55
|
-
if (disposed)
|
|
56
|
-
return;
|
|
57
|
-
disposed = true;
|
|
58
|
-
observer.disconnect();
|
|
59
|
-
try {
|
|
60
|
-
view.dispose();
|
|
61
|
-
}
|
|
62
|
-
finally {
|
|
63
|
-
element.remove();
|
|
74
|
+
observer = new ResizeObserver((entries) => {
|
|
75
|
+
const rect = entries[0]?.contentRect;
|
|
76
|
+
if (rect) {
|
|
77
|
+
try {
|
|
78
|
+
view.resize?.(rect.width, rect.height);
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
options.onError?.(error);
|
|
82
|
+
}
|
|
64
83
|
}
|
|
65
|
-
},
|
|
66
|
-
};
|
|
67
|
-
if (location === 'main')
|
|
68
|
-
void view.ready?.catch((error) => {
|
|
69
|
-
if (!disposed)
|
|
70
|
-
reportError(error);
|
|
71
84
|
});
|
|
72
|
-
|
|
85
|
+
observer.observe(element);
|
|
86
|
+
result = {
|
|
87
|
+
element,
|
|
88
|
+
view,
|
|
89
|
+
pane,
|
|
90
|
+
signature: JSON.stringify(pane),
|
|
91
|
+
renderer,
|
|
92
|
+
dispose,
|
|
93
|
+
};
|
|
94
|
+
if (location === 'main')
|
|
95
|
+
void view.ready?.catch((error) => {
|
|
96
|
+
if (!disposed)
|
|
97
|
+
reportError(error);
|
|
98
|
+
});
|
|
99
|
+
return result;
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
dispose();
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
73
105
|
}
|
|
74
106
|
//# sourceMappingURL=panes.js.map
|
package/dist/panes.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"panes.js","sourceRoot":"","sources":["../src/panes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAGxC,OAAO,EAAE,EAAE,EAAE,MAAM,eAAe,CAAC;AAUnC,MAAM,UAAU,SAAS,CACvB,GAAa,EACb,IAAU,EACV,QAA2B,EAC3B,OAA8B;IAE9B,MAAM,GAAG,GAAG,GAAG,CAAC,WAAW,CAAC;IAC5B,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;IACxD,MAAM,OAAO,GAAG,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC;IAC/C,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;IACjC,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,IAAI,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC;QAChE,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC;QAChC,CAAC,CAAC,SAAS,CAAC;IACd,IAAI,
|
|
1
|
+
{"version":3,"file":"panes.js","sourceRoot":"","sources":["../src/panes.ts"],"names":[],"mappings":"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","sourcesContent":["import { message } from './messages.js';\nimport type { Pane } from 'quilt-core';\nimport type { ResolvedLayoutOptions, PaneView, PaneRenderer } from './types.js';\nimport { el } from './lifetime.js';\nexport interface MountedPane {\n element: HTMLElement;\n view: PaneView;\n pane: Pane;\n signature: string;\n renderer: PaneRenderer | undefined;\n failed?: boolean;\n dispose(): void;\n}\nexport function mountPane(\n doc: Document,\n pane: Pane,\n location: 'main' | 'popout',\n options: ResolvedLayoutOptions,\n): MountedPane {\n const win = doc.defaultView;\n if (!win) throw new Error('Pane needs a live document');\n const element = el(doc, 'div', 'layouts-pane');\n element.dataset.paneId = pane.id;\n const renderer = Object.hasOwn(options.renderers ?? {}, pane.type)\n ? options.renderers?.[pane.type]\n : undefined;\n let view: PaneView = { dispose() {} };\n let observer: ResizeObserver | undefined;\n let disposed = false;\n const controller = new (win as Window & typeof globalThis).AbortController();\n const cleanups: (() => void)[] = [];\n const reportCleanup = (error: unknown) => {\n try {\n options.onError?.(error);\n } catch {\n /* Finish teardown even if reporting fails. */\n }\n };\n const run = (callback: () => void) => {\n try {\n callback();\n } catch (error) {\n reportCleanup(error);\n }\n };\n const dispose = () => {\n if (disposed) return;\n disposed = true;\n run(() => controller.abort());\n run(() => observer?.disconnect());\n run(() => view.dispose());\n for (const cleanup of cleanups.splice(0).reverse()) run(cleanup);\n element.remove();\n };\n let result: MountedPane | undefined;\n const reportError = (error: unknown) => {\n if (result) result.failed = true;\n options.onError?.(error);\n };\n try {\n if (renderer)\n view = renderer({\n signal: controller.signal,\n onCleanup(callback) {\n if (disposed) run(callback);\n else cleanups.push(callback);\n },\n element,\n reportError,\n document: doc,\n window: win,\n pane,\n state: options.getPaneState?.(pane.id),\n location,\n }) ?? { dispose() {} };\n else {\n element.append(\n el(\n doc,\n 'div',\n 'layouts-placeholder',\n message(options, 'Unknown pane type: {type}. Register a renderer to display this pane.', {\n type: pane.type,\n }),\n ),\n );\n view = { dispose() {} };\n }\n observer = new ResizeObserver((entries) => {\n const rect = entries[0]?.contentRect;\n if (rect) {\n try {\n view.resize?.(rect.width, rect.height);\n } catch (error) {\n options.onError?.(error);\n }\n }\n });\n observer.observe(element);\n result = {\n element,\n view,\n pane,\n signature: JSON.stringify(pane),\n renderer,\n dispose,\n };\n if (location === 'main')\n void view.ready?.catch((error) => {\n if (!disposed) reportError(error);\n });\n return result;\n } catch (error) {\n dispose();\n throw error;\n }\n}\n"]}
|
package/dist/registry.d.ts
CHANGED
package/dist/registry.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AACvC,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7B;2EACuE;IACvE,MAAM,EAAE,CAAC,OAAO,EAAE;QAAE,MAAM,EAAE,IAAI,GAAG,SAAS,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,GAAG,SAAS,CAAC;CACtF;AACD,mFAAmF;AACnF,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAAsC;IACrD,OAAO,CAAC,SAAS,CAAyB;IAC1C,YAAY,OAAO,GAAE,SAAS,eAAe,EAAO,EAEnD;IACD,IAAI,IAAI,SAAS,eAAe,EAAE,CAEjC;IACD,QAAQ,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,IAAI,CAc3C;IACD,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAK1C;IACD,OAAO,CAAC,IAAI;CAGb;
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AACvC,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7B;2EACuE;IACvE,MAAM,EAAE,CAAC,OAAO,EAAE;QAAE,MAAM,EAAE,IAAI,GAAG,SAAS,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,GAAG,SAAS,CAAC;CACtF;AACD,mFAAmF;AACnF,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAAsC;IACrD,OAAO,CAAC,SAAS,CAAyB;IAC1C,YAAY,OAAO,GAAE,SAAS,eAAe,EAAO,EAEnD;IACD,IAAI,IAAI,SAAS,eAAe,EAAE,CAEjC;IACD,QAAQ,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,IAAI,CAc3C;IACD,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAK1C;IACD,OAAO,CAAC,IAAI;CAGb;AAGD,wBAAgB,YAAY,IAAI,MAAM,CAIrC;AAED,MAAM,WAAW,gBAAgB,CAAC,CAAC;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,CAAC,CAAC;IACR,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,UAAU,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC;CAC3F;AACD,2EAA2E;AAC3E,qBAAa,YAAY,CAAC,CAAC;IACzB,OAAO,CAAC,OAAO,CAAoD;IACnE,OAAO,CAAC,SAAS,CAAyB;IAC1C,QAAQ,CAAC,IAAI,cAAqB;IAClC,YAAY,OAAO,GAAE,SAAS,gBAAgB,CAAC,CAAC,CAAC,EAAO,EAEvD;IACD,IAAI,IAAI,SAAS,QAAQ,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,EAAE,CAE/C;IACD,QAAQ,CAAC,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,CAiC/C;IACD,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAK1C;IACD,OAAO,CAAC,IAAI;CAGb"}
|
package/dist/registry.js
CHANGED
|
@@ -37,6 +37,9 @@ export class TabRegistry {
|
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
let instanceSequence = 0;
|
|
40
|
+
export function createPaneId() {
|
|
41
|
+
return (globalThis.crypto?.randomUUID?.() ?? `quilt-${Date.now().toString(36)}-${++instanceSequence}`);
|
|
42
|
+
}
|
|
40
43
|
/** Framework-neutral registrations; the adapter supplies the view type. */
|
|
41
44
|
export class PaneRegistry {
|
|
42
45
|
entries = new Map();
|
|
@@ -71,9 +74,7 @@ export class PaneRegistry {
|
|
|
71
74
|
title: stored.title,
|
|
72
75
|
...(stored.icon !== undefined ? { icon: stored.icon } : {}),
|
|
73
76
|
...supplied,
|
|
74
|
-
id: supplied.id ??
|
|
75
|
-
globalThis.crypto?.randomUUID?.() ??
|
|
76
|
-
`quilt-${Date.now().toString(36)}-${++instanceSequence}`,
|
|
77
|
+
id: supplied.id ?? createPaneId(),
|
|
77
78
|
};
|
|
78
79
|
},
|
|
79
80
|
});
|
package/dist/registry.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAWA,mFAAmF;AACnF,MAAM,OAAO,WAAW;IACd,OAAO,GAAG,IAAI,GAAG,EAA2B,CAAC;IAC7C,SAAS,GAAG,IAAI,GAAG,EAAc,CAAC;IAC1C,YAAY,OAAO,GAA+B,EAAE;QAClD,KAAK,MAAM,KAAK,IAAI,OAAO;YAAE,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACpD,CAAC;IACD,IAAI;QACF,OAAO,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACpC,CAAC;IACD,QAAQ,CAAC,KAAsB;QAC7B,IAAI,CAAC,KAAK,CAAC,EAAE,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YACzC,MAAM,IAAI,KAAK,CAAC,wCAAwC,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC;QACtE,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;YAC3B,GAAG,KAAK;YACR,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC5E,CAAC,CAAC;QACH,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QACnC,IAAI,CAAC,IAAI,EAAE,CAAC;QACZ,OAAO,GAAG,EAAE;YACV,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,MAAM;gBAAE,OAAO;YAClD,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAC9B,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,CAAC,CAAC;IACJ,CAAC;IACD,SAAS,CAAC,QAAoB;QAC5B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC7B,OAAO,GAAG,EAAE;YACV,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAClC,CAAC,CAAC;IACJ,CAAC;IACO,IAAI;QACV,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,SAAS;YAAE,QAAQ,EAAE,CAAC;IACpD,CAAC;CACF;AAED,IAAI,gBAAgB,GAAG,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Pane } from 'quilt-core';\nexport interface TabRegistration {\n id: string;\n title: string;\n description?: string;\n icon?: string;\n keywords?: readonly string[];\n /** Source is undefined when creating content in a completely empty workspace.\n * Return a fresh pane with a unique id; undefined cancels creation. */\n create: (context: { source: Pane | undefined; groupId: string }) => Pane | undefined;\n}\n/** Available content types, independent of open pane instances and layout JSON. */\nexport class TabRegistry {\n private entries = new Map<string, TabRegistration>();\n private listeners = new Set<() => void>();\n constructor(entries: readonly TabRegistration[] = []) {\n for (const entry of entries) this.register(entry);\n }\n list(): readonly TabRegistration[] {\n return [...this.entries.values()];\n }\n register(entry: TabRegistration): () => void {\n if (!entry.id || this.entries.has(entry.id))\n throw new Error(`Duplicate or empty tab registration: ${entry.id}`);\n const stored = Object.freeze({\n ...entry,\n ...(entry.keywords ? { keywords: Object.freeze([...entry.keywords]) } : {}),\n });\n this.entries.set(entry.id, stored);\n this.emit();\n return () => {\n if (this.entries.get(entry.id) !== stored) return;\n this.entries.delete(entry.id);\n this.emit();\n };\n }\n subscribe(listener: () => void): () => void {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n }\n private emit() {\n for (const listener of this.listeners) listener();\n }\n}\n\nlet instanceSequence = 0;\nexport function createPaneId(): string {\n return (\n globalThis.crypto?.randomUUID?.() ?? `quilt-${Date.now().toString(36)}-${++instanceSequence}`\n );\n}\n\nexport interface PaneRegistration<T> {\n type: string;\n title: string;\n view: T;\n description?: string;\n icon?: string;\n keywords?: readonly string[];\n confirmClose?: boolean;\n create?: (context: Parameters<TabRegistration['create']>[0]) => Partial<Pane> | undefined;\n}\n/** Framework-neutral registrations; the adapter supplies the view type. */\nexport class PaneRegistry<T> {\n private entries = new Map<string, Readonly<PaneRegistration<T>>>();\n private listeners = new Set<() => void>();\n readonly tabs = new TabRegistry();\n constructor(entries: readonly PaneRegistration<T>[] = []) {\n entries.forEach((entry) => this.register(entry));\n }\n list(): readonly Readonly<PaneRegistration<T>>[] {\n return [...this.entries.values()];\n }\n register(entry: PaneRegistration<T>): () => void {\n if (!entry.type || this.entries.has(entry.type))\n throw new Error(`Duplicate or empty pane type: ${entry.type}`);\n const stored = Object.freeze({\n ...entry,\n ...(entry.keywords ? { keywords: Object.freeze([...entry.keywords]) } : {}),\n });\n this.entries.set(entry.type, stored);\n const removeTab = this.tabs.register({\n id: entry.type,\n title: entry.title,\n ...(entry.description !== undefined ? { description: entry.description } : {}),\n ...(entry.icon !== undefined ? { icon: entry.icon } : {}),\n ...(entry.keywords !== undefined ? { keywords: entry.keywords } : {}),\n create: (context) => {\n const supplied = stored.create ? stored.create(context) : {};\n if (supplied === undefined) return undefined;\n return {\n type: stored.type,\n title: stored.title,\n ...(stored.icon !== undefined ? { icon: stored.icon } : {}),\n ...supplied,\n id: supplied.id ?? createPaneId(),\n };\n },\n });\n this.emit();\n return () => {\n if (this.entries.get(entry.type) !== stored) return;\n this.entries.delete(entry.type);\n removeTab();\n this.emit();\n };\n }\n subscribe(listener: () => void): () => void {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n }\n private emit() {\n for (const listener of [...this.listeners]) listener();\n }\n}\n"]}
|
package/dist/renderer.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../src/renderer.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../src/renderer.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,aAAa,EAAyB,aAAa,EAAe,MAAM,YAAY,CAAC;AAkBnG,wBAAgB,WAAW,CAAC,KAAK,GAAG,OAAO,EACzC,IAAI,EAAE,WAAW,EACjB,KAAK,EAAE,aAAa,CAAC,KAAK,CAAC,GAC1B,aAAa,CAAC,KAAK,CAAC,CAgCtB"}
|
package/dist/renderer.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { chromeMinimum } from './chrome-size.js';
|
|
1
2
|
import { closeRequests } from './close.js';
|
|
2
3
|
import { dockLayout, parseWorkspace } from './workspace.js';
|
|
3
4
|
import { validateTheme, themePixels } from './theme.js';
|
|
@@ -9,17 +10,39 @@ import { bindCorners } from './corners.js';
|
|
|
9
10
|
import { applyTheme } from './theme.js';
|
|
10
11
|
import { fillTabs } from './tabs.js';
|
|
11
12
|
import { bindShortcuts } from './shortcuts.js';
|
|
12
|
-
import { allocate, bounds, DIVIDER, findNode, groups, paneIds } from 'quilt-core';
|
|
13
|
+
import { LayoutStore, createLayout, allocate, bounds as modelBounds, DIVIDER, findNode, groups, paneIds, } from 'quilt-core';
|
|
13
14
|
import { Scope, el, syncChildren } from './lifetime.js';
|
|
14
15
|
import { mountPane } from './panes.js';
|
|
15
16
|
import { Windows } from './windows.js';
|
|
16
17
|
import { createPaneMenu } from './menu.js';
|
|
17
18
|
let nextMount = 0;
|
|
18
19
|
export function mountLayout(host, input) {
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
if ('store' in input)
|
|
21
|
+
throw new Error('Quilt owns its store; pass initialLayout or initialWorkspace');
|
|
22
|
+
if (input.initialLayout !== undefined && input.initialWorkspace !== undefined)
|
|
23
|
+
throw new Error('initialLayout and initialWorkspace are mutually exclusive');
|
|
24
|
+
if (input.registry && (input.renderers || input.tabs))
|
|
25
|
+
throw new Error('registry cannot be combined with renderers or tabs');
|
|
26
|
+
const preset = input.initialWorkspace === undefined ? undefined : parseWorkspace(input.initialWorkspace);
|
|
27
|
+
const theme = preset?.theme ?? input.theme ?? {};
|
|
28
|
+
const tabBar = preset?.tabBar ?? input.tabBar ?? {};
|
|
29
|
+
validateTheme(theme);
|
|
30
|
+
validateTabBar(tabBar);
|
|
31
|
+
const store = new LayoutStore(dockLayout(preset?.layout ?? input.initialLayout ?? createLayout()), {
|
|
32
|
+
autoCollapse: preset?.autoCollapse ?? 'disabled',
|
|
33
|
+
});
|
|
34
|
+
// The initialization scope rolls back even if setup fails before returning a handle.
|
|
35
|
+
const scope = new Scope();
|
|
36
|
+
scope.add(() => store.dispose());
|
|
37
|
+
try {
|
|
38
|
+
return mountLayoutInternal(host, { ...input, store, theme, tabBar }, scope);
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
scope.dispose();
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
21
44
|
}
|
|
22
|
-
function mountLayoutInternal(host, input) {
|
|
45
|
+
function mountLayoutInternal(host, input, scope) {
|
|
23
46
|
const options = { ...input };
|
|
24
47
|
const configure = () => {
|
|
25
48
|
if (options.registry) {
|
|
@@ -37,7 +60,7 @@ function mountLayoutInternal(host, input) {
|
|
|
37
60
|
const doc = host.ownerDocument, win = doc.defaultView;
|
|
38
61
|
if (!win)
|
|
39
62
|
throw new Error('Layout host must belong to a live document');
|
|
40
|
-
const
|
|
63
|
+
const regions = new Map(), panes = new Map();
|
|
41
64
|
const root = el(doc, 'div', 'layouts');
|
|
42
65
|
applyTheme(root, options.theme ?? {});
|
|
43
66
|
root.setAttribute('aria-label', message(options, 'Pane workspace'));
|
|
@@ -46,6 +69,7 @@ function mountLayoutInternal(host, input) {
|
|
|
46
69
|
status.setAttribute('role', 'status');
|
|
47
70
|
root.append(stage, status);
|
|
48
71
|
host.append(root);
|
|
72
|
+
scope.add(() => root.remove());
|
|
49
73
|
let disposed = false, rendering = false, again = false, dragScope;
|
|
50
74
|
let dragId;
|
|
51
75
|
const error = (e) => {
|
|
@@ -65,9 +89,22 @@ function mountLayoutInternal(host, input) {
|
|
|
65
89
|
error(e);
|
|
66
90
|
}
|
|
67
91
|
};
|
|
68
|
-
const
|
|
92
|
+
const closeScope = new Scope();
|
|
93
|
+
scope.add(() => closeScope.dispose());
|
|
94
|
+
const requestClose = closeRequests(root, options, closeScope, error);
|
|
69
95
|
const windows = new Windows(doc, options, error, root);
|
|
96
|
+
scope.add(() => windows.dispose());
|
|
97
|
+
scope.add(() => {
|
|
98
|
+
for (const pane of panes.values())
|
|
99
|
+
pane.dispose();
|
|
100
|
+
panes.clear();
|
|
101
|
+
for (const region of regions.values())
|
|
102
|
+
region.scope.dispose();
|
|
103
|
+
regions.clear();
|
|
104
|
+
});
|
|
70
105
|
const menu = createPaneMenu(root, options, windows, render, error, requestClose);
|
|
106
|
+
scope.add(() => menu.dispose());
|
|
107
|
+
scope.add(() => dragScope?.dispose());
|
|
71
108
|
bindShortcuts(root, options, scope, act, (group) => {
|
|
72
109
|
const region = regions.get(group.id);
|
|
73
110
|
if (region)
|
|
@@ -101,7 +138,7 @@ function mountLayoutInternal(host, input) {
|
|
|
101
138
|
r.header = el(doc, 'header', 'layouts-header');
|
|
102
139
|
r.body = el(doc, 'div', 'layouts-body');
|
|
103
140
|
r.element.append(r.header, r.body);
|
|
104
|
-
r.
|
|
141
|
+
r.tabStyle = () => {
|
|
105
142
|
const current = findNode(options.store.getSnapshot().root, node.id);
|
|
106
143
|
return {
|
|
107
144
|
...tabBar,
|
|
@@ -113,8 +150,9 @@ function mountLayoutInternal(host, input) {
|
|
|
113
150
|
? { placement: current.tabPlacement }
|
|
114
151
|
: {}),
|
|
115
152
|
};
|
|
116
|
-
}
|
|
117
|
-
|
|
153
|
+
};
|
|
154
|
+
r.updateTabBar = bindTabBar(r.element, r.header, root, r.scope, r.tabStyle, () => options.messages ?? {});
|
|
155
|
+
bindCorners(r.element, node.id, options, r.scope, (pane, group, direction, ratio) => menu.open(r.header, pane, group, direction, ratio), error, bounds);
|
|
118
156
|
r.element.setAttribute('aria-label', message(options, 'Pane region'));
|
|
119
157
|
r.scope.listen(r.element, 'dragover', (event) => {
|
|
120
158
|
if (!dragId)
|
|
@@ -169,7 +207,7 @@ function mountLayoutInternal(host, input) {
|
|
|
169
207
|
const resize = isolatedResize(geometryLayout(), node.id, (child, axis) => {
|
|
170
208
|
const rect = regions.get(child.id).element.getBoundingClientRect();
|
|
171
209
|
return axis === 'horizontal' ? rect.width : rect.height;
|
|
172
|
-
});
|
|
210
|
+
}, bounds);
|
|
173
211
|
r.divider.setPointerCapture(e.pointerId);
|
|
174
212
|
root.classList.add('layouts-resizing');
|
|
175
213
|
drag.add(() => {
|
|
@@ -212,7 +250,7 @@ function mountLayoutInternal(host, input) {
|
|
|
212
250
|
const resize = isolatedResize(geometryLayout(), node.id, (child, axis) => {
|
|
213
251
|
const rect = regions.get(child.id).element.getBoundingClientRect();
|
|
214
252
|
return axis === 'horizontal' ? rect.width : rect.height;
|
|
215
|
-
});
|
|
253
|
+
}, bounds);
|
|
216
254
|
act(() => options.store.resizeMany(resize.ratios(Math.max(0.001, Math.min(0.999, n.ratio + (e.key === keys[0] ? -1 : 1) * (e.shiftKey ? 0.1 : 0.02)))), { source: 'user' }));
|
|
217
255
|
}
|
|
218
256
|
});
|
|
@@ -445,9 +483,30 @@ function mountLayoutInternal(host, input) {
|
|
|
445
483
|
return node.axis === 'horizontal' ? b.minWidth < b.maxWidth : b.minHeight < b.maxHeight;
|
|
446
484
|
});
|
|
447
485
|
}
|
|
486
|
+
const chromeSizes = new Map();
|
|
487
|
+
function bounds(node, layout) {
|
|
488
|
+
return modelBounds(node, layout, (group, constraints) => {
|
|
489
|
+
const chrome = chromeSizes.get(group.id);
|
|
490
|
+
if (!chrome)
|
|
491
|
+
return constraints;
|
|
492
|
+
const minWidth = Math.max(constraints.minWidth, chrome.minWidth);
|
|
493
|
+
const minHeight = Math.max(constraints.minHeight, chrome.minHeight);
|
|
494
|
+
return {
|
|
495
|
+
minWidth,
|
|
496
|
+
minHeight,
|
|
497
|
+
maxWidth: Math.max(constraints.maxWidth, minWidth),
|
|
498
|
+
maxHeight: Math.max(constraints.maxHeight, minHeight),
|
|
499
|
+
};
|
|
500
|
+
});
|
|
501
|
+
}
|
|
448
502
|
// Renderer-only gaps participate in bounds/allocation without modifying Layout JSON.
|
|
449
503
|
function geometryLayout() {
|
|
450
504
|
const layout = options.store.getSnapshot();
|
|
505
|
+
chromeSizes.clear();
|
|
506
|
+
for (const [id, region] of regions) {
|
|
507
|
+
if (region.header && region.tabStyle && region.element.isConnected)
|
|
508
|
+
chromeSizes.set(id, chromeMinimum(region.element, region.header, region.tabStyle()));
|
|
509
|
+
}
|
|
451
510
|
const pixels = (property, fallback) => themePixels(root, property, fallback);
|
|
452
511
|
const width = pixels('--layouts-resize-handle-width', DIVIDER);
|
|
453
512
|
const disabledWidth = pixels('--layouts-disabled-resize-handle-width', 0);
|
|
@@ -537,9 +596,23 @@ function mountLayoutInternal(host, input) {
|
|
|
537
596
|
}
|
|
538
597
|
render();
|
|
539
598
|
}));
|
|
540
|
-
|
|
599
|
+
// Geometry can change the stage's scrollbar gutter. Defer those writes out
|
|
600
|
+
// of ResizeObserver delivery so WebKit does not detect a nested resize loop.
|
|
601
|
+
let measureFrame = 0;
|
|
602
|
+
const observer = new ResizeObserver(() => {
|
|
603
|
+
if (!measureFrame && !disposed)
|
|
604
|
+
measureFrame = doc.defaultView.requestAnimationFrame(() => {
|
|
605
|
+
measureFrame = 0;
|
|
606
|
+
if (!disposed)
|
|
607
|
+
measure();
|
|
608
|
+
});
|
|
609
|
+
});
|
|
541
610
|
observer.observe(stage);
|
|
542
|
-
scope.add(() =>
|
|
611
|
+
scope.add(() => {
|
|
612
|
+
observer.disconnect();
|
|
613
|
+
if (measureFrame)
|
|
614
|
+
doc.defaultView.cancelAnimationFrame(measureFrame);
|
|
615
|
+
});
|
|
543
616
|
scope.listen(doc, 'dragend', () => {
|
|
544
617
|
dragId = undefined;
|
|
545
618
|
for (const r of regions.values())
|
|
@@ -587,13 +660,21 @@ function mountLayoutInternal(host, input) {
|
|
|
587
660
|
themeObserver.observe(ancestor, { attributes: true });
|
|
588
661
|
themeObserver.observe(doc.head, { childList: true, subtree: true, characterData: true });
|
|
589
662
|
scope.add(() => themeObserver.disconnect());
|
|
663
|
+
// Cancel asynchronous actions before tearing down views and the owned store.
|
|
664
|
+
scope.add(() => {
|
|
665
|
+
closeScope.dispose();
|
|
666
|
+
windows.dispose();
|
|
667
|
+
});
|
|
590
668
|
render();
|
|
591
669
|
return {
|
|
670
|
+
store: options.store,
|
|
592
671
|
requestClose,
|
|
593
672
|
refreshTheme,
|
|
594
673
|
updateOptions(next) {
|
|
595
674
|
if (disposed)
|
|
596
675
|
return;
|
|
676
|
+
if ('store' in next || 'initialLayout' in next || 'initialWorkspace' in next)
|
|
677
|
+
throw new Error('Initial configuration cannot be updated; use loadWorkspace or store commands');
|
|
597
678
|
const candidate = { ...options, ...next };
|
|
598
679
|
if (candidate.registry && (next.renderers || next.tabs))
|
|
599
680
|
throw new Error('registry cannot be combined with renderers or tabs');
|
|
@@ -691,23 +772,7 @@ function mountLayoutInternal(host, input) {
|
|
|
691
772
|
if (disposed)
|
|
692
773
|
return;
|
|
693
774
|
disposed = true;
|
|
694
|
-
menu.dispose();
|
|
695
|
-
dragScope?.dispose();
|
|
696
775
|
scope.dispose();
|
|
697
|
-
windows.dispose();
|
|
698
|
-
for (const p of panes.values()) {
|
|
699
|
-
try {
|
|
700
|
-
p.dispose();
|
|
701
|
-
}
|
|
702
|
-
catch (e) {
|
|
703
|
-
error(e);
|
|
704
|
-
}
|
|
705
|
-
}
|
|
706
|
-
for (const r of regions.values())
|
|
707
|
-
r.scope.dispose();
|
|
708
|
-
panes.clear();
|
|
709
|
-
regions.clear();
|
|
710
|
-
root.remove();
|
|
711
776
|
},
|
|
712
777
|
};
|
|
713
778
|
}
|