react-dockable-desktop 1.3.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,103 +1,75 @@
1
1
  # React Dockable Desktop
2
2
 
3
- [![npm version](https://img.shields.io/badge/npm-v1.2.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/)
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/)
6
7
 
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
+ 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**.
8
9
 
9
- [**Live Interactive Demo πŸš€**](https://felipecarrillo100.github.io/react-dockable-desktop/)
10
+ **[Full Documentation](https://felipecarrillo100.github.io/react-dockable-desktop/)**  | 
11
+ **[Live Demo](https://felipecarrillo100.github.io/react-dockable-desktop/demo/)**  | 
12
+ **[API Reference](https://felipecarrillo100.github.io/react-dockable-desktop/api/)**
10
13
 
11
14
  ---
12
15
 
13
- ## 🌟 Key Features
16
+ ## Key Features
14
17
 
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.
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
26
 
27
27
  ---
28
28
 
29
- ## πŸš€ Installation
29
+ ## Installation
30
30
 
31
31
  ```bash
32
32
  npm install react-dockable-desktop replace-react-contexify
33
33
  ```
34
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`):
35
+ Import styles in your entry file:
36
36
 
37
- ```typescript
37
+ ```ts
38
38
  import 'replace-react-contexify/styles.css';
39
39
  import 'react-dockable-desktop/styles.css';
40
40
  ```
41
41
 
42
42
  ---
43
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
44
+ ## Quick Start
63
45
 
64
46
  ### 1. Create a WorkspaceClient
65
47
 
66
- ```typescript
48
+ ```ts
67
49
  import { WorkspaceClient } from 'react-dockable-desktop';
68
- import MapView from './panels/MapView';
50
+ import MapPanel from './panels/MapPanel';
69
51
  import EditorPanel from './panels/EditorPanel';
70
52
 
71
53
  export const client = new WorkspaceClient({
72
54
  panels: {
73
- mainMap: { component: MapView, defaultOptions: { title: 'Satellite Map View', canClose: false, canMinimize: true, canDrag: true } },
74
- editor: { component: EditorPanel, defaultOptions: { title: 'Editor', canMinimize: true } },
55
+ map: { component: MapPanel, defaultOptions: { title: 'Map View' } },
56
+ editor: { component: EditorPanel, defaultOptions: { title: 'Editor' } },
75
57
  },
76
- // Restore last layout, or null for an empty canvas
77
58
  initialState: localStorage.getItem('workspace-layout'),
78
59
  });
79
60
  ```
80
61
 
81
- > **No module-level side effects.** Panels are registered inside `WorkspaceClient`, not via a global `PanelRegistry.register` call. The client can be exported and used imperatively from anywhere: `client.openPanel(...)`, `client.saveLayout()`.
82
-
83
- ### 2. Set Up the Provider
62
+ ### 2. Mount the Provider
84
63
 
85
- ```typescript
86
- import React from 'react';
87
- import {
88
- WindowManagerProvider,
89
- WindowManager,
90
- PanelProvider,
91
- ModalStackRenderer,
92
- SidePanelRenderer,
93
- } from 'react-dockable-desktop';
64
+ ```tsx
65
+ import { WindowManagerProvider, WindowManager, PanelProvider, ModalStackRenderer, SidePanelRenderer } from 'react-dockable-desktop';
94
66
  import { client } from './workspaceClient';
95
67
 
96
68
  function App() {
97
69
  return (
98
70
  <WindowManagerProvider client={client}>
99
71
  <PanelProvider>
100
- <div style={{ width: '100vw', height: '100vh', display: 'flex', flexDirection: 'column' }}>
72
+ <div style={{ width: '100vw', height: '100vh' }}>
101
73
  <WindowManager />
102
74
  </div>
103
75
  <ModalStackRenderer />
@@ -106,280 +78,80 @@ function App() {
106
78
  </WindowManagerProvider>
107
79
  );
108
80
  }
109
-
110
- export default App;
111
81
  ```
112
82
 
113
- > **Backward compatibility:** The `client` prop is optional. The `PanelRegistry` global singleton and the old provider props (`formatMessage`, `predefinedMessages`, `dir`) still work as before.
114
-
115
- ---
116
-
117
- ## 🌍 Internationalization (i18n)
118
-
119
- `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`.
83
+ ### 3. Open Panels Imperatively
120
84
 
121
- ### Message Descriptor Format
85
+ ```ts
86
+ // From anywhere outside React:
87
+ client.openPanel('map-1', 'map', { title: 'Satellite View' });
88
+ client.focusPanel('map-1');
89
+ client.saveLayout();
122
90
 
123
- ```typescript
124
- interface ContextMenuPredefinedMessage {
125
- id: string;
126
- defaultMessage?: string;
127
- values?: Record<string, string | number>;
128
- }
129
- ```
130
-
131
- ### Integrating custom formatters (e.g., `react-intl`)
132
-
133
- To route messages through your application's translation engine, pass a `formatMessage` callback to `WorkspaceClient`:
134
-
135
- ```typescript
136
- const client = new WorkspaceClient({
137
- panels: { ... },
138
- formatMessage: (msg) => intl.formatMessage({ id: msg.id, defaultMessage: msg.defaultMessage }, msg.values),
139
- });
140
-
141
- function App() {
142
- return (
143
- <WindowManagerProvider client={client}>
144
- ...
145
- </WindowManagerProvider>
146
- );
147
- }
148
- ```
149
-
150
- > **Backward compatibility:** Passing `formatMessage` directly as a prop to `WindowManagerProvider` is still supported for existing code.
151
-
152
- *If no `formatMessage` function is provided, the engine defaults to a fallback formatting template parser resolving placeholders like `Hello {user}` using values.*
153
-
154
- ### Right-to-Left (RTL) Layout Support
155
-
156
- 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.
157
-
158
- #### 1. Automatic Detection (Zero Configuration)
159
- 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:
160
- ```html
161
- <div dir="rtl">
162
- <Desktop />
163
- </div>
164
- ```
165
-
166
- #### 2. Explicit Programmatic Control
167
- To force a specific direction regardless of the surrounding HTML structure, pass the `dir` option to `WorkspaceClient`:
168
- ```typescript
169
- const client = new WorkspaceClient({ panels: { ... }, dir: 'rtl' });
170
- <WindowManagerProvider client={client}>
171
- <Desktop />
172
- </WindowManagerProvider>
91
+ // Query state:
92
+ client.isOpen('map-1'); // boolean
93
+ client.getOpenPanelIds(); // string[]
173
94
  ```
174
95
 
175
96
  ---
176
97
 
177
- ## πŸŽ›οΈ Programmatic Spawning and Layout API
178
-
179
- Consume actions from the layout context anywhere inside or outside your panel components using the provided hooks.
180
-
181
- ```typescript
182
- import { useWindowManagerActions, useWindowManagerState } from 'react-dockable-desktop';
98
+ ## Hooks
183
99
 
184
- const SidebarControls = () => {
185
- const { openPanel, closePanel, saveLayout, loadLayout } = useWindowManagerActions();
186
- const state = useWindowManagerState();
100
+ Use these inside any component within the provider tree:
187
101
 
188
- const handleOpenConsole = () => {
189
- openPanel('debug-console', 'terminal', {
190
- title: { id: 'app.console', defaultMessage: 'System Console Log' },
191
- initialTarget: 'floating' // Options: 'docked' | 'floating' | 'tabbed'
192
- });
193
- };
194
-
195
- return (
196
- <div>
197
- <button onClick={handleOpenConsole}>Spawn Console</button>
198
- <button onClick={() => alert(saveLayout())}>Backup Layout</button>
199
- </div>
200
- );
201
- };
202
- ```
203
-
204
- ### Hook Reference
205
-
206
- | Hook Name | Return Type | Description |
207
- | :--- | :--- | :--- |
208
- | `useWindowManagerState()` | `WindowState` | Access grid layout trees, list of active floating windows, minimized windows list, and general dragging statuses. |
209
- | `useWindowManagerActions()` | `WindowActions` | Spawns, minimizes, restores, docks, floats, maximizes, or closes panels. Also handles split sizing, custom locations, and layout serialization (`saveLayout` / `loadLayout`). |
210
- | `useFormatMessage()` | `(msg: ContextMenuPredefinedMessage) => string` | Returns the translation message formatter hook matching the provider preset configuration. |
211
- | `usePanelContext()` | `{ publish, subscribe }` | Dynamic decoupled event bus helper for active panels. |
212
- | `useStyleClasses()` | `StyleClasses` | Returns the custom CSS class overrides configured on the provider (`windowClass`, `windowBodyClass`, etc.). |
213
- | `useRegistry()` | `PanelRegistryClass` | Returns the scoped panel registry for the current provider. |
214
-
215
- ---
216
-
217
- ## New Exports (v1.2.0)
218
-
219
- The following additional exports are available in v1.2.0:
220
-
221
- - `WorkspaceClient` β€” class for creating a scoped workspace configuration outside React.
222
- - `WorkspaceClientConfig` β€” TypeScript interface for the `WorkspaceClient` constructor options.
223
- - `PanelDefinition` β€” TypeScript interface describing a single panel entry in the `panels` map.
224
- - `PanelRegistryClass` β€” the class backing both the scoped (per-client) and global registries; useful for typing or extending the registry.
225
-
226
- ---
227
-
228
- ## πŸ›‘οΈ Form Container Context (Close Interception & Dirty States)
229
-
230
- `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.
231
-
232
- ### Context Hook Functions
233
-
234
- | Function / Property | Type | Description |
102
+ | Hook | Returns | Description |
235
103
  | :--- | :--- | :--- |
236
- | `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. |
237
- | `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. |
238
- | `setTitle(title)` | `(title: string \| ContextMenuPredefinedMessage) => void` | Overrides the tab / window title dynamically from the child element. |
239
- | `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. |
240
- | `instanceId` | `string` | The unique ID of the panel. |
241
-
242
- ### Implementation Example
243
-
244
- ```typescript
245
- import React, { useState, useEffect } from 'react';
246
- import { useFormContainer } from 'react-dockable-desktop';
247
-
248
- const EditFormPanel: React.FC = () => {
249
- const container = useFormContainer();
250
- const [text, setText] = useState('');
251
-
252
- // 1. Mark dirty when typing
253
- const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
254
- setText(e.target.value);
255
- container.setDirty(true); // Appends '*' to tab header and prompts warning on close
256
- };
257
-
258
- const handleSave = () => {
259
- container.setDirty(false); // Resets dirty state
260
- alert('Saved successfully!');
261
- };
262
-
263
- // 2. Intercept and block closing based on conditions
264
- useEffect(() => {
265
- const unregister = container.onCloseRequested(() => {
266
- if (text.includes('BLOCK')) {
267
- alert('Cannot close while the word "BLOCK" is present!');
268
- return false; // Blocks closure
269
- }
270
- return true; // Allows closure
271
- });
272
- return unregister;
273
- }, [container, text]);
274
-
275
- return (
276
- <div style={{ padding: '1rem', color: '#fff' }}>
277
- <h5>Dynamic Form Editor</h5>
278
- <textarea value={text} onChange={handleChange} />
279
- <button onClick={handleSave}>Save</button>
280
- <button onClick={() => container.requestClose()}>Cancel & Close</button>
281
- </div>
282
- );
283
- };
284
- ```
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 |
285
110
 
286
111
  ---
287
112
 
288
- ## πŸ”Œ Inter-Panel Event Communication Bus
113
+ ## v2.0.0 β€” Breaking Changes
289
114
 
290
- Avoid complex state management boilerplate. Active panels can broadcast lightweight messages across the workspace seamlessly:
115
+ | Removed | Replacement |
116
+ | :--- | :--- |
117
+ | `bringToFront(id)` | `focusPanel(id)` β€” works for both floating and docked panels |
118
+ | `setActivePanel(id)` on `WindowActions` | `focusPanel(id)` |
291
119
 
292
- ```typescript
293
- import React, { useEffect } from 'react';
294
- import { usePanelContext } from 'react-dockable-desktop';
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
295
127
 
296
- // Subscriber Panel (e.g. Console Log Viewer)
297
- const ConsoleView: React.FC = () => {
298
- const { subscribe } = usePanelContext();
299
-
300
- useEffect(() => {
301
- const unsubscribe = subscribe('CONSOLE_LOG', (payload) => {
302
- console.log('Received log message: ', payload.message);
303
- });
304
- return () => unsubscribe();
305
- }, [subscribe]);
306
-
307
- return <div>Console Viewer</div>;
308
- };
309
-
310
- // Publisher Panel (e.g. Map View)
311
- const MapView: React.FC = () => {
312
- const { publish } = usePanelContext();
313
-
314
- const handleInteract = () => {
315
- publish('CONSOLE_LOG', { message: 'User zoomed map viewport.' });
316
- };
317
-
318
- return <button onClick={handleInteract}>Click Map</button>;
319
- };
320
- ```
128
+ See the [Migration Guide](https://felipecarrillo100.github.io/react-dockable-desktop/guide/migration) for the full list of changes.
321
129
 
322
130
  ---
323
131
 
324
- ## 🎨 Layout Presets & Configuration Options
325
-
326
- You can customize defaults, positioning attributes, and sizes using the `WorkspaceClient` panels configuration:
327
-
328
- ```typescript
329
- const client = new WorkspaceClient({
330
- panels: {
331
- 'unique-panel-key': {
332
- component: PanelComponent,
333
- defaultOptions: {
334
- title: 'Default Title String', // fallback
335
- canMinimize: true,
336
- canDrag: true,
337
- canClose: true,
338
- initialTarget: 'docked', // or 'floating'
339
- favoritePosition: {
340
- x: 400,
341
- y: 200,
342
- width: 500,
343
- height: 350,
344
- },
345
- },
346
- },
347
- },
348
- });
349
- ```
350
-
351
- > **Legacy / backward-compatible approach:** You can still use the global `PanelRegistry.register('unique-panel-key', PanelComponent, options)` at module scope. This singleton is fully supported for existing codebases.
132
+ ## Demo Environments
352
133
 
353
- To customize CSS layout attributes, you can override variables in your stylesheet:
354
- ```css
355
- :root {
356
- --accent-color: #00f0ff;
357
- --bg-dark-color: #12131a;
358
- --glass-bg: rgba(18, 19, 26, 0.65);
359
- --border-color: rgba(255, 255, 255, 0.08);
360
- }
134
+ ```bash
135
+ npm run dev # Leaflet + Monaco open-source demo
136
+ npm run dev:ria # LuciadRIA 3D Earth demo (requires license)
361
137
  ```
362
138
 
363
139
  ---
364
140
 
365
- ## 🎨 Theming
141
+ ## Documentation
366
142
 
367
- The library's theming attribute is `data-color-scheme`. When switching themes in your app, set this attribute on the workspace root (or a wrapping element):
368
-
369
- ```typescript
370
- document.documentElement.setAttribute('data-color-scheme', 'dark'); // or 'light'
371
- ```
372
-
373
- If you are also using Bootstrap, you may set `data-bs-theme` alongside it for Bootstrap component compatibility.
374
-
375
- ---
143
+ Full narrative guides, API reference, and the interactive demo are published at:
376
144
 
377
- ## πŸ“ Architecture
145
+ **https://felipecarrillo100.github.io/react-dockable-desktop/**
378
146
 
379
- For a deep-dive into the layout tree model, DOM persistence strategy, overlay system, `WorkspaceClient` and scoped registries, empty canvas default behavior, RTL detection, and build pipeline, see [ARCHITECTURE.md](ARCHITECTURE.md).
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)
380
152
 
381
153
  ---
382
154
 
383
- ## πŸ“„ License
155
+ ## License
384
156
 
385
157
  MIT. Free to use, adapt, and build upon.