dockview-core 8.1.0 → 8.3.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.
@@ -77,6 +77,13 @@ export interface DockviewGroupPanelApi extends GridviewPanelApi {
77
77
  isMaximized(): boolean;
78
78
  exitMaximized(): void;
79
79
  close(): void;
80
+ /**
81
+ * Resize this group, clamped by its constraints and the space available.
82
+ * An edge group is sized along its own axis only - `width` for
83
+ * `left`/`right`, `height` for `top`/`bottom` - and that size is the one
84
+ * it expands to, so a collapsed group keeps its strip until expanded.
85
+ */
86
+ setSize(event: SizeEvent): void;
80
87
  /**
81
88
  * Collapse this group (edge groups only). No-op for non-edge groups.
82
89
  */
@@ -101,5 +101,17 @@ export declare class DockviewPanelApiImpl extends GridviewPanelApiImpl implement
101
101
  maximize(): void;
102
102
  isMaximized(): boolean;
103
103
  exitMaximized(): void;
104
+ /**
105
+ * Report that this panel's location may have moved.
106
+ *
107
+ * A relocation touches the location more than once - the panel is
108
+ * reparented into the destination group, then that group is tagged with
109
+ * the location it ends up at - so the event is coalesced to the end of the
110
+ * enclosing layout mutation and reports where the panel actually settled.
111
+ * Firing each signal as it happened surfaced an intermediate `grid`
112
+ * location the panel was never in, at a point where it was in neither
113
+ * group's panel list. Outside a mutation this fires straight away.
114
+ */
115
+ private fireLocationChange;
104
116
  private setupGroupEventListeners;
105
117
  }
@@ -15,6 +15,12 @@ export declare class DropTargetAnchorContainer extends CompositeDisposable {
15
15
  * drag genuinely leaves to somewhere that doesn't re-render here.
16
16
  */
17
17
  private _pendingClear;
18
+ /**
19
+ * The element the live overlay was rendered for, `undefined` when nothing
20
+ * is showing. The container is shared by every drop target, so a caller
21
+ * tearing down only its own overlay must check this before `clear()`.
22
+ */
23
+ get renderedOutline(): HTMLElement | undefined;
18
24
  get disabled(): boolean;
19
25
  set disabled(value: boolean);
20
26
  private _cancelPendingClear;
@@ -142,6 +142,14 @@ export declare class TabReorderController extends CompositeDisposable {
142
142
  * zone, or into the void container; tears it down otherwise.
143
143
  */
144
144
  processDragLeave(related: Element | null): void;
145
+ /**
146
+ * Clear the anchored overlay only when this header is what rendered it.
147
+ * The container is shared with the group's content drop target, which
148
+ * renders into it on the same frame the cursor leaves the strip: the
149
+ * pointer backend calls `handleDragOver` on the new target before the
150
+ * global `onDragMove` that reaches us (#1612).
151
+ */
152
+ private clearHeaderAnchorOverlay;
145
153
  handleDragOver(event: {
146
154
  clientX: number;
147
155
  clientY?: number;
@@ -0,0 +1,62 @@
1
+ import { DockviewGroupPanel } from './dockviewGroupPanel';
2
+ import { IDockviewPanel } from './dockviewPanel';
3
+ import { ITabGroup } from './tabGroup';
4
+ import { IContextMenuHost, IContextMenuService } from './moduleContracts';
5
+ export declare class ContextMenuController implements IContextMenuService {
6
+ private readonly accessor;
7
+ constructor(accessor: IContextMenuHost);
8
+ /**
9
+ * A single maximize/restore toggle whose label and behaviour track the
10
+ * group's live state: it reads *Restore* + calls `exitMaximized` when the
11
+ * group is maximized, otherwise *Maximize* + `maximize`. Only grid groups
12
+ * can be maximized, so the item is disabled for floating / popout panels
13
+ * that are not already maximized.
14
+ */
15
+ private buildMaximizeItem;
16
+ /**
17
+ * A single collapse/expand toggle whose label tracks the tab group's live
18
+ * state: *Expand* when the group is already collapsed, otherwise *Collapse*.
19
+ */
20
+ private buildCollapseItem;
21
+ /**
22
+ * Whether to auto-inject the built-in Pin/Unpin item at the top of the tab
23
+ * menu. True only when the PinnedTabs module is registered, pinning is
24
+ * enabled, and the app has not opted out via `pinnedTabs.contextMenuItem:
25
+ * false` (the item is on by default). This keeps pinning reachable from the
26
+ * menu without the app having to return `'pin'` from
27
+ * `getTabContextMenuItems` itself.
28
+ */
29
+ private _shouldInjectPin;
30
+ /**
31
+ * The tab menu items: the app's own items (if any) with the built-in
32
+ * `'pin'` item prepended when {@link _shouldInjectPin} applies, so the app
33
+ * keeps full control of its list, and pinning is added without disturbing
34
+ * it. Reuses the existing `'pin'` token rendering below.
35
+ */
36
+ private _resolveTabItems;
37
+ /**
38
+ * Render a custom `component` menu item and append it to `menuEl`. Builds
39
+ * the framework renderer via the host's `createContextMenuItemComponent`
40
+ * factory and initialises it. Shared by the tab menu and the chip menu,
41
+ * which differ only in `identity`: the tab menu passes the `panel`, the chip
42
+ * menu passes the `tabGroup`. No-op when no renderer could be created (no
43
+ * factory configured, or the factory declined the component).
44
+ */
45
+ private appendComponentItem;
46
+ /**
47
+ * The element for one built-in tab item, or `undefined` for a token this
48
+ * version doesn't know (an app on a newer typings version, or plain JS):
49
+ * an unrecognised token renders nothing rather than throwing.
50
+ */
51
+ private buildBuiltInTabItem;
52
+ /**
53
+ * Append one app-supplied item. A raw `element` is used as-is, a
54
+ * `component` goes through the framework renderer, and a `label` builds the
55
+ * default row; an item carrying none of the three renders nothing. Shared
56
+ * by both menus, which differ only in `identity`.
57
+ */
58
+ private appendConfigItem;
59
+ show(panel: IDockviewPanel, group: DockviewGroupPanel, event: MouseEvent): void;
60
+ showForChip(tabGroup: ITabGroup, group: DockviewGroupPanel, event: MouseEvent): void;
61
+ }
62
+ export declare const ContextMenuModule: import("./modules").DockviewModule<IContextMenuHost>;
@@ -111,6 +111,11 @@ export interface SerializedDockview {
111
111
  export interface MovePanelEvent {
112
112
  panel: IDockviewPanel;
113
113
  from: DockviewGroupPanel;
114
+ /**
115
+ * The group the panel now belongs to. Equal to `from` when the panel kept
116
+ * its group and the group itself was relocated.
117
+ */
118
+ to: DockviewGroupPanel;
114
119
  }
115
120
  type MoveGroupOptions = {
116
121
  from: {
@@ -345,6 +350,7 @@ export declare class DockviewComponent extends BaseGrid<DockviewGroupPanel> impl
345
350
  private readonly _onWillDrop;
346
351
  readonly onWillDrop: Event<DockviewWillDropEvent>;
347
352
  private _mutationDepth;
353
+ private readonly _pendingLocationChanges;
348
354
  private _origin;
349
355
  private _originDepth;
350
356
  private readonly _onWillMutateLayout;
@@ -856,6 +862,56 @@ export declare class DockviewComponent extends BaseGrid<DockviewGroupPanel> impl
856
862
  * outermost mutation.
857
863
  */
858
864
  mutation<T>(kind: DockviewLayoutMutationKind, func: () => T): T;
865
+ /**
866
+ * `mutation()` for an operation whose work continues after the synchronous
867
+ * call returns. The transaction stays open until the returned promise
868
+ * settles, so everything the operation does - the group it adds, the panels
869
+ * it relocates - lands inside the bracket, matching the synchronous
870
+ * move / float paths.
871
+ */
872
+ private mutationAsync;
873
+ /**
874
+ * Open a transaction and return the function that closes it. Shared by the
875
+ * synchronous and asynchronous brackets; the returned function must be
876
+ * called exactly once.
877
+ *
878
+ * Both ends key off the depth counter reaching zero rather than off which
879
+ * bracket opened first. For synchronous nesting the two are the same thing
880
+ * - brackets close in the order they opened - but asynchronous transactions
881
+ * can *overlap* rather than nest (two `addPopoutGroup` calls in flight at
882
+ * once, or a restore staggering several), and there the first to open is
883
+ * not the last to close. Reporting on the opener would fire `didMutate`
884
+ * while the other transaction was still doing structural work, which is the
885
+ * very thing the async bracket exists to prevent. Overlapping transactions
886
+ * therefore report as one, tagged with the kind of the last to finish.
887
+ */
888
+ private openMutation;
889
+ /**
890
+ * Coalesce a panel's `onDidLocationChange` to the end of the enclosing
891
+ * transaction, or fire it immediately when no transaction is in flight.
892
+ *
893
+ * Relocating a panel touches its location twice: once as it is reparented
894
+ * into the destination group - which, when that group has just been created
895
+ * for a floating or popout window, has not been told where it lives yet -
896
+ * and once as the group is tagged with its final location. Reporting each
897
+ * signal as it happens therefore leaks an intermediate `grid` location the
898
+ * panel was never in, at a moment when it belongs to neither group's panel
899
+ * list and so is missing from `api.panels`.
900
+ *
901
+ * Deferring collapses those signals into a single event carrying the
902
+ * settled location. Note the signals are deliberately *not* compared
903
+ * against the panel's previous location: a panel can move between two
904
+ * floating windows without its location type changing, and this event is
905
+ * the only signal `OverlayRenderContainer` has to re-resolve the panel's
906
+ * z-index against its new host window.
907
+ */
908
+ deferLocationChange(key: object, fire: () => void): void;
909
+ /**
910
+ * Report every panel whose location moved during the transaction that has
911
+ * just closed. Each callback reads the panel's location at this point, so
912
+ * what it reports is where the panel ended up.
913
+ */
914
+ private flushLocationChanges;
859
915
  /**
860
916
  * The origin of the operation currently in progress (`'user'` by default).
861
917
  * Read inside a `mutation()` or active-panel change to learn whether the
@@ -877,6 +933,12 @@ export declare class DockviewComponent extends BaseGrid<DockviewGroupPanel> impl
877
933
  * {@link DockviewOrigin}. Callers keep their own dedupe guards.
878
934
  */
879
935
  private fireActivePanelChange;
936
+ /**
937
+ * Announce that `panel` has finished relocating. Must be called once the
938
+ * move has settled: `to` is read from the panel's current group, so an
939
+ * early call would report the source group as the destination.
940
+ */
941
+ private fireDidMovePanel;
880
942
  moveGroupOrPanel(options: MoveGroupOrPanelOptions): void;
881
943
  private _doMoveGroupOrPanel;
882
944
  private moveTabGroupToGroup;
@@ -889,6 +951,14 @@ export declare class DockviewComponent extends BaseGrid<DockviewGroupPanel> impl
889
951
  private getNextGroupId;
890
952
  createGroup(options?: GroupOptions): DockviewGroupPanel;
891
953
  private createPanel;
954
+ /**
955
+ * Sizing for a group created by a drop next to `referenceLocation`: half
956
+ * of the group the overlay was drawn over, leaving its siblings alone, so
957
+ * the panel lands in the region the overlay indicated (#1612). Gridview
958
+ * rewrites the index to 0 when a cross-axis drop wraps the reference in a
959
+ * new branch, so one value serves both paths.
960
+ */
961
+ private dropSizing;
892
962
  private createGroupAtLocation;
893
963
  /**
894
964
  * Tag a group with the location and render / drop-target containers
@@ -139,6 +139,7 @@ export declare class ShellManager implements IDisposable {
139
139
  private _rightIndex;
140
140
  private readonly _disposables;
141
141
  private readonly _viewConfigs;
142
+ private readonly _pendingSizes;
142
143
  private _currentWidth;
143
144
  private _currentHeight;
144
145
  private _gap;
@@ -163,6 +164,20 @@ export declare class ShellManager implements IDisposable {
163
164
  setEdgeGroupVisible(position: EdgeGroupPosition, visible: boolean): void;
164
165
  isEdgeGroupVisible(position: EdgeGroupPosition): boolean;
165
166
  setEdgeGroupCollapsed(position: EdgeGroupPosition, collapsed: boolean): void;
167
+ /**
168
+ * Resize the edge group at `position` along its primary axis (width for
169
+ * `left`/`right`, height for `top`/`bottom`), clamped by the group's
170
+ * constraints and the space available. Where `groupApi.setSize` lands.
171
+ *
172
+ * The size becomes the group's expanded size, so a collapsed group keeps
173
+ * its strip and takes it on expand, and it survives a `toJSON` round-trip.
174
+ */
175
+ resizeEdgeGroup(position: EdgeGroupPosition, size: number): void;
176
+ /** A resize lands only on a visible view (a hidden one is pinned to zero)
177
+ * whose splitview has extent to distribute. */
178
+ private _canResize;
179
+ private _resizeView;
180
+ private _flushPendingSizes;
166
181
  isEdgeGroupCollapsed(position: EdgeGroupPosition): boolean;
167
182
  /** The size an edge group expands to (its pre-collapse size), used to size
168
183
  * the auto-hide peek overlay. */
@@ -156,8 +156,8 @@ export declare function logMissingModule(moduleName: string, reason?: string | s
156
156
  * case: calling `undo()` having never set the option at all.
157
157
  *
158
158
  * Interaction handlers are queries in this sense too: a right-click reaching an
159
- * absent ContextMenu module means the app never asked for one, so it stays
160
- * silent (`?.`) and the browser's own menu shows. Options are where intent is
159
+ * absent module means the app never asked for that feature, so it stays silent
160
+ * (`?.`) and the browser's own behaviour applies. Options are where intent is
161
161
  * declared; see `optionsModules.ts`.
162
162
  */
163
163
  export declare function assertModule<T>(service: T | undefined, moduleName: string, context?: string): T | undefined;
@@ -5,10 +5,9 @@
5
5
  *
6
6
  * This is the "declared intent" diagnostic. It fires when the user asks for a
7
7
  * feature via options, at construction and on every `updateOptions`. It
8
- * deliberately does *not* fire on user interaction: right-clicking without the
9
- * ContextMenu module stays silent (the browser's own menu shows), because the
10
- * `?.` service-slot call sites can't tell a missing module from a feature the
11
- * app never wanted.
8
+ * deliberately does *not* fire on user interaction: an interaction reaching an
9
+ * absent module stays silent, because the `?.` service-slot call sites can't
10
+ * tell a missing module from a feature the app never wanted.
12
11
  *
13
12
  * Rules are a flat list rather than a `Record<keyof DockviewOptions, ...>`
14
13
  * because dockview's options are nested and value-gated: `overflow.mode:
@@ -2,7 +2,7 @@ import { Event, AsapEvent } from '../events';
2
2
  import { Gridview, IGridView } from './gridview';
3
3
  import { Position } from '../dnd/droptarget';
4
4
  import { IDisposable, IValueDisposable } from '../lifecycle';
5
- import { ISplitviewStyles, Orientation } from '../splitview/splitview';
5
+ import { ISplitviewStyles, Orientation, Sizing } from '../splitview/splitview';
6
6
  import { IPanel } from '../panel/types';
7
7
  import { MovementOptions2 } from '../dockview/options';
8
8
  import { Resizable } from '../resizable';
@@ -95,7 +95,7 @@ export declare abstract class BaseGrid<T extends IGridPanelView> extends Resizab
95
95
  isMaximizedGroup(panel: T): boolean;
96
96
  exitMaximizedGroup(): void;
97
97
  hasMaximizedGroup(): boolean;
98
- protected doAddGroup(group: T, location?: number[], size?: number, gridview?: Gridview): void;
98
+ protected doAddGroup(group: T, location?: number[], size?: number | Sizing, gridview?: Gridview): void;
99
99
  protected doRemoveGroup(group: T, options?: {
100
100
  skipActive?: boolean;
101
101
  skipDispose?: boolean;
@@ -59,6 +59,7 @@ export { type IDragGhostSpec } from './dnd/backend';
59
59
  export { LiveRegionModule } from './dockview/liveRegionService';
60
60
  export { AdvancedDnDModule, AdvancedDnDService, } from './dockview/advancedDnDService';
61
61
  export { TabGroupChipsModule, TabGroupChipsService, } from './dockview/tabGroupChipsService';
62
+ export { ContextMenuController, ContextMenuModule, } from './dockview/contextMenuService';
62
63
  export { FloatingGroupModule } from './dockview/floatingGroupService';
63
64
  export { EdgeGroupModule } from './dockview/edgeGroupService';
64
65
  export { createCloseButton, createPinButton } from './svg';
@@ -12,8 +12,13 @@ export declare class OverlayRenderContainer extends CompositeDisposable {
12
12
  readonly accessor: DockviewComponent;
13
13
  private readonly map;
14
14
  private _disposed;
15
+ /**
16
+ * Monotonic for the container's lifetime, never per-entry: `detatch()`
17
+ * deletes the entry, so an entry-local counter would restart and let a
18
+ * superseded closure collide with a later `attach`.
19
+ */
20
+ private _generation;
15
21
  private readonly positionCache;
16
- private readonly pendingUpdates;
17
22
  constructor(element: HTMLElement, accessor: DockviewComponent);
18
23
  updateAllPositions(): void;
19
24
  /**
@@ -24,6 +29,13 @@ export declare class OverlayRenderContainer extends CompositeDisposable {
24
29
  * the panel's visibility state. No-op if the panel isn't overlay-rendered.
25
30
  */
26
31
  repositionPanelOverlay(panelId: string, forceVisible?: boolean, clip?: DOMRect): void;
32
+ /**
33
+ * Drop the reposition frame queued for a panel, if any. A queued frame is
34
+ * bound to the reference container that was current when it was scheduled,
35
+ * so it must be discarded whenever that container stops being the one the
36
+ * overlay should track.
37
+ */
38
+ private cancelPendingUpdate;
27
39
  detatch(panel: IDockviewPanel): boolean;
28
40
  attach(options: {
29
41
  panel: IDockviewPanel;