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.
- package/LICENSE +661 -0
- package/README.md +480 -0
- package/dist/components/DefaultTab.svelte +55 -0
- package/dist/components/DefaultTab.svelte.d.ts +7 -0
- package/dist/components/Dockview.svelte +517 -0
- package/dist/components/Dockview.svelte.d.ts +113 -0
- package/dist/components/DvWidget.svelte +120 -0
- package/dist/components/DvWidget.svelte.d.ts +41 -0
- package/dist/components/Gridview.svelte +341 -0
- package/dist/components/Gridview.svelte.d.ts +73 -0
- package/dist/components/Paneview.svelte +307 -0
- package/dist/components/Paneview.svelte.d.ts +64 -0
- package/dist/components/Splitview.svelte +332 -0
- package/dist/components/Splitview.svelte.d.ts +70 -0
- package/dist/core/context.d.ts +62 -0
- package/dist/core/context.js +1 -0
- package/dist/core/effect-helpers.d.ts +7 -0
- package/dist/core/effect-helpers.js +23 -0
- package/dist/core/factory.svelte.d.ts +16 -0
- package/dist/core/factory.svelte.js +248 -0
- package/dist/core/gridview.svelte.d.ts +31 -0
- package/dist/core/gridview.svelte.js +177 -0
- package/dist/core/paneview-test-helpers.js +28 -0
- package/dist/core/paneview.svelte.d.ts +29 -0
- package/dist/core/paneview.svelte.js +186 -0
- package/dist/core/registry.d.ts +88 -0
- package/dist/core/registry.js +143 -0
- package/dist/core/splitview.svelte.d.ts +32 -0
- package/dist/core/splitview.svelte.js +179 -0
- package/dist/core/types.d.ts +424 -0
- package/dist/core/types.js +1 -0
- package/dist/core/utils.d.ts +12 -0
- package/dist/core/utils.js +59 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +11 -0
- 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;
|