@liberation-data/desk 0.1.0 → 0.2.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 +92 -1
- package/dist/core/desk.d.ts.map +1 -1
- package/dist/core/desk.js +19 -2
- package/dist/core/desk.js.map +1 -1
- package/dist/core/index.d.ts +2 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +1 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/layouts.d.ts +26 -0
- package/dist/core/layouts.d.ts.map +1 -0
- package/dist/core/layouts.js +70 -0
- package/dist/core/layouts.js.map +1 -0
- package/dist/core/types.d.ts +3 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/desk.css +146 -1
- package/dist/react/Desktop.d.ts +7 -1
- package/dist/react/Desktop.d.ts.map +1 -1
- package/dist/react/Desktop.js +4 -4
- package/dist/react/Desktop.js.map +1 -1
- package/dist/react/Dock.d.ts +16 -1
- package/dist/react/Dock.d.ts.map +1 -1
- package/dist/react/Dock.js +44 -6
- package/dist/react/Dock.js.map +1 -1
- package/dist/react/MenuBar.d.ts +16 -0
- package/dist/react/MenuBar.d.ts.map +1 -1
- package/dist/react/MenuBar.js +36 -27
- package/dist/react/MenuBar.js.map +1 -1
- package/dist/react/context.d.ts +2 -0
- package/dist/react/context.d.ts.map +1 -1
- package/dist/react/context.js +2 -0
- package/dist/react/context.js.map +1 -1
- package/dist/react/contextMenu.d.ts +22 -0
- package/dist/react/contextMenu.d.ts.map +1 -0
- package/dist/react/contextMenu.js +146 -0
- package/dist/react/contextMenu.js.map +1 -0
- package/dist/react/iconView.d.ts +34 -0
- package/dist/react/iconView.d.ts.map +1 -0
- package/dist/react/iconView.js +112 -0
- package/dist/react/iconView.js.map +1 -0
- package/dist/react/index.d.ts +6 -2
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +3 -1
- package/dist/react/index.js.map +1 -1
- package/llms.txt +22 -4
- package/package.json +1 -1
- package/src/core/desk.ts +17 -2
- package/src/core/index.ts +2 -0
- package/src/core/layouts.ts +88 -0
- package/src/core/types.ts +4 -0
- package/src/desk.css +146 -1
- package/src/react/Desktop.tsx +11 -2
- package/src/react/Dock.tsx +74 -5
- package/src/react/MenuBar.tsx +43 -30
- package/src/react/context.tsx +3 -0
- package/src/react/contextMenu.tsx +198 -0
- package/src/react/iconView.tsx +206 -0
- package/src/react/index.ts +6 -2
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useEffect, useId, useLayoutEffect, useRef, useState } from 'react';
|
|
3
|
+
import { createPortal } from 'react-dom';
|
|
4
|
+
import { perform } from '../core/commands.js';
|
|
5
|
+
import { formatShortcut, isApplePlatform } from '../core/shortcuts.js';
|
|
6
|
+
import { useOptionalDesk } from './context.js';
|
|
7
|
+
import { resolveMenuItems, selectable, stepMenu, typeAhead } from './MenuBar.js';
|
|
8
|
+
export function useContextMenu({ items, label, disabled }) {
|
|
9
|
+
const desk = useOptionalDesk();
|
|
10
|
+
const [state, setState] = useState(null);
|
|
11
|
+
const panel = useRef(null);
|
|
12
|
+
const menuId = useId();
|
|
13
|
+
const apple = isApplePlatform();
|
|
14
|
+
const show = useCallback((x, y, opener, activeFirst) => {
|
|
15
|
+
const resolved = resolveMenuItems(desk, items());
|
|
16
|
+
if (!resolved.length)
|
|
17
|
+
return;
|
|
18
|
+
setState({ x, y, items: resolved, active: activeFirst ? stepMenu(resolved, -1, 1) : -1, opener });
|
|
19
|
+
}, [desk, items]);
|
|
20
|
+
const close = useCallback((returnFocus) => {
|
|
21
|
+
setState(current => {
|
|
22
|
+
if (current && returnFocus && current.opener.isConnected)
|
|
23
|
+
current.opener.focus({ preventScroll: true });
|
|
24
|
+
return null;
|
|
25
|
+
});
|
|
26
|
+
}, []);
|
|
27
|
+
const choose = (resolved) => {
|
|
28
|
+
if (!state || !resolved || !selectable(resolved))
|
|
29
|
+
return;
|
|
30
|
+
const { opener } = state;
|
|
31
|
+
setState(null);
|
|
32
|
+
// Back to the item first, so a command starts its search for a responder from there.
|
|
33
|
+
if (opener.isConnected)
|
|
34
|
+
opener.focus({ preventScroll: true });
|
|
35
|
+
const { item } = resolved;
|
|
36
|
+
if (item.type === 'command')
|
|
37
|
+
perform(desk, item.command, item.args);
|
|
38
|
+
else if (item.type === 'action')
|
|
39
|
+
item.onSelect();
|
|
40
|
+
};
|
|
41
|
+
const target = {
|
|
42
|
+
onContextMenu: event => {
|
|
43
|
+
if (disabled)
|
|
44
|
+
return;
|
|
45
|
+
event.preventDefault();
|
|
46
|
+
const opener = event.currentTarget;
|
|
47
|
+
opener.focus({ preventScroll: true });
|
|
48
|
+
show(event.clientX, event.clientY, opener, false);
|
|
49
|
+
},
|
|
50
|
+
onKeyDown: event => {
|
|
51
|
+
if (disabled)
|
|
52
|
+
return;
|
|
53
|
+
if (event.key === 'ContextMenu' || (event.key === 'F10' && event.shiftKey)) {
|
|
54
|
+
event.preventDefault();
|
|
55
|
+
const box = event.currentTarget.getBoundingClientRect();
|
|
56
|
+
show(box.left + 8, box.bottom - 4, event.currentTarget, true);
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
// Keep it on screen: measured once it exists, then moved in from the edges it would cross.
|
|
61
|
+
useLayoutEffect(() => {
|
|
62
|
+
const element = panel.current;
|
|
63
|
+
if (!state || !element)
|
|
64
|
+
return;
|
|
65
|
+
const { width, height } = element.getBoundingClientRect();
|
|
66
|
+
const x = Math.max(8, Math.min(state.x, innerWidth - width - 8));
|
|
67
|
+
const y = Math.max(8, state.y + height > innerHeight - 8 ? state.y - height : state.y);
|
|
68
|
+
element.style.left = `${x}px`;
|
|
69
|
+
element.style.top = `${y}px`;
|
|
70
|
+
element.focus({ preventScroll: true });
|
|
71
|
+
}, [state]);
|
|
72
|
+
useEffect(() => {
|
|
73
|
+
if (!state)
|
|
74
|
+
return;
|
|
75
|
+
const onPointerDown = (event) => {
|
|
76
|
+
if (!panel.current?.contains(event.target))
|
|
77
|
+
close(false);
|
|
78
|
+
};
|
|
79
|
+
const onAway = () => close(false);
|
|
80
|
+
document.addEventListener('pointerdown', onPointerDown, true);
|
|
81
|
+
addEventListener('blur', onAway);
|
|
82
|
+
addEventListener('resize', onAway);
|
|
83
|
+
document.addEventListener('scroll', onAway, true);
|
|
84
|
+
return () => {
|
|
85
|
+
document.removeEventListener('pointerdown', onPointerDown, true);
|
|
86
|
+
removeEventListener('blur', onAway);
|
|
87
|
+
removeEventListener('resize', onAway);
|
|
88
|
+
document.removeEventListener('scroll', onAway, true);
|
|
89
|
+
};
|
|
90
|
+
}, [state, close]);
|
|
91
|
+
const onMenuKeyDown = (event) => {
|
|
92
|
+
if (!state)
|
|
93
|
+
return;
|
|
94
|
+
const move = (active) => setState({ ...state, active });
|
|
95
|
+
switch (event.key) {
|
|
96
|
+
case 'ArrowDown':
|
|
97
|
+
move(stepMenu(state.items, state.active, 1));
|
|
98
|
+
break;
|
|
99
|
+
case 'ArrowUp':
|
|
100
|
+
move(stepMenu(state.items, state.active < 0 ? state.items.length : state.active, -1));
|
|
101
|
+
break;
|
|
102
|
+
case 'Home':
|
|
103
|
+
move(stepMenu(state.items, -1, 1));
|
|
104
|
+
break;
|
|
105
|
+
case 'End':
|
|
106
|
+
move(stepMenu(state.items, state.items.length, -1));
|
|
107
|
+
break;
|
|
108
|
+
case 'Enter':
|
|
109
|
+
case ' ':
|
|
110
|
+
choose(state.items[state.active]);
|
|
111
|
+
break;
|
|
112
|
+
case 'Escape':
|
|
113
|
+
close(true);
|
|
114
|
+
break;
|
|
115
|
+
case 'Tab':
|
|
116
|
+
close(true);
|
|
117
|
+
break;
|
|
118
|
+
default: {
|
|
119
|
+
if (event.key.length !== 1 || event.metaKey || event.ctrlKey || event.altKey)
|
|
120
|
+
return;
|
|
121
|
+
const index = typeAhead(state.items, state.active, event.key);
|
|
122
|
+
if (index < 0)
|
|
123
|
+
return;
|
|
124
|
+
move(index);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
event.preventDefault();
|
|
128
|
+
event.stopPropagation();
|
|
129
|
+
};
|
|
130
|
+
const menu = state && typeof document !== 'undefined'
|
|
131
|
+
? createPortal(_jsx("div", { ref: panel, role: "menu", "aria-label": label, tabIndex: -1, className: "desk-menu desk-context-menu", style: { left: state.x, top: state.y }, "aria-activedescendant": state.active >= 0 ? `${menuId}-${state.active}` : undefined, onKeyDown: onMenuKeyDown, onContextMenu: event => event.preventDefault(), children: state.items.map((resolved, i) => {
|
|
132
|
+
const { item } = resolved;
|
|
133
|
+
if (item.type === 'separator')
|
|
134
|
+
return _jsx("div", { role: "separator", className: "desk-menu-separator" }, i);
|
|
135
|
+
if (item.type === 'header')
|
|
136
|
+
return _jsx("div", { role: "presentation", className: "desk-menu-header", children: item.label }, i);
|
|
137
|
+
const checkable = resolved.checked !== undefined;
|
|
138
|
+
return (_jsxs("div", { id: `${menuId}-${i}`, role: checkable ? 'menuitemcheckbox' : 'menuitem', "aria-checked": checkable ? resolved.checked : undefined, "aria-disabled": !resolved.enabled || undefined, className: "desk-menu-item", "data-active": i === state.active || undefined, onPointerMove: () => {
|
|
139
|
+
if (state.active !== i && selectable(resolved))
|
|
140
|
+
setState({ ...state, active: i });
|
|
141
|
+
}, onClick: () => choose(resolved), children: [_jsx("span", { className: "desk-menu-check", "aria-hidden": "true", children: resolved.checked ? '✓' : '' }), _jsx("span", { className: "desk-menu-label", children: item.label }), item.detail && _jsx("span", { className: "desk-menu-detail", children: item.detail }), item.shortcut && _jsx("kbd", { className: "desk-menu-shortcut", children: formatShortcut(item.shortcut, apple) })] }, i));
|
|
142
|
+
}) }), document.body)
|
|
143
|
+
: null;
|
|
144
|
+
return { target, menu, open: state !== null };
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=contextMenu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contextMenu.js","sourceRoot":"","sources":["../../src/react/contextMenu.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { MenuItem } from './MenuBar.js';
|
|
3
|
+
export interface IconViewItem {
|
|
4
|
+
readonly id: string;
|
|
5
|
+
readonly label: string;
|
|
6
|
+
readonly icon: ReactNode;
|
|
7
|
+
/** A second line, muted: a kind, a scope, a size. */
|
|
8
|
+
readonly subtitle?: string;
|
|
9
|
+
readonly badge?: ReactNode;
|
|
10
|
+
readonly disabled?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export interface IconViewProps<T extends IconViewItem> {
|
|
13
|
+
readonly items: readonly T[];
|
|
14
|
+
/** Names the collection: "Apps". */
|
|
15
|
+
readonly label: string;
|
|
16
|
+
readonly onOpen: (item: T) => void;
|
|
17
|
+
/** `double` (the default): click selects, double-click or Return opens. `single`: a click opens. */
|
|
18
|
+
readonly openOn?: 'double' | 'single';
|
|
19
|
+
/** Controlled selection. Leave both out and the view keeps its own. */
|
|
20
|
+
readonly selected?: string | null;
|
|
21
|
+
readonly onSelectionChange?: (id: string | null) => void;
|
|
22
|
+
/** The item's context menu: what can be done to this one thing. */
|
|
23
|
+
readonly contextMenu?: (item: T) => readonly MenuItem[];
|
|
24
|
+
/** Lets an icon be picked up and carried, to the dock or into another window. */
|
|
25
|
+
readonly drag?: {
|
|
26
|
+
readonly type: string;
|
|
27
|
+
readonly payload: (item: T) => unknown;
|
|
28
|
+
};
|
|
29
|
+
/** Shown when there are no items. */
|
|
30
|
+
readonly empty?: ReactNode;
|
|
31
|
+
readonly className?: string;
|
|
32
|
+
}
|
|
33
|
+
export declare function IconView<T extends IconViewItem>({ items, label, onOpen, openOn, selected, onSelectionChange, contextMenu, drag, empty, className, }: IconViewProps<T>): import("react").JSX.Element;
|
|
34
|
+
//# sourceMappingURL=iconView.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"iconView.d.ts","sourceRoot":"","sources":["../../src/react/iconView.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAuC,SAAS,EAAE,MAAM,OAAO,CAAA;AAG3E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAY5C,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;IACxB,qDAAqD;IACrD,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,CAAA;IAC1B,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAC5B;AAED,MAAM,WAAW,aAAa,CAAC,CAAC,SAAS,YAAY;IACnD,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC,EAAE,CAAA;IAC5B,oCAAoC;IACpC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAA;IAClC,oGAAoG;IACpG,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAA;IACrC,uEAAuE;IACvE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAA;IACxD,mEAAmE;IACnE,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,SAAS,QAAQ,EAAE,CAAA;IACvD,iFAAiF;IACjF,QAAQ,CAAC,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAA;KAAE,CAAA;IACjF,qCAAqC;IACrC,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,CAAA;IAC1B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAC5B;AAED,wBAAgB,QAAQ,CAAC,CAAC,SAAS,YAAY,EAAE,EAC/C,KAAK,EACL,KAAK,EACL,MAAM,EACN,MAAiB,EACjB,QAAQ,EACR,iBAAiB,EACjB,WAAW,EACX,IAAI,EACJ,KAAK,EACL,SAAS,GACV,EAAE,aAAa,CAAC,CAAC,CAAC,+BAmGlB"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useRef, useState } from 'react';
|
|
3
|
+
import { useContextMenu } from './contextMenu.js';
|
|
4
|
+
import { useDragSource } from './dnd.js';
|
|
5
|
+
export function IconView({ items, label, onOpen, openOn = 'double', selected, onSelectionChange, contextMenu, drag, empty, className, }) {
|
|
6
|
+
const [ownSelection, setOwnSelection] = useState(null);
|
|
7
|
+
const current = selected !== undefined ? selected : ownSelection;
|
|
8
|
+
const select = (id) => {
|
|
9
|
+
if (selected === undefined)
|
|
10
|
+
setOwnSelection(id);
|
|
11
|
+
onSelectionChange?.(id);
|
|
12
|
+
};
|
|
13
|
+
const list = useRef(null);
|
|
14
|
+
const typed = useRef({ text: '', at: 0 });
|
|
15
|
+
const source = useDragSource({ type: drag?.type ?? 'desk.icon', disabled: !drag });
|
|
16
|
+
// The one that takes Tab: the selected item, or the first.
|
|
17
|
+
const focusable = items.some(i => i.id === current) ? current : (items[0]?.id ?? null);
|
|
18
|
+
const cells = () => [...(list.current?.querySelectorAll('[data-icon-id]') ?? [])];
|
|
19
|
+
const focusAt = (index) => {
|
|
20
|
+
const all = cells();
|
|
21
|
+
const target = all[Math.max(0, Math.min(index, all.length - 1))];
|
|
22
|
+
if (!target)
|
|
23
|
+
return;
|
|
24
|
+
target.focus();
|
|
25
|
+
select(target.dataset.iconId ?? null);
|
|
26
|
+
};
|
|
27
|
+
// How many icons fit in a row right now: the ones that share the first one's top edge.
|
|
28
|
+
const columns = () => {
|
|
29
|
+
const all = cells();
|
|
30
|
+
const top = all[0]?.offsetTop;
|
|
31
|
+
const count = all.filter(cell => cell.offsetTop === top).length;
|
|
32
|
+
return Math.max(1, count);
|
|
33
|
+
};
|
|
34
|
+
const onKeyDown = (event) => {
|
|
35
|
+
const all = cells();
|
|
36
|
+
const index = all.findIndex(cell => cell === document.activeElement);
|
|
37
|
+
if (index < 0)
|
|
38
|
+
return;
|
|
39
|
+
const item = items[index];
|
|
40
|
+
switch (event.key) {
|
|
41
|
+
case 'ArrowRight':
|
|
42
|
+
focusAt(index + 1);
|
|
43
|
+
break;
|
|
44
|
+
case 'ArrowLeft':
|
|
45
|
+
focusAt(index - 1);
|
|
46
|
+
break;
|
|
47
|
+
case 'ArrowDown':
|
|
48
|
+
focusAt(index + columns());
|
|
49
|
+
break;
|
|
50
|
+
case 'ArrowUp':
|
|
51
|
+
focusAt(index - columns());
|
|
52
|
+
break;
|
|
53
|
+
case 'Home':
|
|
54
|
+
focusAt(0);
|
|
55
|
+
break;
|
|
56
|
+
case 'End':
|
|
57
|
+
focusAt(all.length - 1);
|
|
58
|
+
break;
|
|
59
|
+
case 'Enter':
|
|
60
|
+
if (item && !item.disabled)
|
|
61
|
+
onOpen(item);
|
|
62
|
+
break;
|
|
63
|
+
case ' ':
|
|
64
|
+
if (item)
|
|
65
|
+
select(item.id);
|
|
66
|
+
break;
|
|
67
|
+
default: {
|
|
68
|
+
if (event.key.length !== 1 || event.metaKey || event.ctrlKey || event.altKey)
|
|
69
|
+
return;
|
|
70
|
+
// Typing a name finds it: letters typed close together build one search, as in a Finder.
|
|
71
|
+
const now = Date.now();
|
|
72
|
+
typed.current = { text: (now - typed.current.at < 700 ? typed.current.text : '') + event.key.toLowerCase(), at: now };
|
|
73
|
+
const search = typed.current.text;
|
|
74
|
+
const order = [...items.slice(index + (search.length === 1 ? 1 : 0)), ...items.slice(0, index + (search.length === 1 ? 1 : 0))];
|
|
75
|
+
const found = order.find(i => i.label.toLowerCase().startsWith(search));
|
|
76
|
+
if (!found)
|
|
77
|
+
return;
|
|
78
|
+
focusAt(items.indexOf(found));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
event.preventDefault();
|
|
82
|
+
};
|
|
83
|
+
// A selection that no longer exists is dropped, so Tab never lands nowhere.
|
|
84
|
+
useEffect(() => {
|
|
85
|
+
if (current && !items.some(i => i.id === current))
|
|
86
|
+
select(null);
|
|
87
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
88
|
+
}, [items, current]);
|
|
89
|
+
if (!items.length)
|
|
90
|
+
return _jsx("div", { className: ['desk-icon-view-empty', className].filter(Boolean).join(' '), children: empty });
|
|
91
|
+
return (_jsx("ul", { ref: list, role: "listbox", "aria-label": label, className: ['desk-icon-view', className].filter(Boolean).join(' '), onKeyDown: onKeyDown, onPointerDown: event => {
|
|
92
|
+
if (event.target === event.currentTarget)
|
|
93
|
+
select(null);
|
|
94
|
+
}, children: items.map(item => (_jsx(IconCell, { item: item, selected: item.id === current, tabbable: item.id === focusable, openOn: openOn, onSelect: () => select(item.id), onOpen: () => onOpen(item), menu: contextMenu ? () => contextMenu(item) : null, dragProps: drag ? source.dragProps(drag.payload(item), _jsx("span", { className: "desk-icon-drag", children: item.icon })) : null }, item.id))) }));
|
|
95
|
+
}
|
|
96
|
+
function IconCell({ item, selected, tabbable, openOn, onSelect, onOpen, menu, dragProps }) {
|
|
97
|
+
const context = useContextMenu({ label: `Actions for ${item.label}`, items: menu ?? (() => []), disabled: !menu });
|
|
98
|
+
// The menu sits beside the cell, not in it: React bubbles a portal's events through its owner,
|
|
99
|
+
// and a click on "Open" must not also count as a click on the icon.
|
|
100
|
+
return (_jsxs(_Fragment, { children: [_jsxs("li", { role: "option", "aria-selected": selected, "aria-disabled": item.disabled || undefined, tabIndex: tabbable ? 0 : -1, "data-icon-id": item.id, className: "desk-icon-cell", ...(dragProps ?? {}), onClick: () => {
|
|
101
|
+
onSelect();
|
|
102
|
+
if (openOn === 'single' && !item.disabled)
|
|
103
|
+
onOpen();
|
|
104
|
+
}, onDoubleClick: () => {
|
|
105
|
+
if (openOn === 'double' && !item.disabled)
|
|
106
|
+
onOpen();
|
|
107
|
+
}, onContextMenu: event => {
|
|
108
|
+
onSelect();
|
|
109
|
+
context.target.onContextMenu(event);
|
|
110
|
+
}, onKeyDown: context.target.onKeyDown, children: [_jsxs("span", { className: "desk-icon-glyph", "aria-hidden": "true", children: [item.icon, item.badge != null && _jsx("span", { className: "desk-icon-badge", children: item.badge })] }), _jsx("span", { className: "desk-icon-label", children: item.label }), item.subtitle && _jsx("span", { className: "desk-icon-subtitle", children: item.subtitle })] }), context.menu] }));
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=iconView.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"iconView.js","sourceRoot":"","sources":["../../src/react/iconView.tsx"],"names":[],"mappings":"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"}
|
package/dist/react/index.d.ts
CHANGED
|
@@ -37,7 +37,11 @@ export type { ComposerProps, Message, ThreadProps } from './conversation.js';
|
|
|
37
37
|
export { Alert, Popover, Sheet, ToastProvider, useToast } from './overlays.js';
|
|
38
38
|
export type { AlertProps, PopoverProps, PopoverTriggerProps, SheetProps, Toast, ToastInput } from './overlays.js';
|
|
39
39
|
export { MenuBar, menuAction, menuCommand, menuHeader, menuSeparator, windowMenuItems } from './MenuBar.js';
|
|
40
|
+
export { useContextMenu } from './contextMenu.js';
|
|
41
|
+
export type { ContextMenuOptions, ContextMenuResult, ContextMenuTargetProps } from './contextMenu.js';
|
|
40
42
|
export type { Menu, MenuBarProps, MenuItem } from './MenuBar.js';
|
|
41
|
-
export {
|
|
42
|
-
export type {
|
|
43
|
+
export { IconView } from './iconView.js';
|
|
44
|
+
export type { IconViewItem, IconViewProps } from './iconView.js';
|
|
45
|
+
export { Dock, DOCK_ITEM, dockItem, dockSeparator, dockStack } from './Dock.js';
|
|
46
|
+
export type { DockEntry, DockItem, DockPins, DockProps, DockStack } from './Dock.js';
|
|
43
47
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"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"}
|
package/dist/react/index.js
CHANGED
|
@@ -18,5 +18,7 @@ export { BusProvider, InputBar, useBus, useDeskEvent, usePublish, useWindowInput
|
|
|
18
18
|
export { Composer, Thread } from './conversation.js';
|
|
19
19
|
export { Alert, Popover, Sheet, ToastProvider, useToast } from './overlays.js';
|
|
20
20
|
export { MenuBar, menuAction, menuCommand, menuHeader, menuSeparator, windowMenuItems } from './MenuBar.js';
|
|
21
|
-
export {
|
|
21
|
+
export { useContextMenu } from './contextMenu.js';
|
|
22
|
+
export { IconView } from './iconView.js';
|
|
23
|
+
export { Dock, DOCK_ITEM, dockItem, dockSeparator, dockStack } from './Dock.js';
|
|
22
24
|
//# sourceMappingURL=index.js.map
|
package/dist/react/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAE1E,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAWhG,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAEtC,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAE/E,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAEnF,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAEtC,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAEhD,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AAetH,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAChD,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAGtE,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAExC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAElC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAEtC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEpC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAEnC,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAEzE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAErG,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAEpD,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAE9E,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAE1E,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAWhG,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAEtC,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAE/E,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAEnF,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAEtC,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAEhD,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AAetH,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAChD,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAGtE,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAExC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAElC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAEtC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEpC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAEnC,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAEzE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAErG,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAEpD,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAE9E,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAC3G,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAGjD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAExC,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA"}
|
package/llms.txt
CHANGED
|
@@ -46,7 +46,12 @@ Rules that are easy to get wrong:
|
|
|
46
46
|
|
|
47
47
|
```ts
|
|
48
48
|
createDesk(options?: DeskOptions): Desk
|
|
49
|
-
interface DeskOptions { cascade?: Partial<CascadeOptions>; stage?: () => Size; initial?: DeskState }
|
|
49
|
+
interface DeskOptions { cascade?: Partial<CascadeOptions>; stage?: () => Size; initial?: DeskState; layouts?: LayoutStore }
|
|
50
|
+
// layouts: remembers each window type's last mode/frame (saved by float/fill/zoom, not placeAll or open frames);
|
|
51
|
+
// open() without mode/frame restores it, fitted to the stage (fills if too small); more instances step +x,+y.
|
|
52
|
+
localLayoutStore(key): LayoutStore // localStorage 'desk.layouts.<key>'
|
|
53
|
+
interface LayoutStore { load(type): SavedLayout | undefined; save(type, layout: SavedLayout): void }
|
|
54
|
+
fitFrame(frame, stage, min?): Frame | null; stepFrom(frame, open: Frame[], stage, step, margin): Frame
|
|
50
55
|
|
|
51
56
|
interface Desk {
|
|
52
57
|
getState(): DeskState
|
|
@@ -177,6 +182,7 @@ useWindowId(): string | null // inside a window's content
|
|
|
177
182
|
<Desktop
|
|
178
183
|
renderWindow={(id) => ReactNode} // memoised: chrome re-renders, content does not
|
|
179
184
|
title={(id) => ReactNode}
|
|
185
|
+
note?={(id) => ReactNode} // quiet text in the title bar: what this window is looking at
|
|
180
186
|
actions?={(id) => ReactNode} // window-wide controls in the title bar
|
|
181
187
|
loading?={(id) => ReactNode} // inside a window while its code loads
|
|
182
188
|
failed?={(id, error, reload) => ReactNode} // inside a window that could not open
|
|
@@ -199,14 +205,17 @@ window; `lazyWindow` retries its import on reload, unlike `React.lazy`, which ca
|
|
|
199
205
|
### Dock
|
|
200
206
|
|
|
201
207
|
```tsx
|
|
202
|
-
<Dock entries={DockEntry[]} label?="Dock" placement?={'overlay' | 'inline'}
|
|
203
|
-
|
|
208
|
+
<Dock entries={DockEntry[]} label?="Dock" placement?={'overlay' | 'inline'}
|
|
209
|
+
pins?={{ accepts, onPin: (drag, before: id | null) => void, onMove?: (id, before: id | null) => void }} />
|
|
210
|
+
dockItem({ id, label, icon, window?, description?, badge?, onSelect?, disabled?, contextMenu?: () => MenuItem[], movable? })
|
|
204
211
|
dockStack({ id, label, items: DockItem[], icon? })
|
|
205
212
|
dockSeparator(id)
|
|
206
213
|
```
|
|
207
214
|
|
|
208
215
|
An item opens `window ?? id` and shows a dot while that window is open, accent when it is key. A stack fans
|
|
209
216
|
out above the dock. One tab stop; arrow keys along it; Escape folds a stack away.
|
|
217
|
+
Pins: the app stores kept items and passes them back as entries. A drop on the dock keeps at the end; on a
|
|
218
|
+
`movable` item, in front of it. Movable items drag along the dock (type DOCK_ITEM, payload id).
|
|
210
219
|
|
|
211
220
|
### Menu bar
|
|
212
221
|
|
|
@@ -218,6 +227,15 @@ menuCommand(label, command, { shortcut?, checked?, detail?, args? })
|
|
|
218
227
|
menuAction(label, onSelect, { disabled?, shortcut?, checked?, detail? })
|
|
219
228
|
menuSeparator(); menuHeader(label)
|
|
220
229
|
windowMenuItems(state, focus, title): MenuItem[]
|
|
230
|
+
|
|
231
|
+
const { target, menu, open } = useContextMenu({ label, items: () => MenuItem[], disabled? })
|
|
232
|
+
// spread `target` (onContextMenu, onKeyDown) on the element; render `menu` anywhere (portal).
|
|
233
|
+
// Right-click opens at the pointer; Menu key / Shift+F10 at the element. Commands run from that element.
|
|
234
|
+
|
|
235
|
+
<IconView label items={{id, label, icon, subtitle?, badge?, disabled?}[]} onOpen={item => …}
|
|
236
|
+
openOn?="double"|"single" selected? onSelectionChange? contextMenu?={item => MenuItem[]}
|
|
237
|
+
drag?={{ type, payload: item => unknown }} empty? className? />
|
|
238
|
+
// click selects, double-click / Return opens (single: click opens); arrows, Home/End, type-ahead. Needs a DeskProvider.
|
|
221
239
|
```
|
|
222
240
|
|
|
223
241
|
Command items are enabled via `canPerform` as the menu opens, and menus bind their own shortcuts. Opening a
|
|
@@ -406,5 +424,5 @@ in the accessibility tree.
|
|
|
406
424
|
- A `DeskProvider` already carries an event bus; `BusProvider` is only for supplying or sharing one.
|
|
407
425
|
- `renderWindow` must be stable (module scope or `useCallback`) for the memoisation to hold.
|
|
408
426
|
- `parse`/`syncWithLocation` warn once when no `isKnown` is given: unknown ids from a URL are then trusted.
|
|
409
|
-
- `npm run size` enforces a gzipped budget: core
|
|
427
|
+
- `npm run size` enforces a gzipped budget: core 11 KiB, react 46 KiB, css 10 KiB.
|
|
410
428
|
- The package is ESM only, with `"sideEffects": ["**/*.css"]`.
|
package/package.json
CHANGED
package/src/core/desk.ts
CHANGED
|
@@ -8,6 +8,7 @@ import type {
|
|
|
8
8
|
Size,
|
|
9
9
|
WindowId,
|
|
10
10
|
} from './types.js'
|
|
11
|
+
import { fitFrame, stepFrom } from './layouts.js'
|
|
11
12
|
|
|
12
13
|
export interface Desk {
|
|
13
14
|
getState(): DeskState
|
|
@@ -106,6 +107,7 @@ export function createDesk(options: DeskOptions = {}): Desk {
|
|
|
106
107
|
let stage = options.stage ?? (() => DEFAULT_STAGE)
|
|
107
108
|
let state = normalise(options.initial ?? EMPTY)
|
|
108
109
|
const listeners = new Set<(state: DeskState) => void>()
|
|
110
|
+
const layouts = options.layouts
|
|
109
111
|
|
|
110
112
|
const commit = (next: DeskState) => {
|
|
111
113
|
if (next === state) return
|
|
@@ -142,6 +144,7 @@ export function createDesk(options: DeskOptions = {}): Desk {
|
|
|
142
144
|
if (window.mode === 'floating' && !frame) return
|
|
143
145
|
const next = frame ?? fits(remembered.get(id)) ?? nextFrame(state)
|
|
144
146
|
if (frame) remembered.set(id, frame)
|
|
147
|
+
layouts?.save(windowType(id), { mode: 'floating', frame: next })
|
|
145
148
|
commit(toFront(replace(state, { id, mode: 'floating', frame: next }), id))
|
|
146
149
|
}
|
|
147
150
|
|
|
@@ -149,6 +152,7 @@ export function createDesk(options: DeskOptions = {}): Desk {
|
|
|
149
152
|
const window = find(id)
|
|
150
153
|
if (!window || window.mode === 'filled') return
|
|
151
154
|
remembered.set(id, window.frame)
|
|
155
|
+
layouts?.save(windowType(id), { mode: 'filled' })
|
|
152
156
|
commit(toFront(replace(state, { id, mode: 'filled' }), id))
|
|
153
157
|
}
|
|
154
158
|
|
|
@@ -167,8 +171,19 @@ export function createDesk(options: DeskOptions = {}): Desk {
|
|
|
167
171
|
commit(toFront(state, id))
|
|
168
172
|
return
|
|
169
173
|
}
|
|
170
|
-
const
|
|
171
|
-
const
|
|
174
|
+
const saved = opts.mode || opts.frame ? undefined : layouts?.load(windowType(id))
|
|
175
|
+
const kept = saved?.mode === 'floating' ? fitFrame(saved.frame, stage()) : null
|
|
176
|
+
const mode = opts.mode ?? (opts.frame || kept ? 'floating' : 'filled')
|
|
177
|
+
const frame = () => {
|
|
178
|
+
if (opts.frame) return opts.frame
|
|
179
|
+
if (!kept) return nextFrame(state)
|
|
180
|
+
const siblings = state.stack.flatMap(other => {
|
|
181
|
+
const w = find(other)
|
|
182
|
+
return w?.mode === 'floating' && windowType(w.id) === windowType(id) ? [w.frame] : []
|
|
183
|
+
})
|
|
184
|
+
return stepFrom(kept, siblings, stage(), cascade.step, cascade.margin)
|
|
185
|
+
}
|
|
186
|
+
const window: DeskWindow = mode === 'filled' ? { id, mode } : { id, mode, frame: frame() }
|
|
172
187
|
commit({ windows: [...state.windows, window], stack: [...state.stack, id] })
|
|
173
188
|
},
|
|
174
189
|
|
package/src/core/index.ts
CHANGED
|
@@ -29,6 +29,8 @@ export { bindShortcuts, formatShortcut, isApplePlatform, isInstalledApp, matches
|
|
|
29
29
|
export type { Keymap, Shortcut, ShortcutOptions } from './shortcuts.js'
|
|
30
30
|
export { parse, serialize, syncWithLocation } from './location.js'
|
|
31
31
|
export { isTitleCase, titleCase } from './titles.js'
|
|
32
|
+
export { fitFrame, localLayoutStore, stepFrom } from './layouts.js'
|
|
33
|
+
export type { LayoutStore, SavedLayout } from './layouts.js'
|
|
32
34
|
export type { LocationEnv, LocationOptions } from './location.js'
|
|
33
35
|
export type {
|
|
34
36
|
CascadeOptions,
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { Frame, Size } from './types.js'
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* Windows that come back the way they were left. Close a window you had made small and put in a
|
|
5
|
+
* corner, open it tomorrow, and it is small and in the corner again; one you zoomed to fill the desk
|
|
6
|
+
* fills it again.
|
|
7
|
+
*
|
|
8
|
+
* What is remembered is per kind of window, not per id: `query#2` opens where `query` was last left.
|
|
9
|
+
* A remembered frame is a promise about a screen that may have changed, so it is fitted to the
|
|
10
|
+
* current one: moved in until it is on the desk, made smaller if the desk is now smaller, and given
|
|
11
|
+
* up for filling if it would be too small to use. A second window of a kind already open steps down
|
|
12
|
+
* and to the right of it, as a cascade does, rather than opening exactly on top and hiding it.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
export type SavedLayout = { readonly mode: 'filled' } | { readonly mode: 'floating'; readonly frame: Frame }
|
|
16
|
+
|
|
17
|
+
/** Where layouts are kept. Synchronous: a window opens now, not after a round trip. */
|
|
18
|
+
export interface LayoutStore {
|
|
19
|
+
load(type: string): SavedLayout | undefined
|
|
20
|
+
save(type: string, layout: SavedLayout): void
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const MIN: Size = { width: 240, height: 160 }
|
|
24
|
+
|
|
25
|
+
/** Keeps layouts in this browser, under `desk.layouts.<key>`. */
|
|
26
|
+
export function localLayoutStore(key: string): LayoutStore {
|
|
27
|
+
const name = `desk.layouts.${key}`
|
|
28
|
+
const read = (): Record<string, SavedLayout> => {
|
|
29
|
+
try {
|
|
30
|
+
const raw = globalThis.localStorage?.getItem(name)
|
|
31
|
+
const parsed: unknown = raw ? JSON.parse(raw) : {}
|
|
32
|
+
return parsed && typeof parsed === 'object' ? (parsed as Record<string, SavedLayout>) : {}
|
|
33
|
+
} catch {
|
|
34
|
+
return {}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
load: type => valid(read()[type]),
|
|
39
|
+
save(type, layout) {
|
|
40
|
+
try {
|
|
41
|
+
globalThis.localStorage?.setItem(name, JSON.stringify({ ...read(), [type]: layout }))
|
|
42
|
+
} catch {
|
|
43
|
+
// Private windows and full storage: windows still open, just not where they were.
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const finite = (...values: unknown[]) => values.every(v => typeof v === 'number' && Number.isFinite(v))
|
|
50
|
+
|
|
51
|
+
/** Storage is outside the program: anything that is not a layout is treated as none. */
|
|
52
|
+
function valid(layout: unknown): SavedLayout | undefined {
|
|
53
|
+
const l = layout as SavedLayout | undefined
|
|
54
|
+
if (l?.mode === 'filled') return l
|
|
55
|
+
if (l?.mode === 'floating' && l.frame && finite(l.frame.x, l.frame.y, l.frame.width, l.frame.height)) return l
|
|
56
|
+
return undefined
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** A remembered frame on today's desk: on screen, no bigger than the desk, or null if too small to use. */
|
|
60
|
+
export function fitFrame(frame: Frame, stage: Size, min: Size = MIN): Frame | null {
|
|
61
|
+
const width = Math.min(frame.width, stage.width)
|
|
62
|
+
const height = Math.min(frame.height, stage.height)
|
|
63
|
+
if (width < min.width || height < min.height) return null
|
|
64
|
+
return {
|
|
65
|
+
x: Math.max(0, Math.min(frame.x, stage.width - width)),
|
|
66
|
+
y: Math.max(0, Math.min(frame.y, stage.height - height)),
|
|
67
|
+
width,
|
|
68
|
+
height,
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Where another window of a kind goes when some are already free on the desk: a step down and right
|
|
74
|
+
* of the one in front, back to the top-left when that would run off the desk, and never exactly on
|
|
75
|
+
* top of one already there.
|
|
76
|
+
*/
|
|
77
|
+
export function stepFrom(frame: Frame, open: readonly Frame[], stage: Size, step: { x: number; y: number }, margin: number): Frame {
|
|
78
|
+
const front = open.at(-1)
|
|
79
|
+
if (!front) return frame
|
|
80
|
+
const taken = (f: Frame) => open.some(o => o.x === f.x && o.y === f.y)
|
|
81
|
+
let next = { ...frame, x: front.x + step.x, y: front.y + step.y }
|
|
82
|
+
for (let tries = 0; tries <= open.length; tries++) {
|
|
83
|
+
if (next.x + next.width > stage.width || next.y + next.height > stage.height) next = { ...next, x: margin, y: margin }
|
|
84
|
+
if (!taken(next)) return next
|
|
85
|
+
next = { ...next, x: next.x + step.x, y: next.y + step.y }
|
|
86
|
+
}
|
|
87
|
+
return next
|
|
88
|
+
}
|
package/src/core/types.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { LayoutStore } from './layouts.js'
|
|
2
|
+
|
|
1
3
|
export type WindowId = string
|
|
2
4
|
|
|
3
5
|
export interface Frame {
|
|
@@ -40,6 +42,8 @@ export interface DeskOptions {
|
|
|
40
42
|
/** Reports the stage's size, so floating windows open inside it. */
|
|
41
43
|
readonly stage?: () => Size
|
|
42
44
|
readonly initial?: DeskState
|
|
45
|
+
/** Remembers how each kind of window was left, and opens it that way again. */
|
|
46
|
+
readonly layouts?: LayoutStore
|
|
43
47
|
}
|
|
44
48
|
|
|
45
49
|
export interface OpenOptions {
|