dockview-svelte 0.0.1

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 (36) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +480 -0
  3. package/dist/components/DefaultTab.svelte +55 -0
  4. package/dist/components/DefaultTab.svelte.d.ts +7 -0
  5. package/dist/components/Dockview.svelte +517 -0
  6. package/dist/components/Dockview.svelte.d.ts +113 -0
  7. package/dist/components/DvWidget.svelte +120 -0
  8. package/dist/components/DvWidget.svelte.d.ts +41 -0
  9. package/dist/components/Gridview.svelte +341 -0
  10. package/dist/components/Gridview.svelte.d.ts +73 -0
  11. package/dist/components/Paneview.svelte +307 -0
  12. package/dist/components/Paneview.svelte.d.ts +64 -0
  13. package/dist/components/Splitview.svelte +332 -0
  14. package/dist/components/Splitview.svelte.d.ts +70 -0
  15. package/dist/core/context.d.ts +62 -0
  16. package/dist/core/context.js +1 -0
  17. package/dist/core/effect-helpers.d.ts +7 -0
  18. package/dist/core/effect-helpers.js +23 -0
  19. package/dist/core/factory.svelte.d.ts +16 -0
  20. package/dist/core/factory.svelte.js +248 -0
  21. package/dist/core/gridview.svelte.d.ts +31 -0
  22. package/dist/core/gridview.svelte.js +177 -0
  23. package/dist/core/paneview-test-helpers.js +28 -0
  24. package/dist/core/paneview.svelte.d.ts +29 -0
  25. package/dist/core/paneview.svelte.js +186 -0
  26. package/dist/core/registry.d.ts +88 -0
  27. package/dist/core/registry.js +143 -0
  28. package/dist/core/splitview.svelte.d.ts +32 -0
  29. package/dist/core/splitview.svelte.js +179 -0
  30. package/dist/core/types.d.ts +424 -0
  31. package/dist/core/types.js +1 -0
  32. package/dist/core/utils.d.ts +12 -0
  33. package/dist/core/utils.js +59 -0
  34. package/dist/index.d.ts +9 -0
  35. package/dist/index.js +11 -0
  36. package/package.json +66 -0
@@ -0,0 +1,517 @@
1
+ <script lang="ts" generics="const W extends Widgets">
2
+ import type {
3
+ AddPanelOptions,
4
+ DockviewActivePanelChangeEvent,
5
+ DockviewApi,
6
+ DockviewComponentOptions,
7
+ DockviewDidDropEvent,
8
+ DockviewDndOverlayEvent,
9
+ DockviewGroupPanel,
10
+ DockviewLayoutMutationEvent,
11
+ DockviewMaximizedGroupChangeEvent,
12
+ DockviewPanelPinnedChangeEvent,
13
+ DockviewPopoutGroupOptions,
14
+ DockviewTabGroupChangeEvent,
15
+ DockviewTabGroupCollapsedChangeEvent,
16
+ DockviewTabGroupPanelChangeEvent,
17
+ DockviewWillDropEvent,
18
+ DockviewWillShowOverlayLocationEvent,
19
+ FloatingGroupOptions,
20
+ GroupDragEvent,
21
+ IDockviewPanel,
22
+ LayoutHistoryChangeEvent,
23
+ MovePanelEvent,
24
+ PopoutGroup,
25
+ PopoutGroupChangePositionEvent,
26
+ PopoutGroupChangeSizeEvent,
27
+ SerializedDockview,
28
+ SmartGuidesSnapEvent,
29
+ SmartGuidesSnapTogetherEvent,
30
+ TabDragEvent,
31
+ } from 'dockview'
32
+ import { DockviewComponent } from 'dockview'
33
+ import { onMount, type Snippet, setContext } from 'svelte'
34
+ import { DOCKVIEW_CONTEXT_KEY } from '../core/context.js'
35
+ import { createDockviewFactory, type DockviewFactory } from '../core/factory.svelte.js'
36
+ import { WidgetRegistry } from '../core/registry.js'
37
+ import type {
38
+ ActiveState,
39
+ DockviewHandle,
40
+ FloatingState,
41
+ HeaderActionComponent,
42
+ OpenPanelOptions,
43
+ PanelHandle,
44
+ ParamsOf,
45
+ PopoutState,
46
+ WatermarkComponent,
47
+ WidgetDefinition,
48
+ Widgets,
49
+ } from '../core/types.js'
50
+ import { deepEqual } from '../core/utils.js'
51
+
52
+ interface Props<W extends Widgets> {
53
+ /** Widget registry: `{ [key]: { component, tab?, title? } }`. */
54
+ widgets?: W
55
+ /**
56
+ * `DockviewComponentOptions` passthrough (theme, keyboard, history, …).
57
+ *
58
+ * `createComponent` / `createTabComponent` are owned by the library (Svelte
59
+ * `mount` factories backed by the `widgets` registry) and cannot be
60
+ * overridden. The header-action factories are likewise owned when the
61
+ * `leftHeaderActions` / `rightHeaderActions` / `prefixHeaderActions` props
62
+ * are set (Svelte components win over the raw options). The remaining
63
+ * raw-dockview factories pass through untouched and are NOT Svelte-wrapped
64
+ * — use them only if you want to render those slots imperatively yourself:
65
+ * `createWatermarkComponent`, `createTabGroupChipComponent`,
66
+ * `createGroupDragGhostComponent`, `createContextMenuItemComponent`.
67
+ * (`defaultTabComponent` is a plain string key and works with the registry
68
+ * as-is.)
69
+ */
70
+ options?: Omit<
71
+ DockviewComponentOptions,
72
+ | 'createComponent'
73
+ | 'createTabComponent'
74
+ | 'createLeftHeaderActionComponent'
75
+ | 'createRightHeaderActionComponent'
76
+ | 'createPrefixHeaderActionComponent'
77
+ >
78
+ /**
79
+ * Svelte components rendered into the group header slots (left of tabs,
80
+ * right of tabs, before everything). Each receives { api, containerApi,
81
+ * group } per group. Set props win over the raw options factories.
82
+ */
83
+ leftHeaderActions?: HeaderActionComponent
84
+ rightHeaderActions?: HeaderActionComponent
85
+ prefixHeaderActions?: HeaderActionComponent
86
+ /**
87
+ * Svelte empty-state overlay, rendered as a plain child when the dock has
88
+ * no panels. Receives `{ openPanel }` — no `IWatermarkRenderer` factory
89
+ * involved, so it gets context automatically like any Svelte child.
90
+ */
91
+ watermark?: WatermarkComponent
92
+ /** `bind:layout` — dockview JSON (`toJSON`/`fromJSON` shape). */
93
+ layout?: SerializedDockview
94
+ /** `bind:handle` — `{ api, openPanel, registerWidget }`. */
95
+ handle?: DockviewHandle<W>
96
+ /** `bind:active` — reactive `{ panel, group }` of the current active panel/group. */
97
+ active?: ActiveState
98
+ /** `bind:floating` — reactive `{ count, hasFloating }` of open floating windows. */
99
+ floating?: FloatingState
100
+ /** `bind:popout` — reactive `{ count, hasPopout }` of open popout windows. */
101
+ popout?: PopoutState
102
+ /** Extra classes for the root container. */
103
+ class?: string
104
+ /** Declarative widgets (`<DvWidget>` children) — alternative to the `widgets` prop. */
105
+ children?: Snippet
106
+ /** Fired once the component is mounted and `api` is ready. */
107
+ onReady?: (event: { api: DockviewApi; handle: DockviewHandle<W> }) => void
108
+ onDidLayoutChange?: () => void
109
+ onDidLayoutFromJSON?: () => void
110
+ onDidAddPanel?: (panel: IDockviewPanel) => void
111
+ onDidRemovePanel?: (panel: IDockviewPanel) => void
112
+ onDidAddGroup?: (group: DockviewGroupPanel) => void
113
+ onDidRemoveGroup?: (group: DockviewGroupPanel) => void
114
+ onDidActivePanelChange?: (event: DockviewActivePanelChangeEvent) => void
115
+ onDidActiveGroupChange?: (group: DockviewGroupPanel | undefined) => void
116
+ onDidMovePanel?: (event: MovePanelEvent) => void
117
+ onWillDrop?: (event: DockviewWillDropEvent) => void
118
+ onDidDrop?: (event: DockviewDidDropEvent) => void
119
+ onWillDragPanel?: (event: TabDragEvent) => void
120
+ onWillDragGroup?: (event: GroupDragEvent) => void
121
+ onWillMutateLayout?: (event: DockviewLayoutMutationEvent) => void
122
+ onDidMutateLayout?: (event: DockviewLayoutMutationEvent) => void
123
+ onWillShowOverlay?: (event: DockviewWillShowOverlayLocationEvent) => void
124
+ onUnhandledDragOver?: (event: DockviewDndOverlayEvent) => void
125
+ onDidAddPopoutGroup?: (group: PopoutGroup) => void
126
+ onDidRemovePopoutGroup?: (group: PopoutGroup) => void
127
+ onDidPopoutGroupSizeChange?: (event: PopoutGroupChangeSizeEvent) => void
128
+ onDidPopoutGroupPositionChange?: (event: PopoutGroupChangePositionEvent) => void
129
+ onDidOpenPopoutWindowFail?: () => void
130
+ onDidCreateTabGroup?: (event: DockviewTabGroupChangeEvent) => void
131
+ onDidDestroyTabGroup?: (event: DockviewTabGroupChangeEvent) => void
132
+ onDidAddPanelToTabGroup?: (event: DockviewTabGroupPanelChangeEvent) => void
133
+ onDidRemovePanelFromTabGroup?: (event: DockviewTabGroupPanelChangeEvent) => void
134
+ onDidTabGroupChange?: (event: DockviewTabGroupChangeEvent) => void
135
+ onDidTabGroupCollapsedChange?: (event: DockviewTabGroupCollapsedChangeEvent) => void
136
+ onDidPanelPinnedChange?: (event: DockviewPanelPinnedChangeEvent) => void
137
+ onDidMaximizedGroupChange?: (event: DockviewMaximizedGroupChangeEvent) => void
138
+ onDidChangeHistory?: (event: LayoutHistoryChangeEvent) => void
139
+ onDidSnapFloat?: (event: SmartGuidesSnapEvent) => void
140
+ onDidSnapTogether?: (event: SmartGuidesSnapTogetherEvent) => void
141
+ }
142
+
143
+ let {
144
+ widgets = {} as W,
145
+ options = {},
146
+ watermark,
147
+ leftHeaderActions,
148
+ rightHeaderActions,
149
+ prefixHeaderActions,
150
+ layout = $bindable(),
151
+ handle = $bindable(),
152
+ active = $bindable({ panel: undefined, group: undefined }),
153
+ floating = $bindable({ count: 0, hasFloating: false }),
154
+ popout = $bindable({ count: 0, hasPopout: false }),
155
+ class: className = '',
156
+ children,
157
+ onReady,
158
+ onDidLayoutChange,
159
+ onDidLayoutFromJSON,
160
+ onDidAddPanel,
161
+ onDidRemovePanel,
162
+ onDidAddGroup,
163
+ onDidRemoveGroup,
164
+ onDidActivePanelChange,
165
+ onDidActiveGroupChange,
166
+ onDidMovePanel,
167
+ onWillDrop,
168
+ onDidDrop,
169
+ onWillDragPanel,
170
+ onWillDragGroup,
171
+ onWillMutateLayout,
172
+ onDidMutateLayout,
173
+ onWillShowOverlay,
174
+ onUnhandledDragOver,
175
+ onDidAddPopoutGroup,
176
+ onDidRemovePopoutGroup,
177
+ onDidPopoutGroupSizeChange,
178
+ onDidPopoutGroupPositionChange,
179
+ onDidOpenPopoutWindowFail,
180
+ onDidCreateTabGroup,
181
+ onDidDestroyTabGroup,
182
+ onDidAddPanelToTabGroup,
183
+ onDidRemovePanelFromTabGroup,
184
+ onDidTabGroupChange,
185
+ onDidTabGroupCollapsedChange,
186
+ onDidPanelPinnedChange,
187
+ onDidMaximizedGroupChange,
188
+ onDidChangeHistory,
189
+ onDidSnapFloat,
190
+ onDidSnapTogether,
191
+ }: Props<W> = $props()
192
+
193
+ let container: HTMLElement
194
+ let component: DockviewComponent | undefined
195
+ let factory: DockviewFactory | undefined
196
+ let api = $state<DockviewApi | undefined>(undefined)
197
+ /** Panel count mirror — drives the Svelte `watermark` overlay. */
198
+ let panelCount = $state(0)
199
+
200
+ /** Refresh `bind:floating` / `bind:popout` + `panelCount` from the live layout. */
201
+ function refreshCounts(): void {
202
+ if (!component) return
203
+ const floatCount = component.api.groups.filter((g) => g.api.location.type === 'floating').length
204
+ const popoutCount = component.api.getPopouts().length
205
+ floating = { count: floatCount, hasFloating: floatCount > 0 }
206
+ popout = { count: popoutCount, hasPopout: popoutCount > 0 }
207
+ panelCount = component.api.panels.length
208
+ }
209
+
210
+ const registry = new WidgetRegistry()
211
+ const counters = new Map<string, number>()
212
+
213
+ // Stable `registerWidget`, shared by context and handle.
214
+ function registerWidget(key: string, def: WidgetDefinition): void {
215
+ registry.register(key, def)
216
+ }
217
+
218
+ function unregisterWidget(key: string): void {
219
+ registry.unregister(key)
220
+ }
221
+
222
+ // Context for descendant widgets (api is populated after mount).
223
+ const context = $state({
224
+ api: undefined as DockviewApi | undefined,
225
+ registerWidget,
226
+ unregisterWidget,
227
+ kind: 'dockview' as const,
228
+ })
229
+ setContext(DOCKVIEW_CONTEXT_KEY, context)
230
+
231
+ // Seed the registry from the `widgets` prop (additive).
232
+ $effect(() => {
233
+ registry.seed(widgets)
234
+ })
235
+
236
+ function nextId(key: string): string {
237
+ const n = (counters.get(key) ?? 0) + 1
238
+ counters.set(key, n)
239
+ return `${key}-${n}`
240
+ }
241
+
242
+ /** `bind:layout` loop-break: the JSON we last emitted to the parent. */
243
+ let lastEmitted: SerializedDockview | undefined
244
+
245
+ /** Serialize the current layout and push it to the bound `layout`. */
246
+ function emitLayout(): void {
247
+ if (!component) return
248
+ const json = component.api.toJSON()
249
+ lastEmitted = json
250
+ layout = json
251
+ refreshCounts()
252
+ }
253
+
254
+ function openPanel<K extends keyof W & string>(
255
+ key: K,
256
+ opts?: OpenPanelOptions<ParamsOf<W[K]['component']>>
257
+ ): PanelHandle<ParamsOf<W[K]['component']>> {
258
+ if (!api || !factory) {
259
+ throw new Error('dockview-svelte: Dockview is not mounted yet')
260
+ }
261
+ const def = registry.get(key)
262
+ if (!def) {
263
+ throw new Error(`dockview-svelte: unknown widget "${key}"`)
264
+ }
265
+
266
+ const title = opts?.title ?? def.title ?? key
267
+ const id = opts?.id ?? nextId(key)
268
+
269
+ const addOptions = {
270
+ ...(opts ?? {}),
271
+ id,
272
+ title,
273
+ component: key,
274
+ tabComponent: key,
275
+ params: opts?.params,
276
+ } as AddPanelOptions
277
+
278
+ const panel = api.addPanel(addOptions)
279
+ // `addPanel` fires `onDidAddPanel` (which refreshes counts) but not a layout
280
+ // event — emit the layout directly so `bind:layout` reflects the new panel.
281
+ emitLayout()
282
+
283
+ const state = factory.getState(id)
284
+ return { id, panel, api: panel.api, state: state! } as PanelHandle<ParamsOf<W[K]['component']>>
285
+ }
286
+
287
+ /**
288
+ * Float an existing panel or group into its own window.
289
+ * Accepts an `IDockviewPanel`, a `DockviewGroupPanel`, or a panel id string.
290
+ */
291
+ function float(
292
+ target: IDockviewPanel | DockviewGroupPanel | string,
293
+ options?: FloatingGroupOptions
294
+ ): void {
295
+ if (!api) {
296
+ throw new Error('dockview-svelte: Dockview is not mounted yet')
297
+ }
298
+ const item =
299
+ typeof target === 'string'
300
+ ? (api.getPanel(target) ?? api.groups.find((g) => g.id === target))
301
+ : target
302
+ if (!item) {
303
+ throw new Error(`dockview-svelte: unknown panel or group "${target}"`)
304
+ }
305
+ api.addFloatingGroup(item, options)
306
+ }
307
+
308
+ /**
309
+ * Pop an existing panel or group out into its own browser window.
310
+ * Accepts an `IDockviewPanel`, a `DockviewGroupPanel`, or a panel id string.
311
+ * Resolves `true` on success, `false` if the popout window failed to open.
312
+ */
313
+ function popoutGroup(
314
+ target: IDockviewPanel | DockviewGroupPanel | string,
315
+ options?: DockviewPopoutGroupOptions
316
+ ): Promise<boolean> {
317
+ if (!api) {
318
+ throw new Error('dockview-svelte: Dockview is not mounted yet')
319
+ }
320
+ const item =
321
+ typeof target === 'string'
322
+ ? (api.getPanel(target) ?? api.groups.find((g) => g.id === target))
323
+ : target
324
+ if (!item) {
325
+ throw new Error(`dockview-svelte: unknown panel or group "${target}"`)
326
+ }
327
+ return api.addPopoutGroup(item, options)
328
+ }
329
+
330
+ /** Dock every floating window back into the main grid. */
331
+ function dockAll(): void {
332
+ if (!api) {
333
+ throw new Error('dockview-svelte: Dockview is not mounted yet')
334
+ }
335
+ // `api.groups` includes floating groups — target the first grid group so
336
+ // floating panels actually move back (moving into a floating group is a no-op).
337
+ const grid = api.groups.find((g) => g.api.location.type === 'grid') ?? api.groups[0]
338
+ if (!grid) return
339
+ for (const panel of [...api.panels]) {
340
+ if (panel.api.location.type !== 'grid') {
341
+ panel.api.moveTo({ group: grid, position: 'center' })
342
+ }
343
+ }
344
+ }
345
+
346
+ // External `layout` changes → apply via `fromJSON` (loop-break via `lastEmitted`).
347
+ $effect(() => {
348
+ const current = api
349
+ if (!current || !layout) return
350
+ if (deepEqual(lastEmitted, layout)) return
351
+ current.fromJSON(layout)
352
+ })
353
+
354
+ // Live `options` changes (theme, etc.) → apply via `updateOptions`.
355
+ // The constructor reads `options` once; without this, later prop changes
356
+ // (e.g. `options={{ theme: themes[name] }}`) are silently ignored.
357
+ // NOTE: `opts` must be read before the `component` guard — otherwise the
358
+ // initial run returns early without tracking `options`, and later theme
359
+ // changes never re-trigger the effect.
360
+ $effect(() => {
361
+ const opts = options
362
+ if (!component) return
363
+ component.updateOptions(opts)
364
+ })
365
+
366
+ onMount(() => {
367
+ factory = createDockviewFactory(registry, context, {
368
+ left: leftHeaderActions,
369
+ right: rightHeaderActions,
370
+ prefix: prefixHeaderActions,
371
+ })
372
+ const headerFactories = factory.createHeaderActionFactories
373
+ const created = new DockviewComponent(container, {
374
+ ...options,
375
+ createComponent: factory.createComponent,
376
+ createTabComponent: factory.createTabComponent,
377
+ ...(headerFactories.left ? { createLeftHeaderActionComponent: headerFactories.left } : {}),
378
+ ...(headerFactories.right ? { createRightHeaderActionComponent: headerFactories.right } : {}),
379
+ ...(headerFactories.prefix
380
+ ? { createPrefixHeaderActionComponent: headerFactories.prefix }
381
+ : {}),
382
+ })
383
+ // Apply a pre-existing `bind:layout` (e.g. a hard-coded initial layout)
384
+ // before exposing the api — the `$effect` above only reacts to changes.
385
+ if (layout) {
386
+ created.api.fromJSON(layout)
387
+ lastEmitted = created.api.toJSON()
388
+ layout = lastEmitted
389
+ }
390
+ component = created
391
+ api = created.api
392
+ context.api = created.api
393
+
394
+ const createdHandle: DockviewHandle<W> = {
395
+ api: created.api,
396
+ openPanel,
397
+ registerWidget,
398
+ float,
399
+ dockAll,
400
+ popout: popoutGroup,
401
+ }
402
+ handle = createdHandle
403
+
404
+ // Seed the initial active panel/group (before any change event fires).
405
+ active = { panel: created.api.activePanel, group: created.api.activeGroup }
406
+ refreshCounts()
407
+
408
+ const apiHandle = created.api
409
+
410
+ // Bridge dockview events to callbacks, disposing on teardown.
411
+ const subscriptions = [
412
+ apiHandle.onDidLayoutChange(() => {
413
+ emitLayout()
414
+ onDidLayoutChange?.()
415
+ }),
416
+ apiHandle.onDidLayoutFromJSON(() => {
417
+ refreshCounts()
418
+ onDidLayoutFromJSON?.()
419
+ }),
420
+ apiHandle.onDidAddPanel((panel) => {
421
+ refreshCounts()
422
+ onDidAddPanel?.(panel)
423
+ }),
424
+ apiHandle.onDidRemovePanel((panel) => {
425
+ refreshCounts()
426
+ onDidRemovePanel?.(panel)
427
+ }),
428
+ apiHandle.onDidAddGroup((group) => {
429
+ refreshCounts()
430
+ onDidAddGroup?.(group)
431
+ }),
432
+ apiHandle.onDidRemoveGroup((group) => {
433
+ refreshCounts()
434
+ onDidRemoveGroup?.(group)
435
+ }),
436
+ apiHandle.onDidActivePanelChange((event) => {
437
+ onDidActivePanelChange?.(event)
438
+ active = { panel: event.panel, group: apiHandle.activeGroup }
439
+ }),
440
+ apiHandle.onDidActiveGroupChange((group) => {
441
+ onDidActiveGroupChange?.(group)
442
+ active = { panel: apiHandle.activePanel, group }
443
+ }),
444
+ apiHandle.onDidMovePanel((event) => {
445
+ refreshCounts()
446
+ onDidMovePanel?.(event)
447
+ }),
448
+ apiHandle.onWillDrop((event) => onWillDrop?.(event)),
449
+ apiHandle.onDidDrop((event) => onDidDrop?.(event)),
450
+ apiHandle.onWillDragPanel((event) => onWillDragPanel?.(event)),
451
+ apiHandle.onWillDragGroup((event) => onWillDragGroup?.(event)),
452
+ apiHandle.onWillMutateLayout((event) => onWillMutateLayout?.(event)),
453
+ apiHandle.onDidMutateLayout((event) => onDidMutateLayout?.(event)),
454
+ apiHandle.onWillShowOverlay((event) => onWillShowOverlay?.(event)),
455
+ apiHandle.onUnhandledDragOver((event) => onUnhandledDragOver?.(event)),
456
+ apiHandle.onDidAddPopoutGroup((group) => {
457
+ refreshCounts()
458
+ onDidAddPopoutGroup?.(group)
459
+ }),
460
+ apiHandle.onDidRemovePopoutGroup((group) => {
461
+ refreshCounts()
462
+ onDidRemovePopoutGroup?.(group)
463
+ }),
464
+ apiHandle.onDidPopoutGroupSizeChange((event) => onDidPopoutGroupSizeChange?.(event)),
465
+ apiHandle.onDidPopoutGroupPositionChange((event) => onDidPopoutGroupPositionChange?.(event)),
466
+ apiHandle.onDidOpenPopoutWindowFail(() => onDidOpenPopoutWindowFail?.()),
467
+ apiHandle.onDidCreateTabGroup((event) => onDidCreateTabGroup?.(event)),
468
+ apiHandle.onDidDestroyTabGroup((event) => onDidDestroyTabGroup?.(event)),
469
+ apiHandle.onDidAddPanelToTabGroup((event) => onDidAddPanelToTabGroup?.(event)),
470
+ apiHandle.onDidRemovePanelFromTabGroup((event) => onDidRemovePanelFromTabGroup?.(event)),
471
+ apiHandle.onDidTabGroupChange((event) => onDidTabGroupChange?.(event)),
472
+ apiHandle.onDidTabGroupCollapsedChange((event) => onDidTabGroupCollapsedChange?.(event)),
473
+ apiHandle.onDidPanelPinnedChange((event) => onDidPanelPinnedChange?.(event)),
474
+ apiHandle.onDidMaximizedGroupChange((event) => onDidMaximizedGroupChange?.(event)),
475
+ apiHandle.onDidChangeHistory((event) => onDidChangeHistory?.(event)),
476
+ apiHandle.onDidSnapFloat((event) => onDidSnapFloat?.(event)),
477
+ apiHandle.onDidSnapTogether((event) => onDidSnapTogether?.(event)),
478
+ ]
479
+ onReady?.({ api: created.api, handle: createdHandle })
480
+
481
+ return () => {
482
+ for (const disposable of subscriptions) disposable.dispose()
483
+ created.dispose()
484
+ component = undefined
485
+ api = undefined
486
+ factory = undefined
487
+ lastEmitted = undefined
488
+ }
489
+ })
490
+ </script>
491
+
492
+ <div class="dv-svelte-root {className}" bind:this={container}>
493
+ {#if watermark && panelCount === 0 && handle}
494
+ {@const Watermark = watermark}
495
+ <div class="dv-svelte-watermark-overlay">
496
+ <Watermark openPanel={handle.openPanel} />
497
+ </div>
498
+ {/if}
499
+ {#if children}
500
+ {@render children()}
501
+ {/if}
502
+ </div>
503
+
504
+ <style>
505
+ .dv-svelte-root {
506
+ width: 100%;
507
+ height: 100%;
508
+ position: relative;
509
+ }
510
+ .dv-svelte-watermark-overlay {
511
+ position: absolute;
512
+ inset: 0;
513
+ /* Above dockview's own `.dv-watermark-container` (z-index 1, later in
514
+ DOM) — otherwise it paints over us and swallows overlay clicks. */
515
+ z-index: 2;
516
+ }
517
+ </style>
@@ -0,0 +1,113 @@
1
+ import type { DockviewActivePanelChangeEvent, DockviewApi, DockviewComponentOptions, DockviewDidDropEvent, DockviewDndOverlayEvent, DockviewGroupPanel, DockviewLayoutMutationEvent, DockviewMaximizedGroupChangeEvent, DockviewPanelPinnedChangeEvent, DockviewTabGroupChangeEvent, DockviewTabGroupCollapsedChangeEvent, DockviewTabGroupPanelChangeEvent, DockviewWillDropEvent, DockviewWillShowOverlayLocationEvent, GroupDragEvent, IDockviewPanel, LayoutHistoryChangeEvent, MovePanelEvent, PopoutGroup, PopoutGroupChangePositionEvent, PopoutGroupChangeSizeEvent, SerializedDockview, SmartGuidesSnapEvent, SmartGuidesSnapTogetherEvent, TabDragEvent } from 'dockview';
2
+ import { type Snippet } from 'svelte';
3
+ import type { ActiveState, DockviewHandle, FloatingState, HeaderActionComponent, PopoutState, WatermarkComponent, Widgets } from '../core/types.js';
4
+ interface Props<W extends Widgets> {
5
+ /** Widget registry: `{ [key]: { component, tab?, title? } }`. */
6
+ widgets?: W;
7
+ /**
8
+ * `DockviewComponentOptions` passthrough (theme, keyboard, history, …).
9
+ *
10
+ * `createComponent` / `createTabComponent` are owned by the library (Svelte
11
+ * `mount` factories backed by the `widgets` registry) and cannot be
12
+ * overridden. The header-action factories are likewise owned when the
13
+ * `leftHeaderActions` / `rightHeaderActions` / `prefixHeaderActions` props
14
+ * are set (Svelte components win over the raw options). The remaining
15
+ * raw-dockview factories pass through untouched and are NOT Svelte-wrapped
16
+ * — use them only if you want to render those slots imperatively yourself:
17
+ * `createWatermarkComponent`, `createTabGroupChipComponent`,
18
+ * `createGroupDragGhostComponent`, `createContextMenuItemComponent`.
19
+ * (`defaultTabComponent` is a plain string key and works with the registry
20
+ * as-is.)
21
+ */
22
+ options?: Omit<DockviewComponentOptions, 'createComponent' | 'createTabComponent' | 'createLeftHeaderActionComponent' | 'createRightHeaderActionComponent' | 'createPrefixHeaderActionComponent'>;
23
+ /**
24
+ * Svelte components rendered into the group header slots (left of tabs,
25
+ * right of tabs, before everything). Each receives { api, containerApi,
26
+ * group } per group. Set props win over the raw options factories.
27
+ */
28
+ leftHeaderActions?: HeaderActionComponent;
29
+ rightHeaderActions?: HeaderActionComponent;
30
+ prefixHeaderActions?: HeaderActionComponent;
31
+ /**
32
+ * Svelte empty-state overlay, rendered as a plain child when the dock has
33
+ * no panels. Receives `{ openPanel }` — no `IWatermarkRenderer` factory
34
+ * involved, so it gets context automatically like any Svelte child.
35
+ */
36
+ watermark?: WatermarkComponent;
37
+ /** `bind:layout` — dockview JSON (`toJSON`/`fromJSON` shape). */
38
+ layout?: SerializedDockview;
39
+ /** `bind:handle` — `{ api, openPanel, registerWidget }`. */
40
+ handle?: DockviewHandle<W>;
41
+ /** `bind:active` — reactive `{ panel, group }` of the current active panel/group. */
42
+ active?: ActiveState;
43
+ /** `bind:floating` — reactive `{ count, hasFloating }` of open floating windows. */
44
+ floating?: FloatingState;
45
+ /** `bind:popout` — reactive `{ count, hasPopout }` of open popout windows. */
46
+ popout?: PopoutState;
47
+ /** Extra classes for the root container. */
48
+ class?: string;
49
+ /** Declarative widgets (`<DvWidget>` children) — alternative to the `widgets` prop. */
50
+ children?: Snippet;
51
+ /** Fired once the component is mounted and `api` is ready. */
52
+ onReady?: (event: {
53
+ api: DockviewApi;
54
+ handle: DockviewHandle<W>;
55
+ }) => void;
56
+ onDidLayoutChange?: () => void;
57
+ onDidLayoutFromJSON?: () => void;
58
+ onDidAddPanel?: (panel: IDockviewPanel) => void;
59
+ onDidRemovePanel?: (panel: IDockviewPanel) => void;
60
+ onDidAddGroup?: (group: DockviewGroupPanel) => void;
61
+ onDidRemoveGroup?: (group: DockviewGroupPanel) => void;
62
+ onDidActivePanelChange?: (event: DockviewActivePanelChangeEvent) => void;
63
+ onDidActiveGroupChange?: (group: DockviewGroupPanel | undefined) => void;
64
+ onDidMovePanel?: (event: MovePanelEvent) => void;
65
+ onWillDrop?: (event: DockviewWillDropEvent) => void;
66
+ onDidDrop?: (event: DockviewDidDropEvent) => void;
67
+ onWillDragPanel?: (event: TabDragEvent) => void;
68
+ onWillDragGroup?: (event: GroupDragEvent) => void;
69
+ onWillMutateLayout?: (event: DockviewLayoutMutationEvent) => void;
70
+ onDidMutateLayout?: (event: DockviewLayoutMutationEvent) => void;
71
+ onWillShowOverlay?: (event: DockviewWillShowOverlayLocationEvent) => void;
72
+ onUnhandledDragOver?: (event: DockviewDndOverlayEvent) => void;
73
+ onDidAddPopoutGroup?: (group: PopoutGroup) => void;
74
+ onDidRemovePopoutGroup?: (group: PopoutGroup) => void;
75
+ onDidPopoutGroupSizeChange?: (event: PopoutGroupChangeSizeEvent) => void;
76
+ onDidPopoutGroupPositionChange?: (event: PopoutGroupChangePositionEvent) => void;
77
+ onDidOpenPopoutWindowFail?: () => void;
78
+ onDidCreateTabGroup?: (event: DockviewTabGroupChangeEvent) => void;
79
+ onDidDestroyTabGroup?: (event: DockviewTabGroupChangeEvent) => void;
80
+ onDidAddPanelToTabGroup?: (event: DockviewTabGroupPanelChangeEvent) => void;
81
+ onDidRemovePanelFromTabGroup?: (event: DockviewTabGroupPanelChangeEvent) => void;
82
+ onDidTabGroupChange?: (event: DockviewTabGroupChangeEvent) => void;
83
+ onDidTabGroupCollapsedChange?: (event: DockviewTabGroupCollapsedChangeEvent) => void;
84
+ onDidPanelPinnedChange?: (event: DockviewPanelPinnedChangeEvent) => void;
85
+ onDidMaximizedGroupChange?: (event: DockviewMaximizedGroupChangeEvent) => void;
86
+ onDidChangeHistory?: (event: LayoutHistoryChangeEvent) => void;
87
+ onDidSnapFloat?: (event: SmartGuidesSnapEvent) => void;
88
+ onDidSnapTogether?: (event: SmartGuidesSnapTogetherEvent) => void;
89
+ }
90
+ declare function $$render<const W extends Widgets>(): {
91
+ props: Props<W>;
92
+ exports: {};
93
+ bindings: "floating" | "layout" | "active" | "handle" | "popout";
94
+ slots: {};
95
+ events: {};
96
+ };
97
+ declare class __sveltets_Render<const W extends Widgets> {
98
+ props(): ReturnType<typeof $$render<W>>['props'];
99
+ events(): ReturnType<typeof $$render<W>>['events'];
100
+ slots(): ReturnType<typeof $$render<W>>['slots'];
101
+ bindings(): "floating" | "layout" | "active" | "handle" | "popout";
102
+ exports(): {};
103
+ }
104
+ interface $$IsomorphicComponent {
105
+ new <const W extends Widgets>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<W>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<W>['props']>, ReturnType<__sveltets_Render<W>['events']>, ReturnType<__sveltets_Render<W>['slots']>> & {
106
+ $$bindings?: ReturnType<__sveltets_Render<W>['bindings']>;
107
+ } & ReturnType<__sveltets_Render<W>['exports']>;
108
+ <const W extends Widgets>(internal: unknown, props: ReturnType<__sveltets_Render<W>['props']> & {}): ReturnType<__sveltets_Render<W>['exports']>;
109
+ z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
110
+ }
111
+ declare const Dockview: $$IsomorphicComponent;
112
+ type Dockview<const W extends Widgets> = InstanceType<typeof Dockview<W>>;
113
+ export default Dockview;