@maomaolabs/core 1.0.1 → 1.0.2
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 +123 -110
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,61 +1,65 @@
|
|
|
1
1
|
<div align="center">
|
|
2
|
-
<h1>@maomaolabs/core</h1>
|
|
3
2
|
|
|
4
|
-
<
|
|
5
|
-
<strong>A standalone lightweight React library that brings a complete, performant, and responsive desktop window management experience to the web.</strong>
|
|
6
|
-
</p>
|
|
3
|
+
<img src="./docs/assets/0.gif" alt="@maomaolabs/core — Desktop Window Management for the Web" width="100%" style="border-radius: 12px;" />
|
|
7
4
|
|
|
8
|
-
<
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
<h1>@maomaolabs/core</h1>
|
|
6
|
+
|
|
7
|
+
<p><strong>A standalone, lightweight React library that brings a complete desktop window management experience to the web.</strong><br/>Drag, resize, snap, minimize, maximize — all performant and mobile-ready out of the box.</p>
|
|
11
8
|
|
|
12
9
|
<p>
|
|
13
10
|
<a href="https://www.npmjs.com/package/@maomaolabs/core"><img src="https://img.shields.io/npm/v/@maomaolabs/core?style=for-the-badge&color=000000" alt="NPM Version" /></a>
|
|
14
|
-
<a href="https://github.com/maomaolabs/core/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/@maomaolabs/core?style=for-the-badge&color=
|
|
11
|
+
<a href="https://github.com/maomaolabs/core/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/@maomaolabs/core?style=for-the-badge&color=000" alt="License" /></a>
|
|
15
12
|
<img src="https://img.shields.io/badge/React-18.0.0+-blue?style=for-the-badge&logo=react&color=000000" alt="React 18+" />
|
|
16
13
|
</p>
|
|
17
|
-
</div>
|
|
18
|
-
|
|
19
|
-
<br />
|
|
20
14
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
**Uncompromised performance**
|
|
24
|
-
Zero unnecessary re-renders thanks to context splitting (`useWindows` vs `useWindowActions`).
|
|
25
|
-
<p align="center">
|
|
26
|
-
<img src="./docs/assets/1.png" alt="Performance architecture diagram" width="100%" style="border-radius: 8px;" />
|
|
27
|
-
</p>
|
|
28
|
-
|
|
29
|
-
**Complete window lifecycle**
|
|
30
|
-
Seamlessly open, close, minimize, maximize, resize, and drag windows.
|
|
31
|
-
<p align="center">
|
|
32
|
-
<img src="./docs/assets/4.gif" alt="Window lifecycle demonstration" width="100%" style="border-radius: 8px;" />
|
|
33
|
-
</p>
|
|
15
|
+
</div>
|
|
34
16
|
|
|
35
|
-
|
|
36
|
-
Native-feeling edge snapping (half screen) and corner snapping (quarter screen) functionality.
|
|
37
|
-
<p align="center">
|
|
38
|
-
<img src="./docs/assets/5.gif" alt="Window snapping demonstration" width="100%" style="border-radius: 8px;" />
|
|
39
|
-
</p>
|
|
17
|
+
---
|
|
40
18
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
<
|
|
44
|
-
<
|
|
45
|
-
|
|
19
|
+
## ✨ Features
|
|
20
|
+
|
|
21
|
+
<table>
|
|
22
|
+
<tr>
|
|
23
|
+
<td width="50%">
|
|
24
|
+
<h3>⚡ Zero unnecessary re-renders</h3>
|
|
25
|
+
Context is split into <code>useWindows</code> (state) and <code>useWindowActions</code> (actions). Components that only dispatch actions never re-render on state changes.
|
|
26
|
+
<br/><br/>
|
|
27
|
+
<img src="./docs/assets/1.png" alt="Performance architecture" width="100%" style="border-radius: 8px;" />
|
|
28
|
+
</td>
|
|
29
|
+
<td width="50%">
|
|
30
|
+
<h3>🪟 Complete window lifecycle</h3>
|
|
31
|
+
Open, close, minimize, maximize, drag and resize windows with native-feeling interactions on both desktop and mobile.
|
|
32
|
+
<br/><br/>
|
|
33
|
+
<img src="./docs/assets/4.gif" alt="Window lifecycle" width="100%" style="border-radius: 8px;" />
|
|
34
|
+
</td>
|
|
35
|
+
</tr>
|
|
36
|
+
<tr>
|
|
37
|
+
<td width="50%" valign="top">
|
|
38
|
+
<h3>🧲 Built-in snapping</h3>
|
|
39
|
+
Half-screen (edge) and quarter-screen (corner) snapping with real-time preview overlays, just like a native OS.
|
|
40
|
+
<br/><br/>
|
|
41
|
+
<img src="./docs/assets/5.gif" alt="Window snapping" width="100%" style="border-radius: 8px;" />
|
|
42
|
+
</td>
|
|
43
|
+
<td width="50%" valign="top">
|
|
44
|
+
<h3>🧰 Out-of-the-box Toolbar</h3>
|
|
45
|
+
A fully customizable taskbar that handles individual app launchers, folder groupings, and minimized window management.
|
|
46
|
+
<br/><br/>
|
|
47
|
+
<img src="./docs/assets/7.png" alt="Toolbar" width="100%" style="border-radius: 8px;" />
|
|
48
|
+
</td>
|
|
49
|
+
</tr>
|
|
50
|
+
</table>
|
|
46
51
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
<
|
|
51
|
-
|
|
52
|
+
<div align="center">
|
|
53
|
+
<h3>📱 Responsive by default</h3>
|
|
54
|
+
Interactions automatically adapt between mouse and touch environments. No configuration needed.
|
|
55
|
+
<br/><br/>
|
|
56
|
+
<img src="./docs/assets/6.png" alt="Responsive design" width="320" style="border-radius: 8px;" />
|
|
57
|
+
</div>
|
|
52
58
|
|
|
53
59
|
---
|
|
54
60
|
|
|
55
61
|
## 📦 Installation
|
|
56
62
|
|
|
57
|
-
Install via your preferred package manager (requires `react` and `react-dom` >= 18.0.0):
|
|
58
|
-
|
|
59
63
|
```bash
|
|
60
64
|
npm install @maomaolabs/core
|
|
61
65
|
# or
|
|
@@ -64,24 +68,24 @@ yarn add @maomaolabs/core
|
|
|
64
68
|
pnpm add @maomaolabs/core
|
|
65
69
|
```
|
|
66
70
|
|
|
71
|
+
> Requires `react` and `react-dom` >= 18.0.0 as peer dependencies.
|
|
72
|
+
|
|
67
73
|
---
|
|
68
74
|
|
|
69
75
|
## 🚀 Quick Start
|
|
70
76
|
|
|
71
|
-
Get a window running in under 30 seconds:
|
|
72
|
-
|
|
73
77
|
```tsx
|
|
74
78
|
import { WindowSystemProvider, WindowManager, useWindowActions } from '@maomaolabs/core';
|
|
75
|
-
import '@maomaolabs/core/dist/style.css';
|
|
79
|
+
import '@maomaolabs/core/dist/style.css';
|
|
76
80
|
|
|
77
81
|
const AppLauncher = () => {
|
|
78
82
|
const { openWindow } = useWindowActions();
|
|
79
83
|
|
|
80
84
|
return (
|
|
81
|
-
<button onClick={() => openWindow({
|
|
82
|
-
id: 'hello',
|
|
83
|
-
title: 'Hello',
|
|
84
|
-
component: <div>
|
|
85
|
+
<button onClick={() => openWindow({
|
|
86
|
+
id: 'hello',
|
|
87
|
+
title: 'Hello World',
|
|
88
|
+
component: <div>Hello from a managed window!</div>
|
|
85
89
|
})}>
|
|
86
90
|
Launch App
|
|
87
91
|
</button>
|
|
@@ -98,26 +102,26 @@ export default function App() {
|
|
|
98
102
|
}
|
|
99
103
|
```
|
|
100
104
|
|
|
105
|
+
> ⚠️ Don't forget the CSS import — it's required for drag, resize, and snap overlays to work correctly.
|
|
106
|
+
|
|
101
107
|
---
|
|
102
108
|
|
|
103
|
-
## 📖
|
|
109
|
+
## 📖 Usage Guide
|
|
104
110
|
|
|
105
|
-
###
|
|
111
|
+
### With Toolbar
|
|
106
112
|
|
|
107
|
-
|
|
113
|
+
The `Toolbar` component provides a ready-made taskbar with app launchers, folder support, and minimized window restoration.
|
|
108
114
|
|
|
109
|
-
<
|
|
110
|
-
<img src="./docs/assets/2.png" alt="Toolbar integration overview" width="100%" style="border-radius: 8px;" />
|
|
111
|
-
</p>
|
|
115
|
+
<img src="./docs/assets/2.png" alt="Toolbar integration" width="100%" style="border-radius: 8px;" />
|
|
112
116
|
|
|
113
117
|
```tsx
|
|
114
118
|
import { WindowSystemProvider, WindowManager, Toolbar } from '@maomaolabs/core';
|
|
115
119
|
|
|
116
120
|
const DESKTOP_ITEMS = [
|
|
117
121
|
{
|
|
118
|
-
id: 'browser
|
|
122
|
+
id: 'browser',
|
|
119
123
|
title: 'Browser',
|
|
120
|
-
component: <div />,
|
|
124
|
+
component: <div />,
|
|
121
125
|
initialSize: { width: 800, height: 600 }
|
|
122
126
|
},
|
|
123
127
|
{
|
|
@@ -141,18 +145,18 @@ export default function Desktop() {
|
|
|
141
145
|
|
|
142
146
|
### Accessing Window State
|
|
143
147
|
|
|
144
|
-
|
|
148
|
+
Use `useWindows` when you need to render UI based on open windows (e.g., a custom taskbar or badge counter).
|
|
145
149
|
|
|
146
|
-
<
|
|
147
|
-
|
|
148
|
-
|
|
150
|
+
<img src="./docs/assets/3.png" alt="Window state access" width="100%" style="border-radius: 8px;" />
|
|
151
|
+
|
|
152
|
+
> ⚠️ **Warning:** `useWindows` triggers a re-render on **every** window state change (drag, resize, focus). Only use it where necessary.
|
|
149
153
|
|
|
150
154
|
```tsx
|
|
151
155
|
import { useWindows } from '@maomaolabs/core';
|
|
152
156
|
|
|
153
157
|
const OpenAppCounter = () => {
|
|
154
158
|
const windows = useWindows();
|
|
155
|
-
return <div>Active
|
|
159
|
+
return <div>Active windows: {windows.length}</div>;
|
|
156
160
|
};
|
|
157
161
|
```
|
|
158
162
|
|
|
@@ -160,80 +164,89 @@ const OpenAppCounter = () => {
|
|
|
160
164
|
|
|
161
165
|
## 📚 API Reference
|
|
162
166
|
|
|
163
|
-
###
|
|
167
|
+
### Components
|
|
164
168
|
|
|
165
169
|
| Component | Description | Props |
|
|
166
170
|
| :--- | :--- | :--- |
|
|
167
|
-
| `WindowSystemProvider` |
|
|
168
|
-
| `WindowManager` | Renders active windows and snap overlays.
|
|
169
|
-
| `Toolbar` |
|
|
171
|
+
| `WindowSystemProvider` | Root context provider. Wrap your entire app with this. | `children: ReactNode` |
|
|
172
|
+
| `WindowManager` | Renders all active windows and snap preview overlays. | — |
|
|
173
|
+
| `Toolbar` | Taskbar with app launchers and folder support. | `toolbarItems: ToolbarItem[]`, `showLogo?: boolean` |
|
|
170
174
|
|
|
171
|
-
###
|
|
175
|
+
### Hooks
|
|
172
176
|
|
|
173
|
-
|
|
174
|
-
Returns
|
|
175
|
-
- `openWindow(window: WindowDefinition): void` - Opens a new window or focuses it if already open.
|
|
176
|
-
- `closeWindow(id: string): void` - Destroys a window instance.
|
|
177
|
-
- `focusWindow(id: string): void` - Brings a window to the top of the z-index stack.
|
|
178
|
-
- `updateWindow(id: string, data: Partial<WindowInstance>): void` - Patches an existing window's state.
|
|
177
|
+
#### `useWindowActions()`
|
|
178
|
+
Returns window manipulation methods. **Does not subscribe to window state** — safe to call anywhere without performance concerns.
|
|
179
179
|
|
|
180
|
-
|
|
181
|
-
|
|
180
|
+
| Method | Signature | Description |
|
|
181
|
+
| :--- | :--- | :--- |
|
|
182
|
+
| `openWindow` | `(window: WindowDefinition) => void` | Opens a new window, or focuses it if already open. |
|
|
183
|
+
| `closeWindow` | `(id: string) => void` | Destroys a window instance. |
|
|
184
|
+
| `focusWindow` | `(id: string) => void` | Brings a window to the top of the z-index stack. |
|
|
185
|
+
| `updateWindow` | `(id: string, data: Partial<WindowInstance>) => void` | Patches an existing window's state. |
|
|
182
186
|
|
|
183
|
-
|
|
184
|
-
|
|
187
|
+
#### `useWindows()`
|
|
188
|
+
Returns `WindowInstance[]` — the list of all currently active windows. Re-renders on every state change.
|
|
185
189
|
|
|
186
|
-
|
|
190
|
+
#### `useWindowSnap()`
|
|
191
|
+
Returns `{ snapPreview, setSnapPreview }` for reading and controlling the active snap preview overlay.
|
|
187
192
|
|
|
188
|
-
|
|
193
|
+
---
|
|
189
194
|
|
|
190
|
-
|
|
191
|
-
| :--- | :--- | :--- |
|
|
192
|
-
| `id` | `string` | **Required.** Unique identifier for the window instance. |
|
|
193
|
-
| `title` | `string` | **Required.** Text displayed in the window header. |
|
|
194
|
-
| `component` | `React.ReactNode` | **Required.** The view to be rendered inside the window. |
|
|
195
|
-
| `icon` | `React.ReactNode` | Optional element (e.g., SVG/image) for headers/toolbars. |
|
|
196
|
-
| `initialSize` | `{ width: number; height: number }` | Optional starting dimensions. |
|
|
197
|
-
| `initialPosition` | `{ x: number; y: number }` | Optional starting coordinates. |
|
|
198
|
-
| `layer` | `'base' \| 'normal' \| 'alwaysOnTop' \| 'modal'` | Window render priority layer. |
|
|
199
|
-
| `isMaximized` | `boolean` | If true, spawns the window spanning the screen. |
|
|
200
|
-
| `canMinimize` | `boolean` | Allows the user to hide the window. |
|
|
201
|
-
| `canMaximize` | `boolean` | Allows the user to toggle screen-spanning. |
|
|
202
|
-
| `canClose` | `boolean` | Allows the user to destroy the window. |
|
|
203
|
-
|
|
204
|
-
**`FolderDefinition`** *(Used within Toolbars to group apps)*
|
|
205
|
-
|
|
206
|
-
| Property | Type | Description |
|
|
207
|
-
| :--- | :--- | :--- |
|
|
208
|
-
| `id` | `string` | **Required.** Unique identifier for the folder. |
|
|
209
|
-
| `title` | `string` | **Required.** Folder name. |
|
|
210
|
-
| `apps` | `WindowDefinition[]` | **Required.** Array of windows contained within. |
|
|
211
|
-
| `icon` | `React.ReactNode` | Optional visual descriptor. |
|
|
195
|
+
### Interfaces
|
|
212
196
|
|
|
213
|
-
|
|
197
|
+
#### `WindowDefinition`
|
|
198
|
+
|
|
199
|
+
| Property | Type | Required | Description |
|
|
200
|
+
| :--- | :--- | :---: | :--- |
|
|
201
|
+
| `id` | `string` | ✅ | Unique identifier for the window. |
|
|
202
|
+
| `title` | `string` | ✅ | Text shown in the window title bar. |
|
|
203
|
+
| `component` | `ReactNode` | ✅ | Content rendered inside the window. |
|
|
204
|
+
| `icon` | `ReactNode` | — | Icon shown in the title bar and toolbar. |
|
|
205
|
+
| `initialSize` | `{ width: number; height: number }` | — | Starting dimensions in pixels. |
|
|
206
|
+
| `initialPosition` | `{ x: number; y: number }` | — | Starting coordinates in pixels. |
|
|
207
|
+
| `layer` | `'base' \| 'normal' \| 'alwaysOnTop' \| 'modal'` | — | Z-index render layer. |
|
|
208
|
+
| `isMaximized` | `boolean` | — | Spawns the window in maximized state. |
|
|
209
|
+
| `canMinimize` | `boolean` | — | Shows the minimize control. |
|
|
210
|
+
| `canMaximize` | `boolean` | — | Shows the maximize/restore control. |
|
|
211
|
+
| `canClose` | `boolean` | — | Shows the close control. |
|
|
212
|
+
|
|
213
|
+
#### `FolderDefinition`
|
|
214
|
+
|
|
215
|
+
| Property | Type | Required | Description |
|
|
216
|
+
| :--- | :--- | :---: | :--- |
|
|
217
|
+
| `id` | `string` | ✅ | Unique identifier for the folder. |
|
|
218
|
+
| `title` | `string` | ✅ | Folder display name. |
|
|
219
|
+
| `apps` | `WindowDefinition[]` | ✅ | Windows grouped inside this folder. |
|
|
220
|
+
| `icon` | `ReactNode` | — | Optional visual icon. |
|
|
221
|
+
|
|
222
|
+
> `ToolbarItem = WindowDefinition | FolderDefinition`
|
|
214
223
|
|
|
215
224
|
---
|
|
216
225
|
|
|
217
|
-
## ⚙️
|
|
226
|
+
## ⚙️ Styling
|
|
218
227
|
|
|
219
|
-
|
|
228
|
+
The library requires a single CSS import to function correctly:
|
|
220
229
|
|
|
221
230
|
```tsx
|
|
222
231
|
import '@maomaolabs/core/dist/style.css';
|
|
223
232
|
```
|
|
224
|
-
|
|
233
|
+
|
|
234
|
+
Ensure your bundler (Vite, Webpack, etc.) is configured to process CSS from `node_modules`.
|
|
225
235
|
|
|
226
236
|
---
|
|
227
237
|
|
|
228
|
-
## 🤝
|
|
238
|
+
## 🤝 Contributing
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
npm install # Install dependencies
|
|
242
|
+
npm run dev # Start dev server with hot reload
|
|
243
|
+
npm run test # Run test suite (Vitest)
|
|
244
|
+
```
|
|
229
245
|
|
|
230
|
-
|
|
231
|
-
1. `npm install`
|
|
232
|
-
2. `npm run dev` to watch changes and test locally.
|
|
233
|
-
3. `npm run test` before committing to ensure Vitest suites pass.
|
|
246
|
+
PRs are welcome. Please ensure all tests pass before submitting.
|
|
234
247
|
|
|
235
248
|
---
|
|
236
249
|
|
|
237
250
|
## 📝 License
|
|
238
251
|
|
|
239
|
-
MIT
|
|
252
|
+
MIT © [MaoMao Labs](https://github.com/maomaolabs)
|