@owdproject/core 3.4.0 → 4.0.0-alpha.4
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 +112 -13
- package/dist/dom/index.d.mts +65 -0
- package/dist/dom/index.d.ts +65 -0
- package/dist/dom/index.mjs +224 -0
- package/dist/events/index.d.mts +70 -0
- package/dist/events/index.d.ts +70 -0
- package/dist/events/index.mjs +3 -0
- package/dist/index.d.mts +73 -0
- package/dist/index.d.ts +73 -0
- package/dist/index.mjs +115 -0
- package/dist/layout/index.d.mts +41 -0
- package/dist/layout/index.d.ts +41 -0
- package/dist/layout/index.mjs +64 -0
- package/dist/machines/index.d.mts +31 -0
- package/dist/machines/index.d.ts +31 -0
- package/dist/machines/index.mjs +2 -0
- package/dist/managers/index.d.mts +118 -0
- package/dist/managers/index.d.ts +118 -0
- package/dist/managers/index.mjs +6 -0
- package/dist/session/index.d.mts +57 -0
- package/dist/session/index.d.ts +57 -0
- package/dist/session/index.mjs +65 -0
- package/dist/shared/core.B1XxB289.mjs +239 -0
- package/dist/shared/core.B3mp7ztE.mjs +237 -0
- package/dist/shared/core.BOvFdEVQ.d.ts +114 -0
- package/dist/shared/core.CsDFgGnX.mjs +40 -0
- package/dist/shared/core.Di1eFcr_.d.mts +114 -0
- package/dist/shared/core.Pd_Ogt4g.mjs +101 -0
- package/dist/shared/core.b3Xldzyu.mjs +29 -0
- package/dist/shared/core.d_A3q1kZ.mjs +869 -0
- package/dist/types/index.d.mts +266 -0
- package/dist/types/index.d.ts +266 -0
- package/dist/types/index.mjs +1 -0
- package/package.json +56 -112
- package/CHANGELOG.md +0 -98
- package/DESKTOP_KERNEL.md +0 -232
- package/MIGRATION_3.3.2.md +0 -23
- package/MIGRATION_3.4.md +0 -126
- package/PLAYGROUND.md +0 -91
- package/dist/module.d.mts +0 -13
- package/dist/module.json +0 -9
- package/dist/module.mjs +0 -254
- package/dist/types.d.mts +0 -7
- package/index.ts +0 -8
- package/kit/authoring.ts +0 -340
- package/kit/defineDesktopApp.ts +0 -56
- package/module.ts +0 -203
- package/runtime/components/Application/DesktopCoreApplicationRender.vue +0 -20
- package/runtime/components/Application/DesktopCoreApplicationWindowsRender.vue +0 -38
- package/runtime/components/background/DesktopCoreBackground.vue +0 -16
- package/runtime/components/core/DesktopCore.vue +0 -43
- package/runtime/components/time/DesktopCoreTime.vue +0 -56
- package/runtime/components/window/DesktopCoreWindow.vue +0 -215
- package/runtime/components/window/DesktopCoreWindowContent.vue +0 -28
- package/runtime/components/window/DesktopCoreWindowNav.vue +0 -66
- package/runtime/components/window/DesktopCoreWindowSnapHintsBase.vue +0 -74
- package/runtime/components/workspace/DesktopCoreWorkspaceEdgeHintsBase.vue +0 -84
- package/runtime/composables/useApplicationEntries.ts +0 -51
- package/runtime/composables/useApplicationManager.ts +0 -285
- package/runtime/composables/useBlockNonInputContextMenu.ts +0 -30
- package/runtime/composables/useDesktopConfig.ts +0 -8
- package/runtime/composables/useDesktopDialogs.ts +0 -16
- package/runtime/composables/useDesktopExtension.ts +0 -8
- package/runtime/composables/useDesktopManager.ts +0 -51
- package/runtime/composables/useDesktopManifest.ts +0 -17
- package/runtime/composables/useDesktopSession.ts +0 -27
- package/runtime/composables/useDesktopShellIdentity.ts +0 -99
- package/runtime/composables/useDesktopShellOptions.ts +0 -36
- package/runtime/composables/useDesktopShellReady.ts +0 -7
- package/runtime/composables/useDesktopWorkArea.ts +0 -93
- package/runtime/composables/useTerminalManager.ts +0 -159
- package/runtime/composables/useToggleWindowMaximize.ts +0 -35
- package/runtime/composables/useWindowDragHandlers.ts +0 -47
- package/runtime/composables/useWindowSnapDrop.ts +0 -112
- package/runtime/composables/useWorkspaceEdgeDrop.ts +0 -176
- package/runtime/composables/useWorkspaceManager.ts +0 -67
- package/runtime/composables/useWorkspaceOverviewCapture.ts +0 -92
- package/runtime/composables/useWorkspaceOverviewLiveScale.ts +0 -151
- package/runtime/constants/desktopShellKeys.ts +0 -12
- package/runtime/constants/shellLayout.ts +0 -5
- package/runtime/dialogs/desktopDialogProvider.ts +0 -73
- package/runtime/internal/controllers/ApplicationController.ts +0 -351
- package/runtime/internal/controllers/WindowController.ts +0 -547
- package/runtime/plugins/01.desktop-shell-init.client.ts +0 -28
- package/runtime/plugins/02.desktop-register-desktop-apps.client.ts +0 -13
- package/runtime/plugins/resize.client.ts +0 -6
- package/runtime/stores/storeApplicationMeta.ts +0 -60
- package/runtime/stores/storeApplicationWindows.ts +0 -21
- package/runtime/stores/storeDesktop.ts +0 -71
- package/runtime/stores/storeDesktopDefaultApps.ts +0 -54
- package/runtime/stores/storeDesktopVolume.ts +0 -19
- package/runtime/stores/storeDesktopWindow.ts +0 -38
- package/runtime/stores/storeDesktopWorkspace.ts +0 -105
- package/runtime/stores/storeIds.ts +0 -35
- package/runtime/types/desktopMenu.ts +0 -10
- package/runtime/utils/initDesktopShell.ts +0 -80
- package/runtime/utils/migratePersistedStoreIds.ts +0 -57
- package/runtime/utils/utilApp.ts +0 -25
- package/runtime/utils/utilCaptureElementToCanvas.ts +0 -21
- package/runtime/utils/utilCommon.ts +0 -26
- package/runtime/utils/utilDebug.ts +0 -30
- package/runtime/utils/utilDetectSnapZone.ts +0 -57
- package/runtime/utils/utilTerminal.ts +0 -6
- package/runtime/utils/utilWindowControllerAdapter.ts +0 -15
- package/runtime/utils/utilWindowLayout.ts +0 -82
- package/runtime/utils/utilWindowMaximizeLayout.ts +0 -44
- package/runtime/utils/utilWorkspaceWindows.ts +0 -33
- package/types/index.d.ts +0 -531
package/README.md
CHANGED
|
@@ -1,22 +1,121 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
<h1>@owdproject/core</h1>
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
<p>
|
|
6
|
+
<strong>A TypeScript runtime for web desktop interfaces.</strong><br /><br />
|
|
7
|
+
A deterministic, framework-independent runtime for multi-window workspaces,<br />
|
|
8
|
+
XState v5 process orchestration, magnetic snap geometry, and W3C Pointer math.
|
|
9
|
+
</p>
|
|
6
10
|
|
|
7
|
-
|
|
11
|
+
<br />
|
|
8
12
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
+
<p>
|
|
14
|
+
<a href="https://npmjs.com/package/@owdproject/core"><img src="https://img.shields.io/npm/v/@owdproject/core/alpha.svg?style=flat&colorA=020420&colorB=00DC82" alt="npm version" /></a>
|
|
15
|
+
<a href="https://npm.chart.dev/@owdproject/core"><img src="https://img.shields.io/npm/dm/@owdproject/core.svg?style=flat&colorA=020420&colorB=00DC82" alt="npm downloads" /></a>
|
|
16
|
+
<a href="https://github.com/owdproject/core/blob/main/LICENSE"><img src="https://img.shields.io/badge/License-MIT-00DC82.svg?style=flat&colorA=020420&colorB=00DC82" alt="License" /></a>
|
|
17
|
+
</p>
|
|
13
18
|
|
|
14
|
-
|
|
19
|
+
<p>
|
|
20
|
+
<a href="#overview">Overview</a> ·
|
|
21
|
+
<a href="#architecture--capabilities">Architecture</a> ·
|
|
22
|
+
<a href="#quick-start">Quick Start</a> ·
|
|
23
|
+
<a href="#desktop-subsystems-createdesktop">Subsystems API</a> ·
|
|
24
|
+
<a href="#official-framework-adapters">Adapters</a>
|
|
25
|
+
</p>
|
|
15
26
|
|
|
16
|
-
|
|
17
|
-
pnpm add @owdproject/core
|
|
18
|
-
\`\`\`
|
|
27
|
+
</div>
|
|
19
28
|
|
|
20
29
|
---
|
|
21
30
|
|
|
22
|
-
|
|
31
|
+
## Overview
|
|
32
|
+
|
|
33
|
+
`@owdproject/core` (`4.0.0-alpha.0`) is the pure TypeScript & XState v5 engine behind [Open Web Desktop](https://github.com/owdproject/nuxt-desktop).
|
|
34
|
+
|
|
35
|
+
Completely decoupled from any UI framework, it exposes `createDesktop()`—an isolated desktop kernel encapsulating window management, application lifecycle states (`PID`, `SIGSTOP`, `SIGCONT`, `SIGTERM`, `SIGKILL`), virtual workspaces, CLI command parsing, a 19-event `hookable` lifecycle bus, a pub/sub IPC bus, and a Pointer Events drag/resize engine.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Architecture & Capabilities
|
|
40
|
+
|
|
41
|
+
* **Zero UI Framework Dependencies** — Pure TypeScript, `xstate` v5, `hookable`, `nanoid`, `getopts`, and `shellwords`. Runs identically in browsers, SSR, and Node.js test suites.
|
|
42
|
+
* **Frozen Immutable Snapshots (`Object.freeze`)** — Every window, process, and workspace transition emits a frozen snapshot compatible with React `useSyncExternalStore`, Vue `shallowRef`, Svelte stores, and Angular signals.
|
|
43
|
+
* **Deterministic XState v5 Machines** — `windowMachine` and `applicationMachine` prevent invalid state combinations across maximization, snapping, minimization, and process suspension.
|
|
44
|
+
* **W3C Pointer Engine & `IframeGuard`** — Native `setPointerCapture` drag and 8-directional resize math with magnetic snap-zone detection (`left-half`, `right-half`, `maximize`, corners) and automatic `<iframe>` pointer-event protection.
|
|
45
|
+
* **Cancellable Runtime Hooks** — Intercept and cancel `app:before-launch`, `window:before-open`, `command:before-exec`, or `workspace:before-switch` via `desktop.hooks`.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Quick Start
|
|
50
|
+
|
|
51
|
+
Install `@owdproject/core`:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pnpm add @owdproject/core@4.0.0-alpha.0
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Create an isolated desktop instance with `createDesktop()`:
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
import { createDesktop } from '@owdproject/core'
|
|
61
|
+
|
|
62
|
+
const desktop = createDesktop({
|
|
63
|
+
workspaces: ['ws-main', 'ws-dev'],
|
|
64
|
+
activeWorkspace: 'ws-main',
|
|
65
|
+
workarea: { x: 0, y: 32, width: 1920, height: 1048 },
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
// Spawn a window
|
|
69
|
+
const win = desktop.windows.createWindow({
|
|
70
|
+
id: 'terminal-1',
|
|
71
|
+
model: 'terminal',
|
|
72
|
+
config: {
|
|
73
|
+
title: 'Terminal',
|
|
74
|
+
size: { width: 680, height: 440, minWidth: 320, minHeight: 220 },
|
|
75
|
+
position: { x: 120, y: 80 },
|
|
76
|
+
resizable: true,
|
|
77
|
+
maximizable: true,
|
|
78
|
+
minimizable: true,
|
|
79
|
+
},
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
// Snap to left half of workarea
|
|
83
|
+
win.setLayout('left-half', desktop.workspaces.workarea)
|
|
84
|
+
|
|
85
|
+
// Subscribe to immutable desktop snapshots
|
|
86
|
+
desktop.subscribe((snapshot) => {
|
|
87
|
+
console.log('Active windows:', snapshot.windows.length)
|
|
88
|
+
})
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Desktop Subsystems (`createDesktop()`)
|
|
94
|
+
|
|
95
|
+
| Subsystem | Type | Responsibility |
|
|
96
|
+
| :--- | :--- | :--- |
|
|
97
|
+
| **`desktop.windows`** | `WindowManager` | Window lookup, focus stacking, snap zones, and `tileWindows('horizontal' \| 'vertical' \| 'grid')`. |
|
|
98
|
+
| **`desktop.applications`** | `ApplicationManager` | Application manifest registry, `PID` allocation, and Unix signals (`suspend`, `resume`, `terminate`). |
|
|
99
|
+
| **`desktop.workspaces`** | `WorkspaceManager` | Virtual workspace switching, overview state, and workarea rectangle geometry. |
|
|
100
|
+
| **`desktop.commands`** | `DesktopCommands` | CLI command registry, tokenizer, and `exec()` dispatcher. |
|
|
101
|
+
| **`desktop.hooks`** | `Hookable<DesktopRuntimeHooks>` | 19 synchronous/asynchronous lifecycle hooks with `before-*` cancellation support. |
|
|
102
|
+
| **`desktop.ipc`** | `CoreIPCBus` | Cross-application pub/sub bus with wildcard (`*`) listener and event history ring buffer. |
|
|
103
|
+
| **`desktop.session`** | `{ serialize, restore }` | JSON session serialization and hydration for active windows and workspaces. |
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Official Framework Adapters
|
|
108
|
+
|
|
109
|
+
* **[@owdproject/nuxt](https://npmjs.com/package/@owdproject/nuxt)** — Official Nuxt & Vue 3 reactive composables and `WindowController`.
|
|
110
|
+
* **[@owdproject/react](https://npmjs.com/package/@owdproject/react)** — Official React 18/19 concurrent-safe hooks (`useSyncExternalStore`).
|
|
111
|
+
* **[@owdproject/svelte](https://npmjs.com/package/@owdproject/svelte)** — Official Svelte 4/5 `Readable` stores and pointer actions.
|
|
112
|
+
* **[@owdproject/angular](https://npmjs.com/package/@owdproject/angular)** — Official Angular 17+ `DesktopAdapterService` and reactive streams.
|
|
113
|
+
* **[@owdproject/astro](https://npmjs.com/package/@owdproject/astro)** — Official Astro multi-framework Islands and `<owd-desktop-window>` Custom Element.
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## License
|
|
118
|
+
|
|
119
|
+
[MIT](https://opensource.org/licenses/MIT)
|
|
120
|
+
|
|
121
|
+
Copyright (c) 2024-present, [Diego Villa (@dxlliv)](https://github.com/dxlliv) and Open Web Desktop contributors.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { WindowBounds, DesktopWorkareaRect, SnapZoneHint } from '../types/index.mjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* IframeGuard: prevents embedded <iframe> apps from stealing pointer events
|
|
5
|
+
* during window dragging and resizing across all frameworks.
|
|
6
|
+
*/
|
|
7
|
+
declare class IframeGuard {
|
|
8
|
+
/**
|
|
9
|
+
* Disables pointer events on all iframes in the document.
|
|
10
|
+
* Safe to call repeatedly; uses reference counting.
|
|
11
|
+
*/
|
|
12
|
+
static enable(selector?: string): void;
|
|
13
|
+
/**
|
|
14
|
+
* Restores pointer events on all iframes once all active operations end.
|
|
15
|
+
*/
|
|
16
|
+
static disable(selector?: string): void;
|
|
17
|
+
/**
|
|
18
|
+
* Guard an asynchronous or synchronous action with automatic enable/disable.
|
|
19
|
+
*/
|
|
20
|
+
static wrap<T>(action: () => Promise<T> | T, selector?: string): Promise<T>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @owdproject/core - Framework-Agnostic W3C Pointer Events Engine
|
|
25
|
+
* High-performance, zero-framework Drag & Resize controller with Pointer Capture,
|
|
26
|
+
* Boundary Clamping, 8-directional Resizing, and IframeGuard integration.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
type ResizeDirection = 'n' | 's' | 'e' | 'w' | 'ne' | 'nw' | 'se' | 'sw';
|
|
30
|
+
interface DragSessionOptions {
|
|
31
|
+
initialBounds: WindowBounds;
|
|
32
|
+
workarea?: DesktopWorkareaRect;
|
|
33
|
+
minDistanceToDrag?: number;
|
|
34
|
+
onStart?: () => void;
|
|
35
|
+
onMove?: (bounds: WindowBounds, snapZone: SnapZoneHint | null) => void;
|
|
36
|
+
onEnd?: (finalBounds: WindowBounds, snapZone: SnapZoneHint | null) => void;
|
|
37
|
+
onCancel?: () => void;
|
|
38
|
+
}
|
|
39
|
+
interface ResizeSessionOptions {
|
|
40
|
+
direction: ResizeDirection;
|
|
41
|
+
initialBounds: WindowBounds;
|
|
42
|
+
minWidth?: number;
|
|
43
|
+
minHeight?: number;
|
|
44
|
+
maxWidth?: number;
|
|
45
|
+
maxHeight?: number;
|
|
46
|
+
workarea?: DesktopWorkareaRect;
|
|
47
|
+
onStart?: () => void;
|
|
48
|
+
onMove?: (bounds: WindowBounds) => void;
|
|
49
|
+
onEnd?: (finalBounds: WindowBounds) => void;
|
|
50
|
+
onCancel?: () => void;
|
|
51
|
+
}
|
|
52
|
+
declare class DesktopPointerSession {
|
|
53
|
+
/**
|
|
54
|
+
* Starts an agnostic pointer drag operation on any DOM element.
|
|
55
|
+
* Uses setPointerCapture to guarantee smooth tracking even if the cursor leaves the window.
|
|
56
|
+
*/
|
|
57
|
+
static startDrag(event: PointerEvent, options: DragSessionOptions): () => void;
|
|
58
|
+
/**
|
|
59
|
+
* Starts an agnostic 8-directional pointer resize operation on any DOM element.
|
|
60
|
+
*/
|
|
61
|
+
static startResize(event: PointerEvent, options: ResizeSessionOptions): () => void;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export { DesktopPointerSession, IframeGuard };
|
|
65
|
+
export type { DragSessionOptions, ResizeDirection, ResizeSessionOptions };
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { WindowBounds, DesktopWorkareaRect, SnapZoneHint } from '../types/index.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* IframeGuard: prevents embedded <iframe> apps from stealing pointer events
|
|
5
|
+
* during window dragging and resizing across all frameworks.
|
|
6
|
+
*/
|
|
7
|
+
declare class IframeGuard {
|
|
8
|
+
/**
|
|
9
|
+
* Disables pointer events on all iframes in the document.
|
|
10
|
+
* Safe to call repeatedly; uses reference counting.
|
|
11
|
+
*/
|
|
12
|
+
static enable(selector?: string): void;
|
|
13
|
+
/**
|
|
14
|
+
* Restores pointer events on all iframes once all active operations end.
|
|
15
|
+
*/
|
|
16
|
+
static disable(selector?: string): void;
|
|
17
|
+
/**
|
|
18
|
+
* Guard an asynchronous or synchronous action with automatic enable/disable.
|
|
19
|
+
*/
|
|
20
|
+
static wrap<T>(action: () => Promise<T> | T, selector?: string): Promise<T>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @owdproject/core - Framework-Agnostic W3C Pointer Events Engine
|
|
25
|
+
* High-performance, zero-framework Drag & Resize controller with Pointer Capture,
|
|
26
|
+
* Boundary Clamping, 8-directional Resizing, and IframeGuard integration.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
type ResizeDirection = 'n' | 's' | 'e' | 'w' | 'ne' | 'nw' | 'se' | 'sw';
|
|
30
|
+
interface DragSessionOptions {
|
|
31
|
+
initialBounds: WindowBounds;
|
|
32
|
+
workarea?: DesktopWorkareaRect;
|
|
33
|
+
minDistanceToDrag?: number;
|
|
34
|
+
onStart?: () => void;
|
|
35
|
+
onMove?: (bounds: WindowBounds, snapZone: SnapZoneHint | null) => void;
|
|
36
|
+
onEnd?: (finalBounds: WindowBounds, snapZone: SnapZoneHint | null) => void;
|
|
37
|
+
onCancel?: () => void;
|
|
38
|
+
}
|
|
39
|
+
interface ResizeSessionOptions {
|
|
40
|
+
direction: ResizeDirection;
|
|
41
|
+
initialBounds: WindowBounds;
|
|
42
|
+
minWidth?: number;
|
|
43
|
+
minHeight?: number;
|
|
44
|
+
maxWidth?: number;
|
|
45
|
+
maxHeight?: number;
|
|
46
|
+
workarea?: DesktopWorkareaRect;
|
|
47
|
+
onStart?: () => void;
|
|
48
|
+
onMove?: (bounds: WindowBounds) => void;
|
|
49
|
+
onEnd?: (finalBounds: WindowBounds) => void;
|
|
50
|
+
onCancel?: () => void;
|
|
51
|
+
}
|
|
52
|
+
declare class DesktopPointerSession {
|
|
53
|
+
/**
|
|
54
|
+
* Starts an agnostic pointer drag operation on any DOM element.
|
|
55
|
+
* Uses setPointerCapture to guarantee smooth tracking even if the cursor leaves the window.
|
|
56
|
+
*/
|
|
57
|
+
static startDrag(event: PointerEvent, options: DragSessionOptions): () => void;
|
|
58
|
+
/**
|
|
59
|
+
* Starts an agnostic 8-directional pointer resize operation on any DOM element.
|
|
60
|
+
*/
|
|
61
|
+
static startResize(event: PointerEvent, options: ResizeSessionOptions): () => void;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export { DesktopPointerSession, IframeGuard };
|
|
65
|
+
export type { DragSessionOptions, ResizeDirection, ResizeSessionOptions };
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { d as detectSnapZone } from '../shared/core.b3Xldzyu.mjs';
|
|
2
|
+
import '../shared/core.CsDFgGnX.mjs';
|
|
3
|
+
|
|
4
|
+
let activeGuardCount = 0;
|
|
5
|
+
const originalPointerEventsMap = /* @__PURE__ */ new WeakMap();
|
|
6
|
+
class IframeGuard {
|
|
7
|
+
/**
|
|
8
|
+
* Disables pointer events on all iframes in the document.
|
|
9
|
+
* Safe to call repeatedly; uses reference counting.
|
|
10
|
+
*/
|
|
11
|
+
static enable(selector = "iframe") {
|
|
12
|
+
if (typeof document === "undefined") return;
|
|
13
|
+
activeGuardCount++;
|
|
14
|
+
if (activeGuardCount === 1) {
|
|
15
|
+
const iframes = document.querySelectorAll(selector);
|
|
16
|
+
iframes.forEach((iframe) => {
|
|
17
|
+
originalPointerEventsMap.set(iframe, iframe.style.pointerEvents);
|
|
18
|
+
iframe.style.pointerEvents = "none";
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Restores pointer events on all iframes once all active operations end.
|
|
24
|
+
*/
|
|
25
|
+
static disable(selector = "iframe") {
|
|
26
|
+
if (typeof document === "undefined") return;
|
|
27
|
+
activeGuardCount = Math.max(0, activeGuardCount - 1);
|
|
28
|
+
if (activeGuardCount === 0) {
|
|
29
|
+
const iframes = document.querySelectorAll(selector);
|
|
30
|
+
iframes.forEach((iframe) => {
|
|
31
|
+
const orig = originalPointerEventsMap.get(iframe) ?? "";
|
|
32
|
+
iframe.style.pointerEvents = orig;
|
|
33
|
+
originalPointerEventsMap.delete(iframe);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Guard an asynchronous or synchronous action with automatic enable/disable.
|
|
39
|
+
*/
|
|
40
|
+
static async wrap(action, selector = "iframe") {
|
|
41
|
+
IframeGuard.enable(selector);
|
|
42
|
+
try {
|
|
43
|
+
return await action();
|
|
44
|
+
} finally {
|
|
45
|
+
IframeGuard.disable(selector);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
class DesktopPointerSession {
|
|
51
|
+
/**
|
|
52
|
+
* Starts an agnostic pointer drag operation on any DOM element.
|
|
53
|
+
* Uses setPointerCapture to guarantee smooth tracking even if the cursor leaves the window.
|
|
54
|
+
*/
|
|
55
|
+
static startDrag(event, options) {
|
|
56
|
+
if (typeof window === "undefined") return () => {
|
|
57
|
+
};
|
|
58
|
+
const target = event.currentTarget;
|
|
59
|
+
const pointerId = event.pointerId;
|
|
60
|
+
const startX = event.clientX;
|
|
61
|
+
const startY = event.clientY;
|
|
62
|
+
const { initialBounds, workarea, minDistanceToDrag = 3 } = options;
|
|
63
|
+
let hasStarted = false;
|
|
64
|
+
let currentBounds = { ...initialBounds };
|
|
65
|
+
let currentSnapZone = null;
|
|
66
|
+
try {
|
|
67
|
+
target?.setPointerCapture(pointerId);
|
|
68
|
+
} catch {
|
|
69
|
+
}
|
|
70
|
+
const onPointerMove = (e) => {
|
|
71
|
+
if (e.pointerId !== pointerId) return;
|
|
72
|
+
const deltaX = e.clientX - startX;
|
|
73
|
+
const deltaY = e.clientY - startY;
|
|
74
|
+
if (!hasStarted) {
|
|
75
|
+
const distance = Math.hypot(deltaX, deltaY);
|
|
76
|
+
if (distance >= minDistanceToDrag) {
|
|
77
|
+
hasStarted = true;
|
|
78
|
+
IframeGuard.enable();
|
|
79
|
+
options.onStart?.();
|
|
80
|
+
} else {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
let newX = initialBounds.x + deltaX;
|
|
85
|
+
let newY = initialBounds.y + deltaY;
|
|
86
|
+
if (workarea) {
|
|
87
|
+
const minVisiblePx = 40;
|
|
88
|
+
newX = Math.max(workarea.x - initialBounds.width + minVisiblePx, Math.min(newX, workarea.x + workarea.width - minVisiblePx));
|
|
89
|
+
newY = Math.max(workarea.y, Math.min(newY, workarea.y + workarea.height - 30));
|
|
90
|
+
}
|
|
91
|
+
currentBounds = {
|
|
92
|
+
x: Math.round(newX),
|
|
93
|
+
y: Math.round(newY),
|
|
94
|
+
width: initialBounds.width,
|
|
95
|
+
height: initialBounds.height
|
|
96
|
+
};
|
|
97
|
+
if (workarea) {
|
|
98
|
+
currentSnapZone = detectSnapZone(e.clientX, e.clientY, workarea);
|
|
99
|
+
}
|
|
100
|
+
options.onMove?.(currentBounds, currentSnapZone);
|
|
101
|
+
};
|
|
102
|
+
const cleanup = () => {
|
|
103
|
+
window.removeEventListener("pointermove", onPointerMove);
|
|
104
|
+
window.removeEventListener("pointerup", onPointerUp);
|
|
105
|
+
window.removeEventListener("pointercancel", onPointerCancel);
|
|
106
|
+
try {
|
|
107
|
+
if (target?.hasPointerCapture(pointerId)) {
|
|
108
|
+
target.releasePointerCapture(pointerId);
|
|
109
|
+
}
|
|
110
|
+
} catch {
|
|
111
|
+
}
|
|
112
|
+
IframeGuard.disable();
|
|
113
|
+
};
|
|
114
|
+
const onPointerUp = (e) => {
|
|
115
|
+
if (e.pointerId !== pointerId) return;
|
|
116
|
+
cleanup();
|
|
117
|
+
if (hasStarted) {
|
|
118
|
+
options.onEnd?.(currentBounds, currentSnapZone);
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
const onPointerCancel = (e) => {
|
|
122
|
+
if (e.pointerId !== pointerId) return;
|
|
123
|
+
cleanup();
|
|
124
|
+
if (hasStarted) {
|
|
125
|
+
options.onCancel?.();
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
window.addEventListener("pointermove", onPointerMove, { passive: false });
|
|
129
|
+
window.addEventListener("pointerup", onPointerUp, { passive: true });
|
|
130
|
+
window.addEventListener("pointercancel", onPointerCancel, { passive: true });
|
|
131
|
+
return cleanup;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Starts an agnostic 8-directional pointer resize operation on any DOM element.
|
|
135
|
+
*/
|
|
136
|
+
static startResize(event, options) {
|
|
137
|
+
if (typeof window === "undefined") return () => {
|
|
138
|
+
};
|
|
139
|
+
const target = event.currentTarget;
|
|
140
|
+
const pointerId = event.pointerId;
|
|
141
|
+
const startX = event.clientX;
|
|
142
|
+
const startY = event.clientY;
|
|
143
|
+
const {
|
|
144
|
+
direction,
|
|
145
|
+
initialBounds,
|
|
146
|
+
minWidth = 240,
|
|
147
|
+
minHeight = 160,
|
|
148
|
+
maxWidth = 3840,
|
|
149
|
+
maxHeight = 2160
|
|
150
|
+
} = options;
|
|
151
|
+
let currentBounds = { ...initialBounds };
|
|
152
|
+
try {
|
|
153
|
+
target?.setPointerCapture(pointerId);
|
|
154
|
+
} catch {
|
|
155
|
+
}
|
|
156
|
+
IframeGuard.enable();
|
|
157
|
+
options.onStart?.();
|
|
158
|
+
const onPointerMove = (e) => {
|
|
159
|
+
if (e.pointerId !== pointerId) return;
|
|
160
|
+
const deltaX = e.clientX - startX;
|
|
161
|
+
const deltaY = e.clientY - startY;
|
|
162
|
+
let { x, y, width, height } = initialBounds;
|
|
163
|
+
if (direction.includes("e")) {
|
|
164
|
+
width = Math.min(maxWidth, Math.max(minWidth, initialBounds.width + deltaX));
|
|
165
|
+
} else if (direction.includes("w")) {
|
|
166
|
+
const potentialWidth = initialBounds.width - deltaX;
|
|
167
|
+
if (potentialWidth >= minWidth && potentialWidth <= maxWidth) {
|
|
168
|
+
width = potentialWidth;
|
|
169
|
+
x = initialBounds.x + deltaX;
|
|
170
|
+
} else if (potentialWidth < minWidth) {
|
|
171
|
+
width = minWidth;
|
|
172
|
+
x = initialBounds.x + (initialBounds.width - minWidth);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
if (direction.includes("s")) {
|
|
176
|
+
height = Math.min(maxHeight, Math.max(minHeight, initialBounds.height + deltaY));
|
|
177
|
+
} else if (direction.includes("n")) {
|
|
178
|
+
const potentialHeight = initialBounds.height - deltaY;
|
|
179
|
+
if (potentialHeight >= minHeight && potentialHeight <= maxHeight) {
|
|
180
|
+
height = potentialHeight;
|
|
181
|
+
y = initialBounds.y + deltaY;
|
|
182
|
+
} else if (potentialHeight < minHeight) {
|
|
183
|
+
height = minHeight;
|
|
184
|
+
y = initialBounds.y + (initialBounds.height - minHeight);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
currentBounds = {
|
|
188
|
+
x: Math.round(x),
|
|
189
|
+
y: Math.round(y),
|
|
190
|
+
width: Math.round(width),
|
|
191
|
+
height: Math.round(height)
|
|
192
|
+
};
|
|
193
|
+
options.onMove?.(currentBounds);
|
|
194
|
+
};
|
|
195
|
+
const cleanup = () => {
|
|
196
|
+
window.removeEventListener("pointermove", onPointerMove);
|
|
197
|
+
window.removeEventListener("pointerup", onPointerUp);
|
|
198
|
+
window.removeEventListener("pointercancel", onPointerCancel);
|
|
199
|
+
try {
|
|
200
|
+
if (target?.hasPointerCapture(pointerId)) {
|
|
201
|
+
target.releasePointerCapture(pointerId);
|
|
202
|
+
}
|
|
203
|
+
} catch {
|
|
204
|
+
}
|
|
205
|
+
IframeGuard.disable();
|
|
206
|
+
};
|
|
207
|
+
const onPointerUp = (e) => {
|
|
208
|
+
if (e.pointerId !== pointerId) return;
|
|
209
|
+
cleanup();
|
|
210
|
+
options.onEnd?.(currentBounds);
|
|
211
|
+
};
|
|
212
|
+
const onPointerCancel = (e) => {
|
|
213
|
+
if (e.pointerId !== pointerId) return;
|
|
214
|
+
cleanup();
|
|
215
|
+
options.onCancel?.();
|
|
216
|
+
};
|
|
217
|
+
window.addEventListener("pointermove", onPointerMove, { passive: false });
|
|
218
|
+
window.addEventListener("pointerup", onPointerUp, { passive: true });
|
|
219
|
+
window.addEventListener("pointercancel", onPointerCancel, { passive: true });
|
|
220
|
+
return cleanup;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export { DesktopPointerSession, IframeGuard };
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { C as CoreIPCBus } from '../shared/core.Di1eFcr_.mjs';
|
|
2
|
+
import { WindowManager } from '../index.mjs';
|
|
3
|
+
export { E as EventHandler, g as globalIPCBus } from '../shared/core.Di1eFcr_.mjs';
|
|
4
|
+
import { Hookable } from 'hookable';
|
|
5
|
+
import { DesktopRuntimeHooks, DesktopWorkareaRect, CommandOutput, DesktopCommand } from '../types/index.mjs';
|
|
6
|
+
|
|
7
|
+
declare function createDesktopHooks(): Hookable<DesktopRuntimeHooks>;
|
|
8
|
+
declare const globalDesktopHooks: Hookable<DesktopRuntimeHooks>;
|
|
9
|
+
|
|
10
|
+
declare function shellEscape(str: string): string;
|
|
11
|
+
declare function padEnd(str: string, len: number): string;
|
|
12
|
+
declare function formatDuration(ms: number): string;
|
|
13
|
+
declare function parseCommandLine(input: string): {
|
|
14
|
+
name: string;
|
|
15
|
+
args: string[];
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @owdproject/core - Framework-Agnostic Desktop Keybindings Engine
|
|
20
|
+
* Listens to OS-level shortcuts (Alt+Tab, Super+Arrows, Close, Minimize) and triggers actions.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
interface KeybindingActionContext {
|
|
24
|
+
event: KeyboardEvent;
|
|
25
|
+
windowManager: WindowManager;
|
|
26
|
+
workarea?: DesktopWorkareaRect;
|
|
27
|
+
}
|
|
28
|
+
type KeybindingHandler = (ctx: KeybindingActionContext) => void | boolean;
|
|
29
|
+
declare class DesktopKeybindings {
|
|
30
|
+
private windowManager;
|
|
31
|
+
private workareaProvider?;
|
|
32
|
+
private customHandlers;
|
|
33
|
+
private isListening;
|
|
34
|
+
private listenerRef?;
|
|
35
|
+
constructor(windowManager: WindowManager, options?: {
|
|
36
|
+
workareaProvider?: () => DesktopWorkareaRect | undefined;
|
|
37
|
+
});
|
|
38
|
+
register(shortcut: string, handler: KeybindingHandler): this;
|
|
39
|
+
listen(): () => void;
|
|
40
|
+
stop(): void;
|
|
41
|
+
private handleKeyDown;
|
|
42
|
+
private cycleWindowFocus;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
type DesktopCommandHandler = (args: string[], rawInput: string) => Promise<CommandOutput | string | void> | CommandOutput | string | void;
|
|
46
|
+
interface RegisteredDesktopCommand extends DesktopCommand {
|
|
47
|
+
handler: DesktopCommandHandler;
|
|
48
|
+
}
|
|
49
|
+
declare class DesktopCommands {
|
|
50
|
+
private commands;
|
|
51
|
+
private snapshotCache;
|
|
52
|
+
private subscribers;
|
|
53
|
+
private hooks;
|
|
54
|
+
private ipc;
|
|
55
|
+
constructor(options?: {
|
|
56
|
+
hooks?: Hookable<DesktopRuntimeHooks>;
|
|
57
|
+
ipc?: CoreIPCBus;
|
|
58
|
+
});
|
|
59
|
+
getSnapshot(): DesktopCommand[];
|
|
60
|
+
subscribe(callback: (commands: DesktopCommand[]) => void): () => void;
|
|
61
|
+
private notify;
|
|
62
|
+
register(command: DesktopCommand, handler: DesktopCommandHandler): () => void;
|
|
63
|
+
unregister(name: string): boolean;
|
|
64
|
+
has(name: string): boolean;
|
|
65
|
+
getCommands(): DesktopCommand[];
|
|
66
|
+
exec(input: string): Promise<CommandOutput | void>;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export { CoreIPCBus, DesktopCommands, DesktopKeybindings, DesktopRuntimeHooks, createDesktopHooks, formatDuration, globalDesktopHooks, padEnd, parseCommandLine, shellEscape };
|
|
70
|
+
export type { DesktopCommandHandler, KeybindingActionContext, KeybindingHandler, RegisteredDesktopCommand };
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { C as CoreIPCBus } from '../shared/core.BOvFdEVQ.js';
|
|
2
|
+
import { WindowManager } from '../index.js';
|
|
3
|
+
export { E as EventHandler, g as globalIPCBus } from '../shared/core.BOvFdEVQ.js';
|
|
4
|
+
import { Hookable } from 'hookable';
|
|
5
|
+
import { DesktopRuntimeHooks, DesktopWorkareaRect, CommandOutput, DesktopCommand } from '../types/index.js';
|
|
6
|
+
|
|
7
|
+
declare function createDesktopHooks(): Hookable<DesktopRuntimeHooks>;
|
|
8
|
+
declare const globalDesktopHooks: Hookable<DesktopRuntimeHooks>;
|
|
9
|
+
|
|
10
|
+
declare function shellEscape(str: string): string;
|
|
11
|
+
declare function padEnd(str: string, len: number): string;
|
|
12
|
+
declare function formatDuration(ms: number): string;
|
|
13
|
+
declare function parseCommandLine(input: string): {
|
|
14
|
+
name: string;
|
|
15
|
+
args: string[];
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @owdproject/core - Framework-Agnostic Desktop Keybindings Engine
|
|
20
|
+
* Listens to OS-level shortcuts (Alt+Tab, Super+Arrows, Close, Minimize) and triggers actions.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
interface KeybindingActionContext {
|
|
24
|
+
event: KeyboardEvent;
|
|
25
|
+
windowManager: WindowManager;
|
|
26
|
+
workarea?: DesktopWorkareaRect;
|
|
27
|
+
}
|
|
28
|
+
type KeybindingHandler = (ctx: KeybindingActionContext) => void | boolean;
|
|
29
|
+
declare class DesktopKeybindings {
|
|
30
|
+
private windowManager;
|
|
31
|
+
private workareaProvider?;
|
|
32
|
+
private customHandlers;
|
|
33
|
+
private isListening;
|
|
34
|
+
private listenerRef?;
|
|
35
|
+
constructor(windowManager: WindowManager, options?: {
|
|
36
|
+
workareaProvider?: () => DesktopWorkareaRect | undefined;
|
|
37
|
+
});
|
|
38
|
+
register(shortcut: string, handler: KeybindingHandler): this;
|
|
39
|
+
listen(): () => void;
|
|
40
|
+
stop(): void;
|
|
41
|
+
private handleKeyDown;
|
|
42
|
+
private cycleWindowFocus;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
type DesktopCommandHandler = (args: string[], rawInput: string) => Promise<CommandOutput | string | void> | CommandOutput | string | void;
|
|
46
|
+
interface RegisteredDesktopCommand extends DesktopCommand {
|
|
47
|
+
handler: DesktopCommandHandler;
|
|
48
|
+
}
|
|
49
|
+
declare class DesktopCommands {
|
|
50
|
+
private commands;
|
|
51
|
+
private snapshotCache;
|
|
52
|
+
private subscribers;
|
|
53
|
+
private hooks;
|
|
54
|
+
private ipc;
|
|
55
|
+
constructor(options?: {
|
|
56
|
+
hooks?: Hookable<DesktopRuntimeHooks>;
|
|
57
|
+
ipc?: CoreIPCBus;
|
|
58
|
+
});
|
|
59
|
+
getSnapshot(): DesktopCommand[];
|
|
60
|
+
subscribe(callback: (commands: DesktopCommand[]) => void): () => void;
|
|
61
|
+
private notify;
|
|
62
|
+
register(command: DesktopCommand, handler: DesktopCommandHandler): () => void;
|
|
63
|
+
unregister(name: string): boolean;
|
|
64
|
+
has(name: string): boolean;
|
|
65
|
+
getCommands(): DesktopCommand[];
|
|
66
|
+
exec(input: string): Promise<CommandOutput | void>;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export { CoreIPCBus, DesktopCommands, DesktopKeybindings, DesktopRuntimeHooks, createDesktopHooks, formatDuration, globalDesktopHooks, padEnd, parseCommandLine, shellEscape };
|
|
70
|
+
export type { DesktopCommandHandler, KeybindingActionContext, KeybindingHandler, RegisteredDesktopCommand };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { C as CoreIPCBus, c as createDesktopHooks, g as globalDesktopHooks, a as globalIPCBus } from '../shared/core.Pd_Ogt4g.mjs';
|
|
2
|
+
export { D as DesktopCommands, a as DesktopKeybindings, f as formatDuration, p as padEnd, b as parseCommandLine, s as shellEscape } from '../shared/core.B1XxB289.mjs';
|
|
3
|
+
import 'hookable';
|