react-dockable-desktop 1.2.0 β†’ 2.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/README.md CHANGED
@@ -1,365 +1,157 @@
1
- # React Dockable Desktop
2
-
3
- [![npm version](https://img.shields.io/badge/npm-v1.0.0-blue.svg)](#)
4
- [![license](https://img.shields.io/badge/license-MIT-green.svg)](#)
5
- [![Demo](https://img.shields.io/badge/demo-live-brightgreen.svg)](https://felipecarrillo100.github.io/react-dockable-desktop/)
6
-
7
- A beautiful, premium, state-of-the-art React window manager and dockable layout engine. It features fluid split-docking grids, resizable floating windows, dynamic taskbars, and tabbed panels with **zero-unmount DOM persistence** and **built-in internationalization (i18n) support**.
8
-
9
- [**Live Interactive Demo πŸš€**](https://felipecarrillo100.github.io/react-dockable-desktop/)
10
-
11
- ---
12
-
13
- ## 🌟 Key Features
14
-
15
- * **πŸ“¦ Dockable Splits & Tab Grid**: Drag-and-drop panels to split screens or group them together into tabbed containers.
16
- * **πŸ—ΊοΈ Workspace Edge Docking**: Drag a tab or floating window to the outer edges of the screen (left, right, top, bottom) to instantly dock it as a full-width or full-height column/row.
17
- * **πŸͺ Floating Windows**: Seamlessly pop panels out into floating windows with smooth drag-and-drop movement, custom resizing, maximize, and minimize behaviors.
18
- * **🎨 Custom Global Style Classes**: Inject custom, global styles at the provider level (`modalClass`, `modalBodyClass`, `sidePanelClass`, `sidePanelBodyClass`, `windowClass`, and `windowBodyClass`) to style widgets uniformly.
19
- * **πŸ₯ž Aspect-Ratio Modal Engine**: Modals automatically wrap and shrink-to-fit content snugly, but cap height and scroll gracefully at visual aspect-ratio thresholds (4:3 for small/medium, 16:10 for large layouts).
20
- * **πŸ”¬ Zero-Unmount DOM Persistence**: Heavy widgets (like Leaflet Maps, WebGL viewports, terminal consoles, or stateful forms) maintain their DOM nodes and state. The engine moves existing DOM structures into a hidden document fragment host rather than unmounting them.
21
- * **🌍 i18n & Full RTL Support**: Native translation pipeline matching React Intl formats and **Right-to-Left (RTL) language layouts** (Arabic, Hebrew, Persian, etc.). Detection is completely automatic based on surrounding `dir="rtl"` elements, with explicit provider control options.
22
- * **πŸ› οΈ Custom Header Actions**: Inject custom React components directly into tabbed headers and floating window titlebars dynamically using the `renderHeaderActions` registry property.
23
- * **πŸ” Initial Letter Hover Miniatures**: Miniature preview popovers automatically display the uppercase first character of the panel title inside a theme-responsive grayish layout fallback for panels with disabled live previews.
24
- * **πŸ’Ž Glassmorphic & Modern Styling**: Sleek dark mode aesthetics, interactive micro-animations, and fluid transitions.
25
- * **πŸ”Œ Inter-Panel Pub/Sub Event Bus**: A robust messaging system for lightweight, decoupled communication between active panels.
26
-
27
- ---
28
-
29
- ## πŸš€ Installation
30
-
31
- ```bash
32
- npm install react-dockable-desktop replace-react-contexify
33
- ```
34
-
35
- Ensure the styling for both the layout engine and context menu is imported in your main entry file (e.g., `index.js` or `main.tsx`):
36
-
37
- ```typescript
38
- import 'replace-react-contexify/styles.css';
39
- import 'react-dockable-desktop/styles.css';
40
- ```
41
-
42
- ---
43
-
44
- ## πŸ’» Running the Demo Environments
45
-
46
- The project includes two built-in demo setups to explore and test the window manager layout features:
47
-
48
- ### 1. Leaflet & Monaco Open Source Demo (Default)
49
- A clean, lightweight dashboard demo suitable for public deployment. It showcases Leaflet 2D/3D map integration (with dynamic CARTO Light/Dark tile styles mapping to dashboard theme switches) and Monaco Editor panels.
50
- ```bash
51
- npm run dev
52
- ```
53
-
54
- ### 2. LuciadRIA Earth 3D Demo (Isolated)
55
- An isolated sandbox dashboard demonstrating premium 3D Earth visualizations in the `EPSG:4978` reference reference frame using LuciadRIA. *Note: Requires a valid LuciadRIA developer license locally to run.*
56
- ```bash
57
- npm run dev:ria
58
- ```
59
-
60
- ---
61
-
62
- ## πŸ› οΈ Getting Started
63
-
64
- ### 1. Define and Register Custom Panels
65
-
66
- Register your components with `PanelRegistry`. This exposes them to the window manager layout engine for spawning and custom configuration.
67
-
68
- ```typescript
69
- import React from 'react';
70
- import { PanelRegistry } from 'react-dockable-desktop';
71
-
72
- // Example Panel Component
73
- const MapView: React.FC = () => {
74
- return (
75
- <div style={{ width: '100%', height: '100%', padding: '1rem', color: '#fff' }}>
76
- <h3>Interactive Map</h3>
77
- <p>This DOM is preserved across tabs, floats, and minimizations!</p>
78
- </div>
79
- );
80
- };
81
-
82
- // Register
83
- PanelRegistry.register('mainMap', MapView, {
84
- title: { id: 'app.mapTitle', defaultMessage: 'Satellite Map View' },
85
- canClose: false, // Permanent panel
86
- canMinimize: true,
87
- canDrag: true,
88
- favoritePosition: { x: 100, y: 120, width: 600, height: 400 }
89
- });
90
- ```
91
-
92
- ### 2. Set Up the WindowManager Context Provider
93
-
94
- Wrap your workspace inside `WindowManagerProvider` and render `WindowManager`. If you need modals or side panels, also add `ModalStackRenderer` and/or `SidePanelRenderer` inside the same provider tree.
95
-
96
- ```typescript
97
- import React from 'react';
98
- import {
99
- WindowManagerProvider,
100
- WindowManager,
101
- PanelProvider,
102
- ModalStackRenderer,
103
- SidePanelRenderer,
104
- } from 'react-dockable-desktop';
105
-
106
- function App() {
107
- return (
108
- <WindowManagerProvider>
109
- <PanelProvider>
110
- <div style={{ width: '100vw', height: '100vh', display: 'flex', flexDirection: 'column' }}>
111
- <WindowManager />
112
- </div>
113
- <ModalStackRenderer />
114
- <SidePanelRenderer />
115
- </PanelProvider>
116
- </WindowManagerProvider>
117
- );
118
- }
119
-
120
- export default App;
121
- ```
122
-
123
- ---
124
-
125
- ## 🌍 Internationalization (i18n)
126
-
127
- `react-dockable-desktop` is built with dynamic translation in mind. Titles and context menus can accept either raw `string` values or a structured descriptor object resembling `ContextMenuPredefinedMessage`.
128
-
129
- ### Message Descriptor Format
130
-
131
- ```typescript
132
- interface ContextMenuPredefinedMessage {
133
- id: string;
134
- defaultMessage?: string;
135
- values?: Record<string, string | number>;
136
- }
137
- ```
138
-
139
- ### Integrating custom formatters (e.g., `react-intl`)
140
-
141
- To route messages through your application's translation engine, pass a `formatMessage` callback to the `WindowManagerProvider`.
142
-
143
- ```typescript
144
- import React from 'react';
145
- import { useIntl } from 'react-intl';
146
- import { WindowManagerProvider, Desktop } from 'react-dockable-desktop';
147
-
148
- function App() {
149
- const intl = useIntl();
150
-
151
- // Map descriptor payload directly to react-intl formatter
152
- const handleFormatMessage = (msg: { id: string; defaultMessage?: string; values?: any }) => {
153
- return intl.formatMessage({ id: msg.id, defaultMessage: msg.defaultMessage }, msg.values);
154
- };
155
-
156
- return (
157
- <WindowManagerProvider formatMessage={handleFormatMessage}>
158
- <div style={{ width: '100vw', height: '100vh' }}>
159
- <Desktop />
160
- </div>
161
- </WindowManagerProvider>
162
- );
163
- }
164
- ```
165
-
166
- *If no `formatMessage` function is provided, the engine defaults to a fallback formatting template parser resolving placeholders like `Hello {user}` using values.*
167
-
168
- ### Right-to-Left (RTL) Layout Support
169
-
170
- The library features built-in, theme-resilient Right-to-Left (RTL) rendering. It automatically mirrors tab stacking flows, close icon alignments, custom header buttons, side drawers (which slide in from the opposite edge), titlebars, and taskbar icons.
171
-
172
- #### 1. Automatic Detection (Zero Configuration)
173
- Simply apply the HTML `dir="rtl"` attribute to the container enclosing your layout, or globally on the `<html>`/`<body>` nodes. The workspace will observe it using a `MutationObserver` and mirror dynamically:
174
- ```html
175
- <div dir="rtl">
176
- <Desktop />
177
- </div>
178
- ```
179
-
180
- #### 2. Explicit Programmatic Control
181
- To force a specific direction regardless of the surrounding HTML structure, pass the `dir` prop directly to the provider:
182
- ```typescript
183
- <WindowManagerProvider dir="rtl">
184
- <Desktop />
185
- </WindowManagerProvider>
186
- ```
187
-
188
- ---
189
-
190
- ## πŸŽ›οΈ Programmatic Spawning and Layout API
191
-
192
- Consume actions from the layout context anywhere inside or outside your panel components using the provided hooks.
193
-
194
- ```typescript
195
- import { useWindowManagerActions, useWindowManagerState } from 'react-dockable-desktop';
196
-
197
- const SidebarControls = () => {
198
- const { openPanel, closePanel, saveLayout, loadLayout } = useWindowManagerActions();
199
- const state = useWindowManagerState();
200
-
201
- const handleOpenConsole = () => {
202
- openPanel('debug-console', 'terminal', {
203
- title: { id: 'app.console', defaultMessage: 'System Console Log' },
204
- initialTarget: 'floating' // Options: 'docked' | 'floating' | 'tabbed'
205
- });
206
- };
207
-
208
- return (
209
- <div>
210
- <button onClick={handleOpenConsole}>Spawn Console</button>
211
- <button onClick={() => alert(saveLayout())}>Backup Layout</button>
212
- </div>
213
- );
214
- };
215
- ```
216
-
217
- ### Hook Reference
218
-
219
- | Hook Name | Return Type | Description |
220
- | :--- | :--- | :--- |
221
- | `useWindowManagerState()` | `WindowState` | Access grid layout trees, list of active floating windows, minimized windows list, and general dragging statuses. |
222
- | `useWindowManagerActions()` | `WindowActions` | Spawns, minimizes, restores, docks, floats, maximizes, or closes panels. Also handles split sizing, custom locations, and layout serialization (`saveLayout` / `loadLayout`). |
223
- | `useFormatMessage()` | `(msg: ContextMenuPredefinedMessage) => string` | Returns the translation message formatter hook matching the provider preset configuration. |
224
- | `usePanelContext()` | `{ publish, subscribe }` | Dynamic decoupled event bus helper for active panels. |
225
- | `useStyleClasses()` | `StyleClasses` | Returns the custom CSS class overrides configured on the provider (`windowClass`, `windowBodyClass`, etc.). |
226
-
227
- ---
228
-
229
- ## πŸ›‘οΈ Form Container Context (Close Interception & Dirty States)
230
-
231
- `react-dockable-desktop` provides a context-driven panel container contract to support dirty form tracking, dynamic title overrides, and close action guards. Child elements can access this container context using the `useFormContainer()` hook.
232
-
233
- ### Context Hook Functions
234
-
235
- | Function / Property | Type | Description |
236
- | :--- | :--- | :--- |
237
- | `setDirty(dirty)` | `(dirty: boolean) => void` | Marks the container as dirty. An asterisk `*` will be appended to the panel title (in tabs, minimized taskbars, and floating headers). Attempting to close the panel will trigger a confirmation warning modal. |
238
- | `onCloseRequested(handler)` | `(handler: () => boolean \| Promise<boolean>) => () => void` | Registers an interception handler. When the panel is closed, this function is triggered. If it returns `false`, the closing is cancelled. Returns an unregister cleanup function. |
239
- | `setTitle(title)` | `(title: string \| ContextMenuPredefinedMessage) => void` | Overrides the tab / window title dynamically from the child element. |
240
- | `requestClose(options)` | `(options?: { force?: boolean }) => void` | Request the parent panel container to close programmatically. If `force: true` is passed, it closes immediately, bypassing any dirty checks or guards. |
241
- | `instanceId` | `string` | The unique ID of the panel. |
242
-
243
- ### Implementation Example
244
-
245
- ```typescript
246
- import React, { useState, useEffect } from 'react';
247
- import { useFormContainer } from 'react-dockable-desktop';
248
-
249
- const EditFormPanel: React.FC = () => {
250
- const container = useFormContainer();
251
- const [text, setText] = useState('');
252
-
253
- // 1. Mark dirty when typing
254
- const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
255
- setText(e.target.value);
256
- container.setDirty(true); // Appends '*' to tab header and prompts warning on close
257
- };
258
-
259
- const handleSave = () => {
260
- container.setDirty(false); // Resets dirty state
261
- alert('Saved successfully!');
262
- };
263
-
264
- // 2. Intercept and block closing based on conditions
265
- useEffect(() => {
266
- const unregister = container.onCloseRequested(() => {
267
- if (text.includes('BLOCK')) {
268
- alert('Cannot close while the word "BLOCK" is present!');
269
- return false; // Blocks closure
270
- }
271
- return true; // Allows closure
272
- });
273
- return unregister;
274
- }, [container, text]);
275
-
276
- return (
277
- <div style={{ padding: '1rem', color: '#fff' }}>
278
- <h5>Dynamic Form Editor</h5>
279
- <textarea value={text} onChange={handleChange} />
280
- <button onClick={handleSave}>Save</button>
281
- <button onClick={() => container.requestClose()}>Cancel & Close</button>
282
- </div>
283
- );
284
- };
285
- ```
286
-
287
- ---
288
-
289
- ## πŸ”Œ Inter-Panel Event Communication Bus
290
-
291
- Avoid complex state management boilerplate. Active panels can broadcast lightweight messages across the workspace seamlessly:
292
-
293
- ```typescript
294
- import React, { useEffect } from 'react';
295
- import { usePanelContext } from 'react-dockable-desktop';
296
-
297
- // Subscriber Panel (e.g. Console Log Viewer)
298
- const ConsoleView: React.FC = () => {
299
- const { subscribe } = usePanelContext();
300
-
301
- useEffect(() => {
302
- const unsubscribe = subscribe('CONSOLE_LOG', (payload) => {
303
- console.log('Received log message: ', payload.message);
304
- });
305
- return () => unsubscribe();
306
- }, [subscribe]);
307
-
308
- return <div>Console Viewer</div>;
309
- };
310
-
311
- // Publisher Panel (e.g. Map View)
312
- const MapView: React.FC = () => {
313
- const { publish } = usePanelContext();
314
-
315
- const handleInteract = () => {
316
- publish('CONSOLE_LOG', { message: 'User zoomed map viewport.' });
317
- };
318
-
319
- return <button onClick={handleInteract}>Click Map</button>;
320
- };
321
- ```
322
-
323
- ---
324
-
325
- ## 🎨 Layout Presets & Configuration Options
326
-
327
- You can customized defaults, positioning attributes, and sizes using the registry builder options:
328
-
329
- ```typescript
330
- PanelRegistry.register('unique-panel-key', PanelComponent, {
331
- title: 'Default Title String', // fallback
332
- canMinimize: true,
333
- canDrag: true,
334
- canClose: true,
335
- initialTarget: 'docked', // or 'floating'
336
- favoritePosition: {
337
- x: 400,
338
- y: 200,
339
- width: 500,
340
- height: 350
341
- }
342
- });
343
- ```
344
-
345
- To customize CSS layout attributes, you can override variables in your stylesheet:
346
- ```css
347
- :root {
348
- --accent-color: #00f0ff;
349
- --bg-dark-color: #12131a;
350
- --glass-bg: rgba(18, 19, 26, 0.65);
351
- --border-color: rgba(255, 255, 255, 0.08);
352
- }
353
- ```
354
-
355
- ---
356
-
357
- ## πŸ“ Architecture
358
-
359
- For a deep-dive into the layout tree model, DOM persistence strategy, overlay system, RTL detection, and build pipeline, see [ARCHITECTURE.md](ARCHITECTURE.md).
360
-
361
- ---
362
-
363
- ## πŸ“„ License
364
-
365
- MIT. Free to use, adapt, and build upon.
1
+ # React Dockable Desktop
2
+
3
+ [![npm version](https://img.shields.io/badge/npm-v2.0.0-blue.svg)](https://www.npmjs.com/package/react-dockable-desktop)
4
+ [![license](https://img.shields.io/badge/license-MIT-green.svg)](#license)
5
+ [![Demo](https://img.shields.io/badge/demo-live-brightgreen.svg)](https://felipecarrillo100.github.io/react-dockable-desktop/demo/)
6
+ [![Docs](https://img.shields.io/badge/docs-site-blue.svg)](https://felipecarrillo100.github.io/react-dockable-desktop/)
7
+
8
+ A premium React window manager and dockable layout engine. Fluid split-docking grids, resizable floating windows, dynamic taskbars, and tabbed panels with **zero-unmount DOM persistence** and **built-in i18n/RTL support**.
9
+
10
+ **[Full Documentation](https://felipecarrillo100.github.io/react-dockable-desktop/)** &nbsp;|&nbsp;
11
+ **[Live Demo](https://felipecarrillo100.github.io/react-dockable-desktop/demo/)** &nbsp;|&nbsp;
12
+ **[API Reference](https://felipecarrillo100.github.io/react-dockable-desktop/api/)**
13
+
14
+ ---
15
+
16
+ ## Key Features
17
+
18
+ - **Dockable Splits & Tab Grid** β€” drag panels to split screens or group them into tabbed containers
19
+ - **Workspace Edge Docking** β€” drag to outer edges to dock as full-width/height columns or rows
20
+ - **Floating Windows** β€” pop panels into resizable floating windows with maximize and minimize
21
+ - **Zero-Unmount DOM Persistence** β€” WebGL, maps, terminals, and stateful forms keep their DOM node and state when moved
22
+ - **i18n & RTL** β€” full Right-to-Left layout support with automatic `dir="rtl"` detection
23
+ - **Inter-Panel Pub/Sub** β€” decoupled lightweight messaging between active panels
24
+ - **Imperative API** β€” `WorkspaceClient` lets you open, close, focus, and serialize panels from anywhere outside React
25
+ - **Layout Serialization** β€” save/restore the full workspace layout as a JSON string
26
+
27
+ ---
28
+
29
+ ## Installation
30
+
31
+ ```bash
32
+ npm install react-dockable-desktop replace-react-contexify
33
+ ```
34
+
35
+ Import styles in your entry file:
36
+
37
+ ```ts
38
+ import 'replace-react-contexify/styles.css';
39
+ import 'react-dockable-desktop/styles.css';
40
+ ```
41
+
42
+ ---
43
+
44
+ ## Quick Start
45
+
46
+ ### 1. Create a WorkspaceClient
47
+
48
+ ```ts
49
+ import { WorkspaceClient } from 'react-dockable-desktop';
50
+ import MapPanel from './panels/MapPanel';
51
+ import EditorPanel from './panels/EditorPanel';
52
+
53
+ export const client = new WorkspaceClient({
54
+ panels: {
55
+ map: { component: MapPanel, defaultOptions: { title: 'Map View' } },
56
+ editor: { component: EditorPanel, defaultOptions: { title: 'Editor' } },
57
+ },
58
+ initialState: localStorage.getItem('workspace-layout'),
59
+ });
60
+ ```
61
+
62
+ ### 2. Mount the Provider
63
+
64
+ ```tsx
65
+ import { WindowManagerProvider, WindowManager, PanelProvider, ModalStackRenderer, SidePanelRenderer } from 'react-dockable-desktop';
66
+ import { client } from './workspaceClient';
67
+
68
+ function App() {
69
+ return (
70
+ <WindowManagerProvider client={client}>
71
+ <PanelProvider>
72
+ <div style={{ width: '100vw', height: '100vh' }}>
73
+ <WindowManager />
74
+ </div>
75
+ <ModalStackRenderer />
76
+ <SidePanelRenderer />
77
+ </PanelProvider>
78
+ </WindowManagerProvider>
79
+ );
80
+ }
81
+ ```
82
+
83
+ ### 3. Open Panels Imperatively
84
+
85
+ ```ts
86
+ // From anywhere outside React:
87
+ client.openPanel('map-1', 'map', { title: 'Satellite View' });
88
+ client.focusPanel('map-1');
89
+ client.saveLayout();
90
+
91
+ // Query state:
92
+ client.isOpen('map-1'); // boolean
93
+ client.getOpenPanelIds(); // string[]
94
+ ```
95
+
96
+ ---
97
+
98
+ ## Hooks
99
+
100
+ Use these inside any component within the provider tree:
101
+
102
+ | Hook | Returns | Description |
103
+ | :--- | :--- | :--- |
104
+ | `useWindowManagerActions()` | `WindowActions` | Open, close, focus, dock, float, minimize, maximize, serialize panels |
105
+ | `useWindowManagerState()` | `WindowState` | Reactive access to grid layout, floating windows, minimized panels |
106
+ | `useRegistry()` | `PanelRegistryClass` | The scoped panel registry for the current provider |
107
+ | `usePanelContext()` | `{ publish, subscribe }` | Inter-panel pub/sub event bus |
108
+ | `useFormContainer()` | `FormContainerContract` | Dirty-state tracking, dynamic title overrides, close guards |
109
+ | `useFormatMessage()` | `(msg) => string` | Translation formatter matching the provider's i18n config |
110
+
111
+ ---
112
+
113
+ ## v2.0.0 β€” Breaking Changes
114
+
115
+ | Removed | Replacement |
116
+ | :--- | :--- |
117
+ | `bringToFront(id)` | `focusPanel(id)` β€” works for both floating and docked panels |
118
+ | `setActivePanel(id)` on `WindowActions` | `focusPanel(id)` |
119
+
120
+ **New in v2.0.0:**
121
+ - `focusPanel(id)` β€” unified "show this panel" method
122
+ - `isOpen(id): boolean` β€” synchronous panel state query
123
+ - `getOpenPanelIds(): string[]` β€” list all open panel IDs
124
+ - Pending-call queue: imperative calls before the provider mounts are automatically buffered and replayed
125
+ - DEV-mode warning if `client=` prop is missing on the provider
126
+ - DEV-mode warning if `replace-react-contexify` CSS is not detected
127
+
128
+ See the [Migration Guide](https://felipecarrillo100.github.io/react-dockable-desktop/guide/migration) for the full list of changes.
129
+
130
+ ---
131
+
132
+ ## Demo Environments
133
+
134
+ ```bash
135
+ npm run dev # Leaflet + Monaco open-source demo
136
+ npm run dev:ria # LuciadRIA 3D Earth demo (requires license)
137
+ ```
138
+
139
+ ---
140
+
141
+ ## Documentation
142
+
143
+ Full narrative guides, API reference, and the interactive demo are published at:
144
+
145
+ **https://felipecarrillo100.github.io/react-dockable-desktop/**
146
+
147
+ - [Getting Started](https://felipecarrillo100.github.io/react-dockable-desktop/guide/)
148
+ - [WorkspaceClient Guide](https://felipecarrillo100.github.io/react-dockable-desktop/guide/workspace-client)
149
+ - [Layout System](https://felipecarrillo100.github.io/react-dockable-desktop/guide/layout)
150
+ - [API Reference](https://felipecarrillo100.github.io/react-dockable-desktop/api/)
151
+ - [Migration v1 β†’ v2](https://felipecarrillo100.github.io/react-dockable-desktop/guide/migration)
152
+
153
+ ---
154
+
155
+ ## License
156
+
157
+ MIT. Free to use, adapt, and build upon.