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.
Files changed (95) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +58 -0
  3. package/dist/action-icons.d.ts +18 -0
  4. package/dist/action-icons.d.ts.map +1 -0
  5. package/dist/action-icons.js +36 -0
  6. package/dist/action-icons.js.map +1 -0
  7. package/dist/chrome-icons.d.ts +3 -0
  8. package/dist/chrome-icons.d.ts.map +1 -0
  9. package/dist/chrome-icons.js +32 -0
  10. package/dist/chrome-icons.js.map +1 -0
  11. package/dist/corners.d.ts +8 -0
  12. package/dist/corners.d.ts.map +1 -0
  13. package/dist/corners.js +205 -0
  14. package/dist/corners.js.map +1 -0
  15. package/dist/index.d.ts +9 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +5 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/lifetime.d.ts +10 -0
  20. package/dist/lifetime.d.ts.map +1 -0
  21. package/dist/lifetime.js +44 -0
  22. package/dist/lifetime.js.map +1 -0
  23. package/dist/menu.d.ts +10 -0
  24. package/dist/menu.d.ts.map +1 -0
  25. package/dist/menu.js +356 -0
  26. package/dist/menu.js.map +1 -0
  27. package/dist/panes.d.ts +13 -0
  28. package/dist/panes.d.ts.map +1 -0
  29. package/dist/panes.js +58 -0
  30. package/dist/panes.js.map +1 -0
  31. package/dist/picker.d.ts +6 -0
  32. package/dist/picker.d.ts.map +1 -0
  33. package/dist/picker.js +112 -0
  34. package/dist/picker.js.map +1 -0
  35. package/dist/registry.d.ts +25 -0
  36. package/dist/registry.d.ts.map +1 -0
  37. package/dist/registry.js +39 -0
  38. package/dist/registry.js.map +1 -0
  39. package/dist/renderer.d.ts +3 -0
  40. package/dist/renderer.d.ts.map +1 -0
  41. package/dist/renderer.js +570 -0
  42. package/dist/renderer.js.map +1 -0
  43. package/dist/resize.d.ts +7 -0
  44. package/dist/resize.d.ts.map +1 -0
  45. package/dist/resize.js +56 -0
  46. package/dist/resize.js.map +1 -0
  47. package/dist/shortcuts.d.ts +6 -0
  48. package/dist/shortcuts.d.ts.map +1 -0
  49. package/dist/shortcuts.js +64 -0
  50. package/dist/shortcuts.js.map +1 -0
  51. package/dist/styles.css +842 -0
  52. package/dist/tab-bar.d.ts +6 -0
  53. package/dist/tab-bar.d.ts.map +1 -0
  54. package/dist/tab-bar.js +336 -0
  55. package/dist/tab-bar.js.map +1 -0
  56. package/dist/tab-tooltip.d.ts +4 -0
  57. package/dist/tab-tooltip.d.ts.map +1 -0
  58. package/dist/tab-tooltip.js +95 -0
  59. package/dist/tab-tooltip.js.map +1 -0
  60. package/dist/tabs.d.ts +15 -0
  61. package/dist/tabs.d.ts.map +1 -0
  62. package/dist/tabs.js +126 -0
  63. package/dist/tabs.js.map +1 -0
  64. package/dist/theme.d.ts +206 -0
  65. package/dist/theme.d.ts.map +1 -0
  66. package/dist/theme.js +166 -0
  67. package/dist/theme.js.map +1 -0
  68. package/dist/types.d.ts +66 -0
  69. package/dist/types.d.ts.map +1 -0
  70. package/dist/types.js +2 -0
  71. package/dist/types.js.map +1 -0
  72. package/dist/windows.d.ts +23 -0
  73. package/dist/windows.d.ts.map +1 -0
  74. package/dist/windows.js +247 -0
  75. package/dist/windows.js.map +1 -0
  76. package/package.json +50 -0
  77. package/src/action-icons.ts +40 -0
  78. package/src/chrome-icons.ts +30 -0
  79. package/src/corners.ts +259 -0
  80. package/src/index.ts +27 -0
  81. package/src/lifetime.ts +46 -0
  82. package/src/menu.ts +432 -0
  83. package/src/panes.ts +76 -0
  84. package/src/picker.ts +114 -0
  85. package/src/registry.ts +46 -0
  86. package/src/renderer.ts +654 -0
  87. package/src/resize.ts +65 -0
  88. package/src/shortcuts.ts +90 -0
  89. package/src/styles.css +842 -0
  90. package/src/tab-bar.ts +382 -0
  91. package/src/tab-tooltip.ts +96 -0
  92. package/src/tabs.ts +129 -0
  93. package/src/theme.ts +211 -0
  94. package/src/types.ts +67 -0
  95. 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
+ }
@@ -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
+ }