@owdproject/core 3.3.1 → 4.0.0-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/README.md +91 -59
  2. package/dist/dom/index.d.mts +65 -0
  3. package/dist/dom/index.d.ts +65 -0
  4. package/dist/dom/index.mjs +224 -0
  5. package/dist/events/index.d.mts +70 -0
  6. package/dist/events/index.d.ts +70 -0
  7. package/dist/events/index.mjs +3 -0
  8. package/dist/index.d.mts +73 -0
  9. package/dist/index.d.ts +73 -0
  10. package/dist/index.mjs +115 -0
  11. package/dist/layout/index.d.mts +41 -0
  12. package/dist/layout/index.d.ts +41 -0
  13. package/dist/layout/index.mjs +64 -0
  14. package/dist/machines/index.d.mts +31 -0
  15. package/dist/machines/index.d.ts +31 -0
  16. package/dist/machines/index.mjs +2 -0
  17. package/dist/managers/index.d.mts +117 -0
  18. package/dist/managers/index.d.ts +117 -0
  19. package/dist/managers/index.mjs +6 -0
  20. package/dist/session/index.d.mts +57 -0
  21. package/dist/session/index.d.ts +57 -0
  22. package/dist/session/index.mjs +65 -0
  23. package/dist/shared/core.B0B0KfVK.mjs +865 -0
  24. package/dist/shared/core.B1XxB289.mjs +239 -0
  25. package/dist/shared/core.B3mp7ztE.mjs +237 -0
  26. package/dist/shared/core.BOvFdEVQ.d.ts +114 -0
  27. package/dist/shared/core.CsDFgGnX.mjs +40 -0
  28. package/dist/shared/core.Di1eFcr_.d.mts +114 -0
  29. package/dist/shared/core.Pd_Ogt4g.mjs +101 -0
  30. package/dist/shared/core.b3Xldzyu.mjs +29 -0
  31. package/dist/types/index.d.mts +266 -0
  32. package/dist/types/index.d.ts +266 -0
  33. package/dist/types/index.mjs +1 -0
  34. package/package.json +60 -87
  35. package/bin/cli.js +0 -395
  36. package/bin/desktop.js +0 -5
  37. package/bin/lib/catalog.js +0 -293
  38. package/bin/lib/config.js +0 -109
  39. package/bin/lib/desktopConfig.js +0 -56
  40. package/bin/lib/generateTemplate.js +0 -389
  41. package/bin/lib/install.js +0 -408
  42. package/bin/lib/migrateModulePlayground.config.mjs +0 -164
  43. package/bin/lib/migrateModulePlayground.mjs +0 -313
  44. package/bin/lib/npmVersions.js +0 -124
  45. package/bin/lib/playgroundContext.js +0 -188
  46. package/bin/lib/scaffold.js +0 -197
  47. package/bin/lib/status.js +0 -289
  48. package/bin/lib/validateModule.js +0 -697
  49. package/bin/lib/workspace.js +0 -182
  50. package/bin/owd.js +0 -5
  51. package/bin/tui.js +0 -1379
  52. package/dist/module.d.mts +0 -13
  53. package/dist/module.json +0 -9
  54. package/dist/module.mjs +0 -268
  55. package/dist/types.d.mts +0 -7
  56. package/index.ts +0 -5
  57. package/module.ts +0 -223
  58. package/runtime/components/Desktop/Application/DesktopApplicationRender.vue +0 -20
  59. package/runtime/components/Desktop/Application/DesktopApplicationWindowsRender.vue +0 -38
  60. package/runtime/components/Desktop/Background/DesktopBackground.vue +0 -16
  61. package/runtime/components/Desktop/Core/DesktopCore.vue +0 -90
  62. package/runtime/components/Desktop/Time/DesktopTime.vue +0 -56
  63. package/runtime/components/Desktop/Window/DesktopWindow.vue +0 -204
  64. package/runtime/components/Desktop/Window/DesktopWindowContent.vue +0 -28
  65. package/runtime/components/Desktop/Window/DesktopWindowNav.vue +0 -66
  66. package/runtime/composables/useApplicationEntries.ts +0 -51
  67. package/runtime/composables/useApplicationManager.ts +0 -285
  68. package/runtime/composables/useDesktopManager.ts +0 -49
  69. package/runtime/composables/useTerminalManager.ts +0 -66
  70. package/runtime/composables/useWorkspaceManager.ts +0 -41
  71. package/runtime/internal/controllers/ApplicationController.ts +0 -345
  72. package/runtime/internal/controllers/WindowController.ts +0 -462
  73. package/runtime/plugins/02.desktop-register-desktop-apps.client.ts +0 -17
  74. package/runtime/plugins/resize.client.ts +0 -6
  75. package/runtime/stores/storeApplicationMeta.ts +0 -59
  76. package/runtime/stores/storeApplicationWindows.ts +0 -20
  77. package/runtime/stores/storeDesktop.ts +0 -111
  78. package/runtime/stores/storeDesktopDefaultApps.ts +0 -53
  79. package/runtime/stores/storeDesktopVolume.ts +0 -18
  80. package/runtime/stores/storeDesktopWindow.ts +0 -20
  81. package/runtime/stores/storeDesktopWorkspace.ts +0 -75
  82. package/runtime/utils/captureElementToCanvas.ts +0 -21
  83. package/runtime/utils/explorerEntryPath.ts +0 -10
  84. package/runtime/utils/resolveDesktopConfigPath.ts +0 -52
  85. package/runtime/utils/splitDesktopUserConfig.ts +0 -85
  86. package/runtime/utils/utilApp.ts +0 -37
  87. package/runtime/utils/utilCommon.ts +0 -26
  88. package/runtime/utils/utilDebug.ts +0 -30
  89. package/runtime/utils/utilDesktop.ts +0 -35
  90. package/runtime/utils/utilTerminal.ts +0 -6
  91. package/runtime/utils/utilWindow.ts +0 -15
  92. package/runtime/utils/validateDesktopUserConfig.ts +0 -44
  93. package/types/index.d.ts +0 -420
package/README.md CHANGED
@@ -1,89 +1,121 @@
1
- <p align="center">
2
- <img width="160" height="160" src="https://avatars.githubusercontent.com/u/65117737?s=160&v=4" />
3
- </p>
4
- <h1 align="center">Open Web Desktop</h1>
5
- <h3 align="center">
6
- A modular framework for building web-based desktop experiences.
7
- </h3>
1
+ <div align="center">
8
2
 
9
- ## Overview
10
-
11
- Open Web Desktop (OWD) is a framework designed to provide a simple environment for building web-based desktop experiences. It's built with TypeScript on top of the Nuxt.js framework.
12
-
13
- [Demo](https://atproto-os.pages.dev/) · [Community](https://discord.gg/zPNaN2HAaA) · [Documentation](https://owdproject.org/)
3
+ <h1>@owdproject/core</h1>
14
4
 
15
- ## Features
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>
16
10
 
17
- - Fully extendable through themes, apps, and modules
18
- - Bundled with popular Vue.js libraries like Pinia and VueUse
19
- - Designed to make the most of the Nuxt.js ecosystem
20
- - Styled with PrimeVue and Tailwind for a consistent UI
21
- - Fully localizable with nuxt-i18n support
11
+ <br />
22
12
 
23
- ## Getting started
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>
24
18
 
25
- Bootstrap a new project by running:
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>
26
26
 
27
- ```bash
28
- npm create owd
29
- ```
27
+ </div>
30
28
 
31
- Once the process is done, you can start to develop:
29
+ ---
32
30
 
33
- ```bash
34
- cd owd-client
31
+ ## Overview
35
32
 
36
- # Run the dev server with hot-reload
37
- pnpm install
38
- pnpm run dev
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).
39
34
 
40
- # Build for production
41
- pnpm run generate
42
- ```
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.
43
36
 
44
- ## Extend your desktop
37
+ ---
45
38
 
46
- Thanks to Tailwind and PrimeVue, you can create custom themes from scratch and ensure a consistent look across all apps. Each theme defines its own style, making your desktop both cohesive and uniquely yours.
39
+ ## Architecture & Capabilities
47
40
 
48
- [Applications](https://github.com/topics/owd-apps) · [Modules](https://github.com/topics/owd-modules) · [Themes](https://github.com/topics/owd-themes)
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`.
49
46
 
50
- ### 🧩 Install an app
47
+ ---
51
48
 
52
- Discover apps by searching the [owd-apps](https://github.com/topics/owd-apps) tag on GitHub.
49
+ ## Quick Start
53
50
 
54
- For example, to add the To-do app:
51
+ Install `@owdproject/core`:
55
52
 
56
53
  ```bash
57
- desktop add app-todo
54
+ pnpm add @owdproject/core@4.0.0-alpha.0
58
55
  ```
59
56
 
60
- Shipped with `@owdproject/core` (`bin/desktop.js`). The `owd` binary is a deprecated alias.
61
-
62
- ### 🧩 Install a module
63
-
64
- Discover modules by searching the [owd-modules](https://github.com/topics/owd-modules) tag on GitHub.
65
-
66
- For example, to add Pinia persistence backed by IndexedDB (`idb-keyval`):
67
-
68
- ```bash
69
- desktop add module-pinia-idb
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
+ })
70
89
  ```
71
90
 
72
- ### 🖥️ Install a theme
91
+ ---
73
92
 
74
- Themes are full desktop environments that style all UI components independently, using [PrimeVue](https://primevue.org/).
75
- Each theme provides a unique look and feel while maintaining consistent functionality across all applications.
93
+ ## Desktop Subsystems (`createDesktop()`)
76
94
 
77
- Discover themes by searching the [owd-themes](https://github.com/topics/owd-themes) tag on GitHub.
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. |
78
104
 
79
- ```bash
80
- desktop add theme-gnome
81
- ```
105
+ ---
82
106
 
83
- ## Sponsors
107
+ ## Official Framework Adapters
84
108
 
85
- Be the first to support this project and help us keep it growing! [Sponsor the project](https://github.com/sponsors/owdproject)
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
+ ---
86
116
 
87
117
  ## License
88
118
 
89
- Open Web Desktop is released under the [MIT License](LICENSE).
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';