react-dockable-desktop 3.0.0 → 3.1.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 +269 -69
- package/dist/index.cjs +24 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +240 -25
- package/dist/index.d.ts +240 -25
- package/dist/index.js +24 -3
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1092 -52
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,28 +1,33 @@
|
|
|
1
1
|
# React Dockable Desktop
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/react-dockable-desktop)
|
|
4
|
+
[](https://www.typescriptlang.org/)
|
|
5
|
+
[](#touch--mobile)
|
|
4
6
|
[](#license)
|
|
5
7
|
[](https://felipecarrillo100.github.io/react-dockable-desktop/demo/)
|
|
6
8
|
[](https://felipecarrillo100.github.io/react-dockable-desktop/)
|
|
7
9
|
|
|
8
|
-
A premium
|
|
10
|
+
A premium dockable layout engine for React. Build desktop-class applications with fluid split-docking grids, tabbed panels, resizable floating windows, and **zero-unmount DOM preservation** — so WebGL contexts, live maps, and stateful editors never lose their state when moved or re-tabbed.
|
|
9
11
|
|
|
10
|
-
**[Full Documentation](https://felipecarrillo100.github.io/react-dockable-desktop/)** |
|
|
11
12
|
**[Live Demo](https://felipecarrillo100.github.io/react-dockable-desktop/demo/)** |
|
|
13
|
+
**[Full Documentation](https://felipecarrillo100.github.io/react-dockable-desktop/)** |
|
|
12
14
|
**[API Reference](https://felipecarrillo100.github.io/react-dockable-desktop/api/)**
|
|
13
15
|
|
|
14
16
|
---
|
|
15
17
|
|
|
16
|
-
##
|
|
18
|
+
## Features
|
|
17
19
|
|
|
18
|
-
- **
|
|
19
|
-
- **Workspace Edge Docking** — drag to outer edges to dock as full-width
|
|
20
|
-
- **Floating Windows** — pop panels into resizable floating windows
|
|
21
|
-
- **
|
|
22
|
-
- **
|
|
23
|
-
- **
|
|
24
|
-
- **
|
|
25
|
-
- **
|
|
20
|
+
- **Split-Docking Grid** — drag panels to split any zone into rows/columns or group into tabbed containers
|
|
21
|
+
- **Workspace Edge Docking** — drag to the outer edges to dock a panel as a full-width or full-height strip
|
|
22
|
+
- **Floating Windows** — pop panels into freely resizable floating windows; 8-direction resize handles (N/NE/E/SE/S/SW/W/NW), maximize, minimize
|
|
23
|
+
- **Touch & Mobile Ready** — full iPad and Android support: long-press to drag tabs, touch resize, 44px coarse-pointer targets throughout
|
|
24
|
+
- **Zero-Unmount DOM Persistence** — panel DOM nodes are moved, never destroyed; WebGL, maps, terminals, and forms retain full state
|
|
25
|
+
- **i18n & RTL** — full Right-to-Left layout support; `dir="rtl"` flips every control, tab order, and drop zone automatically
|
|
26
|
+
- **Inter-Panel Pub/Sub** — lightweight typed event bus for decoupled panel-to-panel communication
|
|
27
|
+
- **Imperative API** — `WorkspaceClient` opens, closes, focuses, and serializes panels from anywhere — inside or outside React
|
|
28
|
+
- **Layout Serialization** — save and restore the full workspace as a JSON string; survives page reloads
|
|
29
|
+
- **7 Built-in Skins** — VSCode, macOS, Chrome, Slate, Nord, Obsidian, Tokyo — all fully themeable via CSS variables
|
|
30
|
+
- **TypeScript-first** — complete type definitions included; no separate `@types/` package needed
|
|
26
31
|
|
|
27
32
|
---
|
|
28
33
|
|
|
@@ -32,28 +37,33 @@ A premium React window manager and dockable layout engine. Fluid split-docking g
|
|
|
32
37
|
npm install react-dockable-desktop replace-react-contexify
|
|
33
38
|
```
|
|
34
39
|
|
|
35
|
-
Import styles in your entry file:
|
|
40
|
+
Import styles in your app entry file. **Order matters** — the contexify sheet must come first:
|
|
36
41
|
|
|
37
42
|
```ts
|
|
38
43
|
import 'replace-react-contexify/styles.css';
|
|
39
44
|
import 'react-dockable-desktop/styles.css';
|
|
40
45
|
```
|
|
41
46
|
|
|
47
|
+
**Requirements:** React ≥ 16.8 · Node ≥ 18
|
|
48
|
+
|
|
42
49
|
---
|
|
43
50
|
|
|
44
51
|
## Quick Start
|
|
45
52
|
|
|
46
53
|
### 1. Create a WorkspaceClient
|
|
47
54
|
|
|
55
|
+
Define your panel catalog and create a `WorkspaceClient` **outside React**, at module scope. It acts as the bridge between your imperative code and the React tree.
|
|
56
|
+
|
|
48
57
|
```ts
|
|
58
|
+
// workspace.ts
|
|
49
59
|
import { WorkspaceClient } from 'react-dockable-desktop';
|
|
50
|
-
import MapPanel
|
|
60
|
+
import MapPanel from './panels/MapPanel';
|
|
51
61
|
import EditorPanel from './panels/EditorPanel';
|
|
52
62
|
|
|
53
|
-
export const
|
|
63
|
+
export const workspace = new WorkspaceClient({
|
|
54
64
|
panels: {
|
|
55
65
|
map: { component: MapPanel, defaultOptions: { title: 'Map View' } },
|
|
56
|
-
editor: { component: EditorPanel, defaultOptions: { title: 'Editor'
|
|
66
|
+
editor: { component: EditorPanel, defaultOptions: { title: 'Editor' } },
|
|
57
67
|
},
|
|
58
68
|
initialState: localStorage.getItem('workspace-layout'),
|
|
59
69
|
});
|
|
@@ -61,97 +71,287 @@ export const client = new WorkspaceClient({
|
|
|
61
71
|
|
|
62
72
|
### 2. Mount the Provider
|
|
63
73
|
|
|
74
|
+
`DockableDesktopProvider` is the single composite provider — it wraps everything the library needs:
|
|
75
|
+
|
|
64
76
|
```tsx
|
|
65
|
-
|
|
66
|
-
import {
|
|
77
|
+
// App.tsx
|
|
78
|
+
import { DockableDesktopProvider, WindowManager, ModalStackRenderer } from 'react-dockable-desktop';
|
|
79
|
+
import { workspace } from './workspace';
|
|
67
80
|
|
|
68
|
-
function App() {
|
|
81
|
+
export default function App() {
|
|
69
82
|
return (
|
|
70
|
-
<
|
|
71
|
-
<
|
|
72
|
-
<
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
<SidePanelRenderer />
|
|
77
|
-
</PanelProvider>
|
|
78
|
-
</WindowManagerProvider>
|
|
83
|
+
<DockableDesktopProvider client={workspace}>
|
|
84
|
+
<div style={{ width: '100vw', height: '100vh' }}>
|
|
85
|
+
<WindowManager />
|
|
86
|
+
</div>
|
|
87
|
+
<ModalStackRenderer />
|
|
88
|
+
</DockableDesktopProvider>
|
|
79
89
|
);
|
|
80
90
|
}
|
|
81
91
|
```
|
|
82
92
|
|
|
83
|
-
|
|
93
|
+
> **Important:** the `WindowManager` container must have an explicit height. A `height: 100%` that resolves to zero will produce a development warning.
|
|
94
|
+
|
|
95
|
+
### 3. Open Panels
|
|
84
96
|
|
|
85
97
|
```ts
|
|
86
|
-
// From anywhere outside React:
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
//
|
|
92
|
-
|
|
93
|
-
|
|
98
|
+
// From anywhere — inside or outside React:
|
|
99
|
+
workspace.openPanel('map-1', 'map');
|
|
100
|
+
workspace.openPanel('ed-1', 'editor', { title: 'config.json', initialTarget: 'floating' });
|
|
101
|
+
workspace.focusPanel('map-1');
|
|
102
|
+
|
|
103
|
+
// Layout persistence:
|
|
104
|
+
localStorage.setItem('workspace-layout', workspace.saveLayout());
|
|
105
|
+
|
|
106
|
+
// Query state without a hook:
|
|
107
|
+
workspace.isOpen('map-1'); // boolean
|
|
108
|
+
workspace.getOpenPanelIds(); // string[]
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Panels can now be dragged, split, tabbed, floated, and minimized out of the box.
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Writing a Panel Component
|
|
116
|
+
|
|
117
|
+
A panel is any React component. Use built-in hooks to integrate with the layout:
|
|
118
|
+
|
|
119
|
+
```tsx
|
|
120
|
+
import { useFormContainer, usePanelId } from 'react-dockable-desktop';
|
|
121
|
+
|
|
122
|
+
export default function EditorPanel() {
|
|
123
|
+
const panelId = usePanelId(); // this panel's instance ID — no prop needed
|
|
124
|
+
const { setDirty, setTitle } = useFormContainer();
|
|
125
|
+
|
|
126
|
+
const handleChange = (value: string) => {
|
|
127
|
+
setDirty(true); // blocks close until user confirms discard
|
|
128
|
+
setTitle('config.json *'); // updates the tab title live
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
return <textarea onChange={e => handleChange(e.target.value)} />;
|
|
132
|
+
}
|
|
94
133
|
```
|
|
95
134
|
|
|
96
135
|
---
|
|
97
136
|
|
|
98
137
|
## Hooks
|
|
99
138
|
|
|
100
|
-
|
|
139
|
+
Call these inside any component within the `DockableDesktopProvider` tree:
|
|
101
140
|
|
|
102
|
-
| Hook | Returns |
|
|
141
|
+
| Hook | Returns | Use For |
|
|
103
142
|
| :--- | :--- | :--- |
|
|
104
|
-
| `useWindowManagerActions()` | `WindowActions` | Open, close,
|
|
105
|
-
| `useWindowManagerState()` | `WindowState`
|
|
143
|
+
| `useWindowManagerActions()` | `WindowActions` | Open, close, float, dock, minimize, maximize, serialize panels |
|
|
144
|
+
| `useWindowManagerState(selector?)` | `WindowState` or selected slice | Read layout, floating windows, active panel ID |
|
|
145
|
+
| `usePanelActions()` | `PanelActions` | Open modal overlays and left/right side drawers |
|
|
146
|
+
| `usePanelContext()` | `{ publish, subscribe }` | Inter-panel typed event bus |
|
|
147
|
+
| `useFormContainer()` | `FormContainerContract` | Dirty state, close guards, dynamic panel title/icon |
|
|
148
|
+
| `usePanelId()` | `string` | The panel's own instance ID — no prop drilling needed |
|
|
106
149
|
| `useRegistry()` | `PanelRegistryClass` | The scoped panel registry for the current provider |
|
|
107
|
-
| `
|
|
108
|
-
|
|
109
|
-
|
|
150
|
+
| `useFormatMessage()` | `MessageFormatter` | i18n formatter matching the current provider's locale |
|
|
151
|
+
|
|
152
|
+
**State selectors** prevent unnecessary re-renders:
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
// Only re-renders when activePanelId changes — not on every layout mutation:
|
|
156
|
+
const activeId = useWindowManagerState(s => s.activePanelId);
|
|
157
|
+
const panelCount = useWindowManagerState(s => Object.keys(s.panels).length);
|
|
158
|
+
```
|
|
110
159
|
|
|
111
160
|
---
|
|
112
161
|
|
|
113
|
-
##
|
|
162
|
+
## WorkspaceClient Reference
|
|
114
163
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
164
|
+
```ts
|
|
165
|
+
const workspace = new WorkspaceClient({ panels, initialState?, formatMessage?, dir? });
|
|
166
|
+
|
|
167
|
+
// Panel lifecycle
|
|
168
|
+
workspace.openPanel(id, component, options?) // options: title, initialTarget, stickyRight, stickyBottom
|
|
169
|
+
workspace.closePanel(id)
|
|
170
|
+
workspace.focusPanel(id) // raises floating / selects tab for docked
|
|
171
|
+
workspace.floatPanel(id, rect?) // detach to a floating window
|
|
172
|
+
workspace.dockPanel(id) // return floating to the grid
|
|
173
|
+
workspace.minimizePanel(id)
|
|
174
|
+
workspace.restorePanel(id)
|
|
175
|
+
workspace.maximizePanel(id)
|
|
176
|
+
|
|
177
|
+
// Synchronous state queries (no hook needed)
|
|
178
|
+
workspace.isOpen(id) // → boolean
|
|
179
|
+
workspace.getOpenPanelIds() // → string[]
|
|
180
|
+
|
|
181
|
+
// Layout persistence
|
|
182
|
+
workspace.saveLayout() // → JSON string
|
|
183
|
+
workspace.loadLayout(json) // → boolean (true = success)
|
|
184
|
+
|
|
185
|
+
// Event bus
|
|
186
|
+
workspace.publish(event, data)
|
|
187
|
+
workspace.subscribe(event, callback) // → unsubscribe()
|
|
188
|
+
workspace.onPanelOpen(cb)
|
|
189
|
+
workspace.onPanelClose(cb)
|
|
190
|
+
workspace.onPanelMinimize(cb)
|
|
191
|
+
workspace.onPanelRestore(cb)
|
|
192
|
+
|
|
193
|
+
// Direction
|
|
194
|
+
workspace.setDirection('ltr' | 'rtl')
|
|
195
|
+
```
|
|
119
196
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
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
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## Layout Persistence
|
|
127
200
|
|
|
128
|
-
|
|
201
|
+
```ts
|
|
202
|
+
// Save on unload (or on any meaningful user action):
|
|
203
|
+
window.addEventListener('beforeunload', () => {
|
|
204
|
+
localStorage.setItem('workspace-layout', workspace.saveLayout());
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
// Restore by passing the saved string to the constructor:
|
|
208
|
+
new WorkspaceClient({
|
|
209
|
+
panels: { ... },
|
|
210
|
+
initialState: localStorage.getItem('workspace-layout'),
|
|
211
|
+
});
|
|
212
|
+
```
|
|
129
213
|
|
|
130
214
|
---
|
|
131
215
|
|
|
132
|
-
##
|
|
216
|
+
## Side Panels & Modals
|
|
133
217
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
218
|
+
Add `SidePanelRenderer` and `ModalStackRenderer` to your app root. Placement matters — `SidePanelRenderer` must be **inside** the workspace container so drawers position correctly; `ModalStackRenderer` goes **outside** as a full-screen overlay:
|
|
219
|
+
|
|
220
|
+
```tsx
|
|
221
|
+
// App.tsx
|
|
222
|
+
import { SidePanelRenderer, ModalStackRenderer } from 'react-dockable-desktop';
|
|
223
|
+
|
|
224
|
+
function App() {
|
|
225
|
+
return (
|
|
226
|
+
<DockableDesktopProvider client={workspace}>
|
|
227
|
+
<div style={{ width: '100vw', height: '100vh', overflow: 'hidden', position: 'relative' }}>
|
|
228
|
+
<WindowManager />
|
|
229
|
+
<SidePanelRenderer /> {/* inside — drawers position relative to this container */}
|
|
230
|
+
</div>
|
|
231
|
+
<ModalStackRenderer /> {/* outside — full-screen overlay */}
|
|
232
|
+
</DockableDesktopProvider>
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// From any panel component:
|
|
237
|
+
const { openModal, openRightPanel } = usePanelActions();
|
|
238
|
+
|
|
239
|
+
openModal(MyForm, { itemId: 42 }, { title: 'Edit Item', size: 'medium' });
|
|
240
|
+
openRightPanel(PropertiesPanel, { nodeId }, { title: 'Properties', width: 320 });
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
## Touch & Mobile
|
|
246
|
+
|
|
247
|
+
Touch support is built in for v3.1.0+. No extra setup required:
|
|
248
|
+
|
|
249
|
+
- **Tab drag** — long-press (300ms) on any tab to start dragging; haptic feedback on supported devices
|
|
250
|
+
- **Floating window drag** — long-press the titlebar, then drag
|
|
251
|
+
- **Resize** — drag any of the 8 resize handles; minimum 44px touch targets throughout
|
|
252
|
+
- **Split resizer** — drag the 1px divider line; the hit area extends into the safe direction to avoid accidental tab activation
|
|
253
|
+
- **Tab bar scroll** — swipe horizontally in the tab strip to scroll when there are many tabs
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## i18n & RTL
|
|
258
|
+
|
|
259
|
+
```tsx
|
|
260
|
+
<DockableDesktopProvider
|
|
261
|
+
dir="rtl"
|
|
262
|
+
formatMessage={(msg) => intl.formatMessage({ id: msg.id, defaultMessage: msg.defaultMessage })}
|
|
263
|
+
predefinedMessages={customMessages}
|
|
264
|
+
>
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
`dir` can be `'ltr'` (default) or `'rtl'`. All layout, split directions, tab ordering, drop zones, and context menus flip automatically. You can also switch at runtime:
|
|
268
|
+
|
|
269
|
+
```ts
|
|
270
|
+
workspace.setDirection('rtl');
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
## Skins
|
|
276
|
+
|
|
277
|
+
```tsx
|
|
278
|
+
<WindowManager skin="vscode" /> // default
|
|
279
|
+
<WindowManager skin="macos" />
|
|
280
|
+
<WindowManager skin="nord" />
|
|
281
|
+
<WindowManager skin="tokyo" />
|
|
137
282
|
```
|
|
138
283
|
|
|
284
|
+
**Built-in skins:** `vscode` · `macos` · `chrome` · `slate` · `nord` · `obsidian` · `tokyo`
|
|
285
|
+
|
|
286
|
+
Create your own skin by overriding CSS custom properties under a `[data-workspace-skin="myskin"]` selector. See the [Theming Guide](https://felipecarrillo100.github.io/react-dockable-desktop/guide/theming) for the full variable reference.
|
|
287
|
+
|
|
288
|
+
---
|
|
289
|
+
|
|
290
|
+
## What's New
|
|
291
|
+
|
|
292
|
+
### v3.1.0
|
|
293
|
+
- **Full touch & iPad/Android support** — Pointer Events API migration; long-press (300ms) activates tab drag; all drag/resize surfaces work with finger and Apple Pencil
|
|
294
|
+
- **8-direction resize handles** — floating windows now have N, NE, E, SE, S, SW, W, NW resize handles
|
|
295
|
+
- **Smart resizer hit areas** — horizontal resizer extends only upward into the safe content zone, preventing accidental activation when clicking tabs directly below
|
|
296
|
+
- **Cursor bug fix** — cursor orientation during active resize drag now matches the visual handle correctly
|
|
297
|
+
|
|
298
|
+
### v3.0.0
|
|
299
|
+
- **`DockableDesktopProvider`** — single composite provider replaces the manual `WindowManagerProvider + PanelProvider` nesting
|
|
300
|
+
- **RTL support** — `dir` prop on provider; `setDirection()` on client; full mirroring of all controls
|
|
301
|
+
- **State selectors** — `useWindowManagerState(s => s.activePanelId)` for surgical re-renders
|
|
302
|
+
- **Dynamic ModalStack** — clean overlay system with dirty-state close guards
|
|
303
|
+
- **`usePanelId()` hook** — zero-prop-drilling panel identity
|
|
304
|
+
- **Typed event bus** — `WorkspaceClient<AppEvents>` for type-safe inter-panel messaging
|
|
305
|
+
|
|
306
|
+
### v2.0.0 — Breaking Changes
|
|
307
|
+
|
|
308
|
+
| Removed | Replacement |
|
|
309
|
+
| :--- | :--- |
|
|
310
|
+
| `bringToFront(id)` | `focusPanel(id)` — works for both floating and docked panels |
|
|
311
|
+
| `setActivePanel(id)` | `focusPanel(id)` |
|
|
312
|
+
|
|
313
|
+
Full details in the [Migration Guide](https://felipecarrillo100.github.io/react-dockable-desktop/guide/migration).
|
|
314
|
+
|
|
139
315
|
---
|
|
140
316
|
|
|
141
317
|
## Documentation
|
|
142
318
|
|
|
143
|
-
|
|
319
|
+
Complete guides, API reference, and interactive demo at:
|
|
320
|
+
|
|
321
|
+
**[https://felipecarrillo100.github.io/react-dockable-desktop/](https://felipecarrillo100.github.io/react-dockable-desktop/)**
|
|
144
322
|
|
|
145
|
-
|
|
323
|
+
| Guide | Description |
|
|
324
|
+
| :--- | :--- |
|
|
325
|
+
| [Installation](https://felipecarrillo100.github.io/react-dockable-desktop/guide/installation) | Requirements, CSS import order, module formats |
|
|
326
|
+
| [Quick Start](https://felipecarrillo100.github.io/react-dockable-desktop/guide/quick-start) | Minimal working app with layout persistence |
|
|
327
|
+
| [WorkspaceClient](https://felipecarrillo100.github.io/react-dockable-desktop/guide/workspace-client) | Full imperative API, multiple providers, i18n config |
|
|
328
|
+
| [Panel Registry](https://felipecarrillo100.github.io/react-dockable-desktop/guide/panel-registry) | `defaultOptions`, scoped vs global registry |
|
|
329
|
+
| [Layout System](https://felipecarrillo100.github.io/react-dockable-desktop/guide/layout) | Opening, floating, minimizing, serializing layouts |
|
|
330
|
+
| [Panel Lifecycle & Forms](https://felipecarrillo100.github.io/react-dockable-desktop/guide/forms-and-panels) | Dirty state, close guards, `useFormContainer` |
|
|
331
|
+
| [Modals & Side Panels](https://felipecarrillo100.github.io/react-dockable-desktop/guide/modals-and-drawers) | Modal stack, drawers, `Sidebar` component |
|
|
332
|
+
| [Event Bus](https://felipecarrillo100.github.io/react-dockable-desktop/guide/event-bus) | Typed pub/sub, built-in lifecycle events |
|
|
333
|
+
| [Theming](https://felipecarrillo100.github.io/react-dockable-desktop/guide/theming) | CSS variables, custom skins, dark/light modes |
|
|
334
|
+
| [Advanced Topics](https://felipecarrillo100.github.io/react-dockable-desktop/guide/advanced) | RTL, multiple workspaces, custom header actions |
|
|
335
|
+
| [Best Practices](https://felipecarrillo100.github.io/react-dockable-desktop/guide/best-practices) | Patterns for production-ready implementations |
|
|
336
|
+
| [Migration Guide](https://felipecarrillo100.github.io/react-dockable-desktop/guide/migration) | Upgrade from v1 → v2 → v3 |
|
|
337
|
+
| [API Reference](https://felipecarrillo100.github.io/react-dockable-desktop/api/) | Full type-level reference for all exports |
|
|
338
|
+
|
|
339
|
+
---
|
|
146
340
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
341
|
+
## Development
|
|
342
|
+
|
|
343
|
+
```bash
|
|
344
|
+
git clone https://github.com/felipecarrillo100/react-dockable-desktop.git
|
|
345
|
+
cd react-dockable-desktop
|
|
346
|
+
npm install
|
|
347
|
+
npm run dev # Leaflet + Monaco open-source demo
|
|
348
|
+
npm run dev:ria # LuciadRIA 3D Earth demo (requires license)
|
|
349
|
+
npm test # vitest unit suite
|
|
350
|
+
npm run build # build dist/
|
|
351
|
+
```
|
|
152
352
|
|
|
153
353
|
---
|
|
154
354
|
|
|
155
355
|
## License
|
|
156
356
|
|
|
157
|
-
MIT
|
|
357
|
+
MIT — free to use, adapt, and build upon.
|