quilt-vanilla 0.1.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/LICENSE +21 -0
- package/README.md +58 -0
- package/dist/action-icons.d.ts +18 -0
- package/dist/action-icons.d.ts.map +1 -0
- package/dist/action-icons.js +36 -0
- package/dist/action-icons.js.map +1 -0
- package/dist/chrome-icons.d.ts +3 -0
- package/dist/chrome-icons.d.ts.map +1 -0
- package/dist/chrome-icons.js +32 -0
- package/dist/chrome-icons.js.map +1 -0
- package/dist/corners.d.ts +8 -0
- package/dist/corners.d.ts.map +1 -0
- package/dist/corners.js +205 -0
- package/dist/corners.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/lifetime.d.ts +10 -0
- package/dist/lifetime.d.ts.map +1 -0
- package/dist/lifetime.js +44 -0
- package/dist/lifetime.js.map +1 -0
- package/dist/menu.d.ts +10 -0
- package/dist/menu.d.ts.map +1 -0
- package/dist/menu.js +356 -0
- package/dist/menu.js.map +1 -0
- package/dist/panes.d.ts +13 -0
- package/dist/panes.d.ts.map +1 -0
- package/dist/panes.js +58 -0
- package/dist/panes.js.map +1 -0
- package/dist/picker.d.ts +6 -0
- package/dist/picker.d.ts.map +1 -0
- package/dist/picker.js +112 -0
- package/dist/picker.js.map +1 -0
- package/dist/registry.d.ts +25 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +39 -0
- package/dist/registry.js.map +1 -0
- package/dist/renderer.d.ts +3 -0
- package/dist/renderer.d.ts.map +1 -0
- package/dist/renderer.js +570 -0
- package/dist/renderer.js.map +1 -0
- package/dist/resize.d.ts +7 -0
- package/dist/resize.d.ts.map +1 -0
- package/dist/resize.js +56 -0
- package/dist/resize.js.map +1 -0
- package/dist/shortcuts.d.ts +6 -0
- package/dist/shortcuts.d.ts.map +1 -0
- package/dist/shortcuts.js +64 -0
- package/dist/shortcuts.js.map +1 -0
- package/dist/styles.css +842 -0
- package/dist/tab-bar.d.ts +6 -0
- package/dist/tab-bar.d.ts.map +1 -0
- package/dist/tab-bar.js +336 -0
- package/dist/tab-bar.js.map +1 -0
- package/dist/tab-tooltip.d.ts +4 -0
- package/dist/tab-tooltip.d.ts.map +1 -0
- package/dist/tab-tooltip.js +95 -0
- package/dist/tab-tooltip.js.map +1 -0
- package/dist/tabs.d.ts +15 -0
- package/dist/tabs.d.ts.map +1 -0
- package/dist/tabs.js +126 -0
- package/dist/tabs.js.map +1 -0
- package/dist/theme.d.ts +206 -0
- package/dist/theme.d.ts.map +1 -0
- package/dist/theme.js +166 -0
- package/dist/theme.js.map +1 -0
- package/dist/types.d.ts +66 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/windows.d.ts +23 -0
- package/dist/windows.d.ts.map +1 -0
- package/dist/windows.js +247 -0
- package/dist/windows.js.map +1 -0
- package/package.json +50 -0
- package/src/action-icons.ts +40 -0
- package/src/chrome-icons.ts +30 -0
- package/src/corners.ts +259 -0
- package/src/index.ts +27 -0
- package/src/lifetime.ts +46 -0
- package/src/menu.ts +432 -0
- package/src/panes.ts +76 -0
- package/src/picker.ts +114 -0
- package/src/registry.ts +46 -0
- package/src/renderer.ts +654 -0
- package/src/resize.ts +65 -0
- package/src/shortcuts.ts +90 -0
- package/src/styles.css +842 -0
- package/src/tab-bar.ts +382 -0
- package/src/tab-tooltip.ts +96 -0
- package/src/tabs.ts +129 -0
- package/src/theme.ts +211 -0
- package/src/types.ts +67 -0
- package/src/windows.ts +244 -0
package/src/resize.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { bounds, DIVIDER, findNode } from 'quilt-core';
|
|
2
|
+
import type { Axis, Layout, Node } from 'quilt-core';
|
|
3
|
+
|
|
4
|
+
/** Resize only the branches touching a divider, preserving every farther edge. */
|
|
5
|
+
export function isolatedResize(
|
|
6
|
+
layout: Layout,
|
|
7
|
+
splitId: string,
|
|
8
|
+
extent: (node: Node, axis: Axis) => number,
|
|
9
|
+
) {
|
|
10
|
+
const split = findNode(layout.root, splitId);
|
|
11
|
+
if (split?.kind !== 'split') throw new Error('Split not found');
|
|
12
|
+
const axis = split.axis;
|
|
13
|
+
const sizes = new Map<string, number>();
|
|
14
|
+
const original: Record<string, number> = {};
|
|
15
|
+
function capture(node: Node) {
|
|
16
|
+
sizes.set(node.id, extent(node, axis));
|
|
17
|
+
if (node.kind === 'split') {
|
|
18
|
+
original[node.id] = node.ratio;
|
|
19
|
+
node.children.forEach(capture);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
capture(split);
|
|
23
|
+
function limits(node: Node, start: boolean): [number, number] {
|
|
24
|
+
if (node.kind === 'group') {
|
|
25
|
+
const b = bounds(node, layout),
|
|
26
|
+
size = sizes.get(node.id)!;
|
|
27
|
+
return axis === 'horizontal'
|
|
28
|
+
? [b.minWidth - size, b.maxWidth - size]
|
|
29
|
+
: [b.minHeight - size, b.maxHeight - size];
|
|
30
|
+
}
|
|
31
|
+
if (node.axis === axis) return limits(node.children[start ? 0 : 1], start);
|
|
32
|
+
const a = limits(node.children[0], start),
|
|
33
|
+
b = limits(node.children[1], start);
|
|
34
|
+
return [Math.max(a[0], b[0]), Math.min(a[1], b[1])];
|
|
35
|
+
}
|
|
36
|
+
const a = limits(split.children[0], false),
|
|
37
|
+
b = limits(split.children[1], true);
|
|
38
|
+
const available = sizes.get(split.id)! - (split.gap ?? DIVIDER);
|
|
39
|
+
return {
|
|
40
|
+
original,
|
|
41
|
+
ratios(ratio: number) {
|
|
42
|
+
const delta = Math.max(
|
|
43
|
+
Math.max(a[0], -b[1]),
|
|
44
|
+
Math.min(Math.min(a[1], -b[0]), available * ratio - sizes.get(split.children[0].id)!),
|
|
45
|
+
);
|
|
46
|
+
const ratios: Record<string, number> = {};
|
|
47
|
+
function adjust(node: Node, start: boolean, change: number) {
|
|
48
|
+
if (node.kind === 'group') return;
|
|
49
|
+
if (node.axis === axis) {
|
|
50
|
+
const first = sizes.get(node.children[0].id)! + (start ? change : 0);
|
|
51
|
+
const total = sizes.get(node.id)! + change - (node.gap ?? DIVIDER);
|
|
52
|
+
ratios[node.id] = Math.max(0.001, Math.min(0.999, first / total));
|
|
53
|
+
adjust(node.children[start ? 0 : 1], start, change);
|
|
54
|
+
} else node.children.forEach((child) => adjust(child, start, change));
|
|
55
|
+
}
|
|
56
|
+
ratios[split.id] = Math.max(
|
|
57
|
+
0.001,
|
|
58
|
+
Math.min(0.999, (sizes.get(split.children[0].id)! + delta) / available),
|
|
59
|
+
);
|
|
60
|
+
adjust(split.children[0], false, delta);
|
|
61
|
+
adjust(split.children[1], true, -delta);
|
|
62
|
+
return ratios;
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
}
|
package/src/shortcuts.ts
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { Group } from 'quilt-core';
|
|
2
|
+
import { findNode } from 'quilt-core';
|
|
3
|
+
import type { LayoutOptions } from './types.js';
|
|
4
|
+
import type { Scope } from './lifetime.js';
|
|
5
|
+
export function shortcutEnabled(
|
|
6
|
+
options: LayoutOptions,
|
|
7
|
+
key: 'maximize' | 'middleClickClose' | 'addTab' | 'restoreClosedTab',
|
|
8
|
+
) {
|
|
9
|
+
return (
|
|
10
|
+
options.shortcuts === true ||
|
|
11
|
+
(typeof options.shortcuts === 'object' && options.shortcuts[key] === true)
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
export function bindShortcuts(
|
|
15
|
+
root: HTMLElement,
|
|
16
|
+
options: LayoutOptions,
|
|
17
|
+
scope: Scope,
|
|
18
|
+
act: (fn: () => void) => void,
|
|
19
|
+
addTab: (group: Group) => void,
|
|
20
|
+
) {
|
|
21
|
+
if (
|
|
22
|
+
!shortcutEnabled(options, 'maximize') &&
|
|
23
|
+
!shortcutEnabled(options, 'addTab') &&
|
|
24
|
+
!shortcutEnabled(options, 'restoreClosedTab')
|
|
25
|
+
)
|
|
26
|
+
return;
|
|
27
|
+
let hovered: string | undefined;
|
|
28
|
+
scope.listen(root, 'pointerover', (event) => {
|
|
29
|
+
hovered = (event.target as Element).closest<HTMLElement>('.layouts-group')?.dataset.nodeId;
|
|
30
|
+
});
|
|
31
|
+
scope.listen(root, 'pointerleave', () => {
|
|
32
|
+
hovered = undefined;
|
|
33
|
+
});
|
|
34
|
+
scope.listen(root.ownerDocument, 'keydown', (event) => {
|
|
35
|
+
const e = event as KeyboardEvent;
|
|
36
|
+
const maximizeKey = (e.altKey && e.code === 'Space') || (!e.altKey && e.key === '`');
|
|
37
|
+
const addTabKey = !e.metaKey && !e.altKey && e.key.toLowerCase() === 't';
|
|
38
|
+
const maximize = !e.metaKey && maximizeKey && shortcutEnabled(options, 'maximize');
|
|
39
|
+
const restore =
|
|
40
|
+
!e.metaKey &&
|
|
41
|
+
!e.altKey &&
|
|
42
|
+
e.key.toLowerCase() === 'r' &&
|
|
43
|
+
shortcutEnabled(options, 'restoreClosedTab');
|
|
44
|
+
const create = addTabKey && shortcutEnabled(options, 'addTab');
|
|
45
|
+
if (
|
|
46
|
+
e.isComposing ||
|
|
47
|
+
e.defaultPrevented ||
|
|
48
|
+
e.repeat ||
|
|
49
|
+
(!maximize && !create && !restore) ||
|
|
50
|
+
e.ctrlKey ||
|
|
51
|
+
e.shiftKey
|
|
52
|
+
)
|
|
53
|
+
return;
|
|
54
|
+
const target = e.target as HTMLElement | null;
|
|
55
|
+
if (
|
|
56
|
+
target?.closest(
|
|
57
|
+
'input, textarea, select, [contenteditable]:not([contenteditable="false"]), dialog',
|
|
58
|
+
) ||
|
|
59
|
+
root.ownerDocument.querySelector('dialog[open]')
|
|
60
|
+
)
|
|
61
|
+
return;
|
|
62
|
+
if (restore) {
|
|
63
|
+
if (options.store.canRestoreClosedTab()) {
|
|
64
|
+
e.preventDefault();
|
|
65
|
+
act(() => options.store.restoreClosedTab());
|
|
66
|
+
}
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const focused =
|
|
70
|
+
target && root.contains(target)
|
|
71
|
+
? target.closest<HTMLElement>('.layouts-group')?.dataset.nodeId
|
|
72
|
+
: undefined;
|
|
73
|
+
const id = create ? hovered : (hovered ?? focused);
|
|
74
|
+
const layout = options.store.getSnapshot();
|
|
75
|
+
const group = id ? findNode(layout.root, id) : undefined;
|
|
76
|
+
if (group?.kind !== 'group') return;
|
|
77
|
+
if (
|
|
78
|
+
create &&
|
|
79
|
+
(!options.tabs?.list().length ||
|
|
80
|
+
!group.panes.every((paneId) => options.store.can(paneId, 'move')))
|
|
81
|
+
)
|
|
82
|
+
return;
|
|
83
|
+
e.preventDefault();
|
|
84
|
+
act(() =>
|
|
85
|
+
create
|
|
86
|
+
? addTab(group)
|
|
87
|
+
: options.store.maximize(layout.maximized === group.id ? null : group.id),
|
|
88
|
+
);
|
|
89
|
+
});
|
|
90
|
+
}
|