@signal9/era-ui 3.17.0 → 4.0.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/generated-docs/llms-full.txt +1 -1
- package/dist/generated-docs/manifest.json +1 -1
- package/dist/generated-docs/pane.md +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +5 -0
- package/dist/os/desktop.svelte +25 -25
- package/dist/os/desktop.svelte.d.ts +3 -3
- package/dist/os/index.d.ts +3 -3
- package/dist/os/index.js +5 -5
- package/dist/os/layers.d.ts +4 -4
- package/dist/os/layers.js +4 -4
- package/dist/os/notification-center.svelte +4 -4
- package/dist/os/{wm.svelte.d.ts → pane-manager.svelte.d.ts} +50 -50
- package/dist/os/{wm.svelte.js → pane-manager.svelte.js} +49 -49
- package/dist/os/{window.svelte → pane.svelte} +35 -34
- package/dist/os/pane.svelte.d.ts +8 -0
- package/dist/os/taskbar.svelte +38 -38
- package/dist/os/taskbar.svelte.d.ts +6 -6
- package/dist/os/workspace-storage.svelte.d.ts +14 -7
- package/dist/os/workspace-storage.svelte.js +118 -62
- package/dist/ui/pane/pane.svelte +2 -2
- package/dist/ui/video-player/video-player.svelte +1 -1
- package/package.json +1 -1
- package/dist/os/window.svelte.d.ts +0 -7
|
@@ -914,7 +914,7 @@ assign to move the pane programmatically (e.g. reset to 0,0). |
|
|
|
914
914
|
| `size?` | `{ width: number; height: number } \| null` | `null` | bindable — Explicit pixel size once resized (or a preset). `null` = auto. Bindable. |
|
|
915
915
|
| `resizable?` | `boolean` | `false` | Render a corner grip and allow the pane to be resized. |
|
|
916
916
|
| `title?` | `string` | — | Text shown in the handle bar. For richer chrome use `header`. |
|
|
917
|
-
| `icon?` | `Component<IconProps> \| null` | `
|
|
917
|
+
| `icon?` | `Component<IconProps> \| null` | `AppPane` | Lucide icon rendered left of the title. Pass `null` to omit. |
|
|
918
918
|
| `disabled?` | `boolean` | `false` | Disables dragging (reactive). |
|
|
919
919
|
| `plugins?` | `(Plugin \| Compartment)[] \| (() => (Plugin \| Compartment)[])` | `[]` | Extra neodrag plugins (axis, bounds, grid, threshold, …) appended
|
|
920
920
|
after the pane's own. Pass Compartments for reactive plugin sets. |
|
|
@@ -20,7 +20,7 @@ assign to move the pane programmatically (e.g. reset to 0,0). |
|
|
|
20
20
|
| `size?` | `{ width: number; height: number } \| null` | `null` | bindable — Explicit pixel size once resized (or a preset). `null` = auto. Bindable. |
|
|
21
21
|
| `resizable?` | `boolean` | `false` | Render a corner grip and allow the pane to be resized. |
|
|
22
22
|
| `title?` | `string` | — | Text shown in the handle bar. For richer chrome use `header`. |
|
|
23
|
-
| `icon?` | `Component<IconProps> \| null` | `
|
|
23
|
+
| `icon?` | `Component<IconProps> \| null` | `AppPane` | Lucide icon rendered left of the title. Pass `null` to omit. |
|
|
24
24
|
| `disabled?` | `boolean` | `false` | Disables dragging (reactive). |
|
|
25
25
|
| `plugins?` | `(Plugin \| Compartment)[] \| (() => (Plugin \| Compartment)[])` | `[]` | Extra neodrag plugins (axis, bounds, grid, threshold, …) appended
|
|
26
26
|
after the pane's own. Pass Compartments for reactive plugin sets. |
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export * from './ui/index.js';
|
|
2
2
|
export * as OS from './os/index.js';
|
|
3
3
|
export * as AI from './ai/index.js';
|
|
4
|
-
export type { Point, Size, Rect, Insets, Frame, Workspace,
|
|
4
|
+
export type { Point, Size, Rect, Insets, Frame, Workspace, PaneState, JsonValue, PaneSnapshot, WorkspaceSnapshot, SnapZone, AppPane, AppDefinition, AppComponent, AppProps } from './os/index.js';
|
|
5
|
+
export { PaneManager, SNAPSHOT_VERSION, readSnapshot, persistWorkspace, loadWorkspace, saveWorkspace, clearWorkspace, WORKSPACE_STORAGE_KEY } from './os/index.js';
|
|
5
6
|
export { cn, tv, hotkeys, keys, parseKeybinding, matchKeyBindingPress, createKeybindingsHandler, formatKeybinding, isApplePlatform, modKey, type KeyBindingMap, type KeyBindingPress, type KeyBindingOptions, type PartProps, type VariantProps } from './utils/index.js';
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
export * from './ui/index.js';
|
|
2
2
|
export * as OS from './os/index.js';
|
|
3
3
|
export * as AI from './ai/index.js';
|
|
4
|
+
// The snapshot + persistence API, flat for the same reason: saving and restoring
|
|
5
|
+
// a desktop is a first-class thing consumers do, not an OS-namespace detail.
|
|
6
|
+
// PaneManager comes with them because it is what every one of these functions
|
|
7
|
+
// takes — without it the flat surface cannot type its own arguments.
|
|
8
|
+
export { PaneManager, SNAPSHOT_VERSION, readSnapshot, persistWorkspace, loadWorkspace, saveWorkspace, clearWorkspace, WORKSPACE_STORAGE_KEY } from './os/index.js';
|
|
4
9
|
export { cn, tv, hotkeys, keys, parseKeybinding, matchKeyBindingPress, createKeybindingsHandler, formatKeybinding, isApplePlatform, modKey } from './utils/index.js';
|
package/dist/os/desktop.svelte
CHANGED
|
@@ -2,20 +2,20 @@
|
|
|
2
2
|
import { untrack, type Snippet } from 'svelte';
|
|
3
3
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
4
4
|
import { cn } from '../utils/index.js';
|
|
5
|
-
import {
|
|
5
|
+
import { PaneManager, setPaneManagerContext } from './pane-manager.svelte.js';
|
|
6
6
|
import { NotificationService, setNotificationContext } from './notifications.svelte.js';
|
|
7
|
-
import
|
|
7
|
+
import Pane from './pane.svelte';
|
|
8
8
|
|
|
9
9
|
let {
|
|
10
|
-
|
|
10
|
+
pm: wmProp,
|
|
11
11
|
notifications: notifProp,
|
|
12
12
|
children,
|
|
13
13
|
class: className,
|
|
14
14
|
...restProps
|
|
15
15
|
}: HTMLAttributes<HTMLDivElement> & {
|
|
16
|
-
/** The
|
|
16
|
+
/** The pane store. Pass your own to drive it from outside, or let the
|
|
17
17
|
* Desktop own one. Exposed via context to every descendant. */
|
|
18
|
-
|
|
18
|
+
pm?: PaneManager;
|
|
19
19
|
/** The notification service, likewise shared via context. */
|
|
20
20
|
notifications?: NotificationService;
|
|
21
21
|
/** Chrome + wallpaper: place <Taskbar>, <Toaster>, <Launcher>,
|
|
@@ -25,10 +25,10 @@
|
|
|
25
25
|
|
|
26
26
|
// The stores are stable singletons for this desktop — read the prop once (or
|
|
27
27
|
// mint a default; untrack makes the one-time read explicit). Set into context
|
|
28
|
-
// so every
|
|
29
|
-
const
|
|
28
|
+
// so every pane/chrome descendant shares it.
|
|
29
|
+
const pm = untrack(() => wmProp) ?? new PaneManager();
|
|
30
30
|
const notifications = untrack(() => notifProp) ?? new NotificationService();
|
|
31
|
-
|
|
31
|
+
setPaneManagerContext(pm);
|
|
32
32
|
setNotificationContext(notifications);
|
|
33
33
|
|
|
34
34
|
// Feed the live viewport size to the store so maximize / snap have real bounds.
|
|
@@ -36,17 +36,17 @@
|
|
|
36
36
|
let h = $state(0);
|
|
37
37
|
let ref = $state<HTMLDivElement | null>(null);
|
|
38
38
|
|
|
39
|
-
// Selection containment: a text drag that starts in one
|
|
39
|
+
// Selection containment: a text drag that starts in one pane must never
|
|
40
40
|
// bleed into its neighbours — while the primary button is down, every
|
|
41
|
-
// OTHER
|
|
41
|
+
// OTHER pane goes user-select:none, restored on release. The browser has
|
|
42
42
|
// no cross-window selection fence (user-select: contain never shipped), so
|
|
43
43
|
// this is the whole mechanism.
|
|
44
44
|
function containSelection(e: PointerEvent) {
|
|
45
45
|
if (e.button !== 0 || !ref) return;
|
|
46
|
-
const origin = (e.target as Element | null)?.closest?.('[data-
|
|
46
|
+
const origin = (e.target as Element | null)?.closest?.('[data-pane]');
|
|
47
47
|
if (!origin) return;
|
|
48
48
|
const muted: HTMLElement[] = [];
|
|
49
|
-
for (const el of ref.querySelectorAll<HTMLElement>('[data-
|
|
49
|
+
for (const el of ref.querySelectorAll<HTMLElement>('[data-pane]')) {
|
|
50
50
|
if (el !== origin) {
|
|
51
51
|
el.style.userSelect = 'none';
|
|
52
52
|
muted.push(el);
|
|
@@ -59,13 +59,13 @@
|
|
|
59
59
|
window.addEventListener('pointercancel', release, { once: true });
|
|
60
60
|
}
|
|
61
61
|
$effect(() => {
|
|
62
|
-
|
|
62
|
+
pm.bounds = { width: w, height: h };
|
|
63
63
|
});
|
|
64
|
-
// Viewport/chrome resizes re-fit the
|
|
65
|
-
//
|
|
64
|
+
// Viewport/chrome resizes re-fit the panes (untracked: relayout reads
|
|
65
|
+
// pane state we must not subscribe to, or every drag would re-run this).
|
|
66
66
|
$effect(() => {
|
|
67
|
-
void
|
|
68
|
-
untrack(() =>
|
|
67
|
+
void pm.workArea;
|
|
68
|
+
untrack(() => pm.relayout());
|
|
69
69
|
});
|
|
70
70
|
|
|
71
71
|
// Document scroll lock: the Desktop IS the viewport, so the page itself must
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
// whole workspace around, which is meaningless for a fixed surface. Lock
|
|
74
74
|
// <html>/<body> for the Desktop's lifetime and restore their prior inline
|
|
75
75
|
// values on unmount, so a consumer's ordinary page is untouched before and
|
|
76
|
-
// after the workspace mounts. Scrolling INSIDE
|
|
76
|
+
// after the workspace mounts. Scrolling INSIDE panes and menus is unaffected
|
|
77
77
|
// — those are their own overflow-auto containers with overscroll-behavior.
|
|
78
78
|
// overscroll-behavior:none is the specific killer for iOS pull-to-refresh and
|
|
79
79
|
// the elastic bounce; overflow:hidden + height stop any residual page scroll.
|
|
@@ -90,10 +90,10 @@
|
|
|
90
90
|
|
|
91
91
|
// Pinch-zoom fence: the workspace is a native-app-like surface, so a
|
|
92
92
|
// two-finger pinch must NOT zoom the whole document (which would scale the
|
|
93
|
-
// chrome away and strand
|
|
93
|
+
// chrome away and strand panes). Safari fires non-standard gesture* events
|
|
94
94
|
// for pinch/rotate; other engines surface it as a multi-touch touchmove.
|
|
95
95
|
// Cancel both — non-passive, so preventDefault actually stops the gesture.
|
|
96
|
-
// (Single-finger
|
|
96
|
+
// (Single-finger pane dragging runs on pointer events and is unaffected; the
|
|
97
97
|
// page can't scroll anyway now, see the scroll lock above.)
|
|
98
98
|
$effect(() => {
|
|
99
99
|
const el = ref;
|
|
@@ -124,16 +124,16 @@
|
|
|
124
124
|
class={cn('relative h-full w-full overflow-hidden overscroll-none bg-(--color-1)', className)}
|
|
125
125
|
{...restProps}
|
|
126
126
|
>
|
|
127
|
-
<!--
|
|
128
|
-
out by the
|
|
127
|
+
<!-- Pane layer: an isolated stacking context. Every pane's z-index (handed
|
|
128
|
+
out by the PaneManager) is trapped in here, so no pane can ever paint
|
|
129
129
|
over the chrome / menus / toasts / launcher that render below (outside it)
|
|
130
130
|
at the document root. This is the whole layer contract in one line. -->
|
|
131
131
|
<div class="absolute inset-0 isolate">
|
|
132
|
-
<!-- Only the active workspace paints; other workspaces'
|
|
132
|
+
<!-- Only the active workspace paints; other workspaces' panes keep
|
|
133
133
|
their state untouched and simply aren't in the tree. Keyed by id, so
|
|
134
134
|
switching back remounts them exactly where they were. -->
|
|
135
|
-
{#each
|
|
136
|
-
<
|
|
135
|
+
{#each pm.activePanes as pane (pane.id)}
|
|
136
|
+
<Pane {pane} />
|
|
137
137
|
{/each}
|
|
138
138
|
</div>
|
|
139
139
|
{@render children?.()}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { type Snippet } from 'svelte';
|
|
2
2
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
-
import {
|
|
3
|
+
import { PaneManager } from './pane-manager.svelte.js';
|
|
4
4
|
import { NotificationService } from './notifications.svelte.js';
|
|
5
5
|
type $$ComponentProps = HTMLAttributes<HTMLDivElement> & {
|
|
6
|
-
/** The
|
|
6
|
+
/** The pane store. Pass your own to drive it from outside, or let the
|
|
7
7
|
* Desktop own one. Exposed via context to every descendant. */
|
|
8
|
-
|
|
8
|
+
pm?: PaneManager;
|
|
9
9
|
/** The notification service, likewise shared via context. */
|
|
10
10
|
notifications?: NotificationService;
|
|
11
11
|
/** Chrome + wallpaper: place <Taskbar>, <Toaster>, <Launcher>,
|
package/dist/os/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { PaneManager, getPaneManager, setPaneManagerContext, type Point, type Size, type Rect, type Insets, type Frame, type AppDefinition, type AppPane, type AppComponent, type AppProps, type PaneState, type JsonValue, type PaneSnapshot, type WorkspaceSnapshot, SNAPSHOT_VERSION, readSnapshot } from './pane-manager.svelte.js';
|
|
2
2
|
export { persistWorkspace, loadWorkspace, saveWorkspace, clearWorkspace, WORKSPACE_STORAGE_KEY } from './workspace-storage.svelte.js';
|
|
3
|
-
export { type SnapZone, type Workspace } from './
|
|
3
|
+
export { type SnapZone, type Workspace } from './pane-manager.svelte.js';
|
|
4
4
|
export { NotificationService, getNotifications, setNotificationContext, type AppNotification, type NotifyOptions, type NotificationAction, type NotificationTone } from './notifications.svelte.js';
|
|
5
5
|
export { LAYER } from './layers.js';
|
|
6
6
|
export { default as Desktop } from './desktop.svelte';
|
|
7
|
-
export { default as
|
|
7
|
+
export { default as Pane } from './pane.svelte';
|
|
8
8
|
export { default as Taskbar } from './taskbar.svelte';
|
|
9
9
|
export { default as Toaster } from './toaster.svelte';
|
|
10
10
|
export { default as Toast } from './toast.svelte';
|
package/dist/os/index.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
// The OS shell layer — stateful orchestration on top of the ui/ widgets.
|
|
2
|
-
// Two stores (
|
|
3
|
-
// components that render them: Desktop host,
|
|
2
|
+
// Two stores (pane manager + notifications) shared via context, and the
|
|
3
|
+
// components that render them: Desktop host, Pane, Taskbar (with its
|
|
4
4
|
// built-in command bar), Toaster, NotificationCenter.
|
|
5
|
-
export {
|
|
5
|
+
export { PaneManager, getPaneManager, setPaneManagerContext, SNAPSHOT_VERSION, readSnapshot } from './pane-manager.svelte.js';
|
|
6
6
|
export { persistWorkspace, loadWorkspace, saveWorkspace, clearWorkspace, WORKSPACE_STORAGE_KEY } from './workspace-storage.svelte.js';
|
|
7
|
-
export {} from './
|
|
7
|
+
export {} from './pane-manager.svelte.js';
|
|
8
8
|
export { NotificationService, getNotifications, setNotificationContext } from './notifications.svelte.js';
|
|
9
9
|
export { LAYER } from './layers.js';
|
|
10
10
|
export { default as Desktop } from './desktop.svelte';
|
|
11
|
-
export { default as
|
|
11
|
+
export { default as Pane } from './pane.svelte';
|
|
12
12
|
export { default as Taskbar } from './taskbar.svelte';
|
|
13
13
|
export { default as Toaster } from './toaster.svelte';
|
|
14
14
|
export { default as Toast } from './toast.svelte';
|
package/dist/os/layers.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The layer contract for the OS shell.
|
|
3
3
|
*
|
|
4
|
-
* The hard rule desktop UIs get wrong: a
|
|
4
|
+
* The hard rule desktop UIs get wrong: a pane's z-index must NEVER be able to
|
|
5
5
|
* cover a menu, toast, or the taskbar's command dropdown. We guarantee that structurally rather
|
|
6
6
|
* than by juggling numbers — the `Desktop` surface is an isolated stacking
|
|
7
|
-
* context (`isolate`), so every
|
|
8
|
-
*
|
|
7
|
+
* context (`isolate`), so every pane's z-index (1..N, handed out by the
|
|
8
|
+
* PaneManager) is *contained* within it. OS chrome and portalled overlays
|
|
9
9
|
* render OUTSIDE that context, at the document root, so they always paint above
|
|
10
|
-
* the entire desktop no matter how high a
|
|
10
|
+
* the entire desktop no matter how high a pane's z climbs.
|
|
11
11
|
*
|
|
12
12
|
* These are the root-level tiers (all above the isolated desktop). bits-ui
|
|
13
13
|
* dialogs/menus/tooltips portal to <body> at z-50; the tiers below are chosen
|
package/dist/os/layers.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The layer contract for the OS shell.
|
|
3
3
|
*
|
|
4
|
-
* The hard rule desktop UIs get wrong: a
|
|
4
|
+
* The hard rule desktop UIs get wrong: a pane's z-index must NEVER be able to
|
|
5
5
|
* cover a menu, toast, or the taskbar's command dropdown. We guarantee that structurally rather
|
|
6
6
|
* than by juggling numbers — the `Desktop` surface is an isolated stacking
|
|
7
|
-
* context (`isolate`), so every
|
|
8
|
-
*
|
|
7
|
+
* context (`isolate`), so every pane's z-index (1..N, handed out by the
|
|
8
|
+
* PaneManager) is *contained* within it. OS chrome and portalled overlays
|
|
9
9
|
* render OUTSIDE that context, at the document root, so they always paint above
|
|
10
|
-
* the entire desktop no matter how high a
|
|
10
|
+
* the entire desktop no matter how high a pane's z climbs.
|
|
11
11
|
*
|
|
12
12
|
* These are the root-level tiers (all above the isolated desktop). bits-ui
|
|
13
13
|
* dialogs/menus/tooltips portal to <body> at z-50; the tiers below are chosen
|
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
import BellOff from '@lucide/svelte/icons/bell-off';
|
|
6
6
|
import { cn } from '../utils/index.js';
|
|
7
7
|
import { getNotifications, type AppNotification } from './notifications.svelte.js';
|
|
8
|
-
import {
|
|
8
|
+
import { getPaneManager } from './pane-manager.svelte.js';
|
|
9
9
|
import { LAYER } from './layers.js';
|
|
10
10
|
|
|
11
11
|
let { open = $bindable(false) }: { open?: boolean } = $props();
|
|
12
12
|
const notif = getNotifications();
|
|
13
|
-
const
|
|
13
|
+
const pm = getPaneManager();
|
|
14
14
|
|
|
15
15
|
const accent: Record<AppNotification['tone'], string> = {
|
|
16
16
|
default: 'bg-(--era-highlight)',
|
|
@@ -46,8 +46,8 @@
|
|
|
46
46
|
it down, a bottom one stops it short — so it never slides under a bar. -->
|
|
47
47
|
<aside
|
|
48
48
|
transition:eraFly={{ x: 320, duration: 200 }}
|
|
49
|
-
style:top="{
|
|
50
|
-
style:bottom="{
|
|
49
|
+
style:top="{pm.insets.top}px"
|
|
50
|
+
style:bottom="{pm.insets.bottom}px"
|
|
51
51
|
class="absolute right-0 flex w-80 flex-col border-l border-divider-faded bg-(--era-surface-bg) shadow-(--era-shadow-lg) glass-blur"
|
|
52
52
|
>
|
|
53
53
|
<header
|
|
@@ -20,8 +20,8 @@ export interface Insets {
|
|
|
20
20
|
bottom: number;
|
|
21
21
|
left: number;
|
|
22
22
|
}
|
|
23
|
-
/** A
|
|
24
|
-
* been set (`null` = auto — the
|
|
23
|
+
/** A pane's placement: where it sits, and its explicit size once one has
|
|
24
|
+
* been set (`null` = auto — the pane is content-sized until the user or a
|
|
25
25
|
* preset gives it real dimensions, so we never invent numbers). */
|
|
26
26
|
export interface Frame {
|
|
27
27
|
pos: Point;
|
|
@@ -50,26 +50,26 @@ export type JsonValue = string | number | boolean | null | JsonValue[] | {
|
|
|
50
50
|
*/
|
|
51
51
|
export declare const SNAPSHOT_VERSION = 1;
|
|
52
52
|
/**
|
|
53
|
-
* One
|
|
53
|
+
* One pane, reduced to what a reload cannot reconstruct.
|
|
54
54
|
*
|
|
55
|
-
* Deliberately NOT a partial
|
|
55
|
+
* Deliberately NOT a partial AppPane. A live pane holds a `component` and an
|
|
56
56
|
* `icon`, which are functions; those come from the app registry and are looked
|
|
57
57
|
* up again on restore by `appId`. Storing an id instead of a reference is also
|
|
58
58
|
* what lets a snapshot outlive a refactor of the app itself.
|
|
59
59
|
*/
|
|
60
|
-
export interface
|
|
61
|
-
/** The registered app this
|
|
60
|
+
export interface PaneSnapshot {
|
|
61
|
+
/** The registered app this pane rehydrates from. */
|
|
62
62
|
appId: string;
|
|
63
63
|
/** The workspace it belongs to. */
|
|
64
64
|
workspaceId: string;
|
|
65
65
|
/** Placement when `state` is 'normal'. */
|
|
66
66
|
frame: Frame;
|
|
67
|
-
state:
|
|
67
|
+
state: PaneState;
|
|
68
68
|
/** Where to land on un-maximize / un-snap; null if it was never moved. */
|
|
69
69
|
restore: Frame | null;
|
|
70
70
|
/** Stacking order within its workspace. */
|
|
71
71
|
z: number;
|
|
72
|
-
/** Only when the
|
|
72
|
+
/** Only when the pane was retitled away from its app's default. */
|
|
73
73
|
title?: string;
|
|
74
74
|
/**
|
|
75
75
|
* App-specific state — the note being edited, a scroll offset, a filter.
|
|
@@ -92,7 +92,7 @@ export interface WorkspaceSnapshot {
|
|
|
92
92
|
savedAt: number;
|
|
93
93
|
activeWorkspaceId: string;
|
|
94
94
|
workspaces: Workspace[];
|
|
95
|
-
|
|
95
|
+
panes: PaneSnapshot[];
|
|
96
96
|
}
|
|
97
97
|
/**
|
|
98
98
|
* Parse untrusted JSON into a snapshot, or return null.
|
|
@@ -103,28 +103,28 @@ export interface WorkspaceSnapshot {
|
|
|
103
103
|
* trusting `as`, and refuses an unknown `version` outright — silently importing
|
|
104
104
|
* a layout you only half understand is worse than declining it.
|
|
105
105
|
*
|
|
106
|
-
* Individual
|
|
106
|
+
* Individual panes are filtered, not fatal: one malformed entry should not
|
|
107
107
|
* cost the user the rest of the layout. applySnapshot() drops unknown appIds the
|
|
108
108
|
* same way, for the same reason.
|
|
109
109
|
*/
|
|
110
110
|
export declare function readSnapshot(json: string): WorkspaceSnapshot | null;
|
|
111
|
-
export type
|
|
111
|
+
export type PaneState = 'normal' | 'minimized' | 'maximized';
|
|
112
112
|
/** Snap targets: the four edges (halves) or four corners (quadrants). */
|
|
113
113
|
export type SnapZone = 'left' | 'right' | 'top' | 'bottom' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
|
|
114
|
-
/** Props every app body receives — its own
|
|
114
|
+
/** Props every app body receives — its own pane record and the manager, so it
|
|
115
115
|
* can read its state and drive the desktop (close itself, spawn more…). */
|
|
116
116
|
export type AppProps = {
|
|
117
|
-
|
|
118
|
-
|
|
117
|
+
pane: AppPane;
|
|
118
|
+
pm: PaneManager;
|
|
119
119
|
};
|
|
120
|
-
/** What a
|
|
120
|
+
/** What a pane renders as its body. */
|
|
121
121
|
export type AppComponent = Component<AppProps>;
|
|
122
|
-
/** A registered "app": the template every
|
|
122
|
+
/** A registered "app": the template every pane of that app is spawned from. */
|
|
123
123
|
export interface AppDefinition {
|
|
124
124
|
id: string;
|
|
125
125
|
title: string;
|
|
126
126
|
icon?: Component<IconProps> | null;
|
|
127
|
-
/** Body renderer. Omit for a chromeless/placeholder
|
|
127
|
+
/** Body renderer. Omit for a chromeless/placeholder pane. */
|
|
128
128
|
component?: AppComponent;
|
|
129
129
|
defaultSize?: Size;
|
|
130
130
|
/** Only one live instance; opening again focuses the existing one. */
|
|
@@ -135,27 +135,27 @@ export interface AppDefinition {
|
|
|
135
135
|
* × gesture won't arm it and taskbar tabs only focus — minimize() and
|
|
136
136
|
* toggleMinimize() become focus-only no-ops. */
|
|
137
137
|
minimizable?: boolean;
|
|
138
|
-
/** Extra classes for the
|
|
138
|
+
/** Extra classes for the pane body (Pane.Content) — e.g. `p-(--era-gap)`
|
|
139
139
|
* for a body of controls, or `p-0` for a full-bleed app. */
|
|
140
140
|
bodyClass?: string;
|
|
141
141
|
/**
|
|
142
|
-
* Starting app state for every
|
|
143
|
-
*
|
|
142
|
+
* Starting app state for every pane spawned from this app — the value a
|
|
143
|
+
* pane carries in its snapshot's `props`. An app reads it back off
|
|
144
144
|
* `window.props` (AppProps hands the whole record over).
|
|
145
145
|
*/
|
|
146
146
|
props?: JsonValue;
|
|
147
147
|
/** Extra title-bar controls, rendered immediately LEFT of the close button.
|
|
148
148
|
* For per-window affordances that belong on the chrome rather than in the
|
|
149
149
|
* body — a help/usage launcher, a pin, a view toggle. Assignable on the
|
|
150
|
-
* live
|
|
150
|
+
* live AppPane too, so a host can swap it as the pane's content
|
|
151
151
|
* changes. */
|
|
152
152
|
actions?: Snippet;
|
|
153
153
|
}
|
|
154
|
-
/** A live
|
|
155
|
-
export interface
|
|
154
|
+
/** A live pane instance in the registry. */
|
|
155
|
+
export interface AppPane {
|
|
156
156
|
id: string;
|
|
157
157
|
appId: string;
|
|
158
|
-
/** The workspace this
|
|
158
|
+
/** The workspace this pane lives on. */
|
|
159
159
|
workspaceId: string;
|
|
160
160
|
title: string;
|
|
161
161
|
icon?: Component<IconProps> | null;
|
|
@@ -165,7 +165,7 @@ export interface AppWindow {
|
|
|
165
165
|
size: Size | null;
|
|
166
166
|
/** Stacking order within the desktop (higher = nearer the front). */
|
|
167
167
|
z: number;
|
|
168
|
-
state:
|
|
168
|
+
state: PaneState;
|
|
169
169
|
/** Frame snapshot to restore to after un-maximize / un-snap. */
|
|
170
170
|
restore: Frame | null;
|
|
171
171
|
component?: AppComponent;
|
|
@@ -176,24 +176,24 @@ export interface AppWindow {
|
|
|
176
176
|
/** App-specific state, carried verbatim through a snapshot. */
|
|
177
177
|
props?: JsonValue;
|
|
178
178
|
}
|
|
179
|
-
/** A named virtual desktop. Every
|
|
180
|
-
* active workspace's
|
|
179
|
+
/** A named virtual desktop. Every pane belongs to exactly one; only the
|
|
180
|
+
* active workspace's panes are shown, the rest keep their geometry and
|
|
181
181
|
* stacking untouched until switched back to. */
|
|
182
182
|
export interface Workspace {
|
|
183
183
|
id: string;
|
|
184
184
|
name: string;
|
|
185
185
|
}
|
|
186
186
|
/**
|
|
187
|
-
* The source of truth for the desktop: which workspaces and
|
|
187
|
+
* The source of truth for the desktop: which workspaces and panes exist,
|
|
188
188
|
* their geometry, and their stacking / focus order. Everything visual
|
|
189
|
-
* (Desktop,
|
|
189
|
+
* (Desktop, Pane, Taskbar, Launcher, …) is a pure view of this. Runes-based,
|
|
190
190
|
* shared via context.
|
|
191
191
|
*/
|
|
192
|
-
export declare class
|
|
192
|
+
export declare class PaneManager {
|
|
193
193
|
#private;
|
|
194
|
-
/** Every live
|
|
194
|
+
/** Every live pane, across all workspaces. Order is spawn order; paint
|
|
195
195
|
* order is by `z`; visibility is by workspace. */
|
|
196
|
-
|
|
196
|
+
panes: AppPane[];
|
|
197
197
|
/** Registered app templates, keyed by id. */
|
|
198
198
|
apps: Record<string, AppDefinition>;
|
|
199
199
|
/** The virtual desktops. Always at least one. */
|
|
@@ -206,42 +206,42 @@ export declare class WindowManager {
|
|
|
206
206
|
* The work area = bounds − insets; maximize, snap and drag containment
|
|
207
207
|
* honour it. */
|
|
208
208
|
insets: Insets;
|
|
209
|
-
/** Drag containment: a
|
|
209
|
+
/** Drag containment: a pane's bar may never leave the top of the work
|
|
210
210
|
* area, and at least this many px of it must stay reachable on every
|
|
211
211
|
* other side. */
|
|
212
212
|
dragKeep: number;
|
|
213
213
|
/** The usable desktop: bounds minus reserved chrome. Everything that places
|
|
214
|
-
* a
|
|
214
|
+
* a pane against "the screen" (maximize, snap, containment) uses this,
|
|
215
215
|
* never raw bounds — a strip hidden behind chrome is as lost as one
|
|
216
216
|
* off-screen. */
|
|
217
217
|
workArea: Rect;
|
|
218
|
-
/** The active workspace's
|
|
218
|
+
/** The active workspace's panes — what the Desktop paints and the
|
|
219
219
|
* Taskbar lists. */
|
|
220
|
-
|
|
221
|
-
/** The focused
|
|
220
|
+
activePanes: AppPane[];
|
|
221
|
+
/** The focused pane = the top-most non-minimized one on the active
|
|
222
222
|
* workspace. */
|
|
223
223
|
focusedId: string | null;
|
|
224
224
|
register(app: AppDefinition): void;
|
|
225
225
|
registerMany(apps: AppDefinition[]): void;
|
|
226
|
-
/** Spawn a
|
|
226
|
+
/** Spawn a pane for an app (or focus the existing one if it's a
|
|
227
227
|
* singleton — from any workspace; it is brought to the active one). */
|
|
228
|
-
open(appId: string, overrides?: Partial<Pick<
|
|
228
|
+
open(appId: string, overrides?: Partial<Pick<AppPane, 'title' | 'pos' | 'size' | 'resizable' | 'workspaceId'>>): string | null;
|
|
229
229
|
close(id: string): void;
|
|
230
|
-
/** Make a
|
|
230
|
+
/** Make a pane the frontmost VISIBLE one: switch to its workspace,
|
|
231
231
|
* un-minimize it, and bring it to the front. Focus means reveal at every
|
|
232
232
|
* level — never a silent off-screen z bump. */
|
|
233
233
|
focus(id: string): void;
|
|
234
234
|
minimize(id: string): void;
|
|
235
235
|
/** Taskbar behaviour: focus if not focused, else minimize; restore if minimized. */
|
|
236
236
|
toggleMinimize(id: string): void;
|
|
237
|
-
/** Fill the work area (middle-click on the
|
|
237
|
+
/** Fill the work area (middle-click on the pane's ×). Keeps the first
|
|
238
238
|
* pre-maximize/pre-snap frame so restore returns to the true origin. */
|
|
239
239
|
maximize(id: string): void;
|
|
240
240
|
toggleMaximize(id: string): void;
|
|
241
241
|
/** Un-maximize / un-snap back to the pre-change frame (or just un-minimize). */
|
|
242
242
|
restore(id: string): void;
|
|
243
|
-
/** Re-fit
|
|
244
|
-
*
|
|
243
|
+
/** Re-fit panes after the desktop or its chrome resizes: maximized
|
|
244
|
+
* panes re-fill the work area; normal panes re-clamp so the bar stays
|
|
245
245
|
* below the top and at least dragKeep px stays reachable on every other
|
|
246
246
|
* side — the same fence the drag containment enforces, applied at rest.
|
|
247
247
|
* The Desktop calls this whenever the work area changes; chrome itself
|
|
@@ -250,7 +250,7 @@ export declare class WindowManager {
|
|
|
250
250
|
/**
|
|
251
251
|
* The whole desktop as one JSON-safe document.
|
|
252
252
|
*
|
|
253
|
-
* Reads every workspace and every
|
|
253
|
+
* Reads every workspace and every pane across ALL of them, not just the
|
|
254
254
|
* active one — a snapshot that only captured what was on screen would quietly
|
|
255
255
|
* drop the other workspaces the moment it was restored.
|
|
256
256
|
*/
|
|
@@ -259,11 +259,11 @@ export declare class WindowManager {
|
|
|
259
259
|
* Replace the desktop with a snapshot.
|
|
260
260
|
*
|
|
261
261
|
* Named applySnapshot, not restore: `restore(id)` already means "un-maximize
|
|
262
|
-
* this
|
|
262
|
+
* this pane", and one verb cannot mean both.
|
|
263
263
|
*
|
|
264
264
|
* Windows whose `appId` is no longer registered are SKIPPED rather than
|
|
265
265
|
* failing the whole restore: an app can be removed between export and import,
|
|
266
|
-
* and losing one
|
|
266
|
+
* and losing one pane beats losing the layout. Same for a pane pointing at
|
|
267
267
|
* a workspace the snapshot does not contain.
|
|
268
268
|
*/
|
|
269
269
|
applySnapshot(snapshot: WorkspaceSnapshot): void;
|
|
@@ -275,12 +275,12 @@ export declare class WindowManager {
|
|
|
275
275
|
}): string;
|
|
276
276
|
/** Show a workspace. Windows on others keep their geometry and stacking. */
|
|
277
277
|
switchWorkspace(id: string): void;
|
|
278
|
-
/** Remove a workspace. Its
|
|
278
|
+
/** Remove a workspace. Its panes migrate to the fallback (the active
|
|
279
279
|
* workspace, or the first remaining one) — closing a desktop never
|
|
280
280
|
* silently closes the work on it. The last workspace can't be removed. */
|
|
281
281
|
removeWorkspace(id: string): void;
|
|
282
|
-
/** Send a
|
|
282
|
+
/** Send a pane to another workspace (it stays where it was on screen). */
|
|
283
283
|
moveToWorkspace(windowId: string, workspaceId: string): void;
|
|
284
284
|
}
|
|
285
|
-
export declare function
|
|
286
|
-
export declare function
|
|
285
|
+
export declare function setPaneManagerContext(pm: PaneManager): PaneManager;
|
|
286
|
+
export declare function getPaneManager(): PaneManager;
|