dockview-core 6.6.0 → 7.0.2

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 (153) hide show
  1. package/README.md +8 -1
  2. package/dist/cjs/api/component.api.d.ts +42 -21
  3. package/dist/cjs/api/component.api.js +111 -20
  4. package/dist/cjs/api/dockviewGroupPanelApi.d.ts +23 -8
  5. package/dist/cjs/api/dockviewGroupPanelApi.js +23 -0
  6. package/dist/cjs/api/dockviewPanelApi.d.ts +4 -3
  7. package/dist/cjs/api/dockviewPanelApi.js +8 -0
  8. package/dist/cjs/dnd/droptarget.d.ts +8 -0
  9. package/dist/cjs/dnd/droptarget.js +28 -0
  10. package/dist/cjs/dockview/accessibilityMessages.d.ts +32 -0
  11. package/dist/cjs/dockview/accessibilityMessages.js +51 -0
  12. package/dist/cjs/dockview/allModules.d.ts +8 -0
  13. package/dist/cjs/dockview/allModules.js +25 -0
  14. package/dist/cjs/dockview/components/panel/content.d.ts +2 -0
  15. package/dist/cjs/dockview/components/panel/content.js +35 -4
  16. package/dist/cjs/dockview/components/tab/tab.js +33 -5
  17. package/dist/cjs/dockview/components/titlebar/floatingTitleBar.d.ts +35 -0
  18. package/dist/cjs/dockview/components/titlebar/floatingTitleBar.js +95 -0
  19. package/dist/cjs/dockview/components/titlebar/groupDragSource.d.ts +52 -0
  20. package/dist/cjs/dockview/components/titlebar/groupDragSource.js +218 -0
  21. package/dist/cjs/dockview/components/titlebar/tabGroupIndicator.d.ts +2 -1
  22. package/dist/cjs/dockview/components/titlebar/tabGroupIndicator.js +31 -24
  23. package/dist/cjs/dockview/components/titlebar/tabGroups.js +1 -0
  24. package/dist/cjs/dockview/components/titlebar/tabs.d.ts +12 -0
  25. package/dist/cjs/dockview/components/titlebar/tabs.js +105 -2
  26. package/dist/cjs/dockview/components/titlebar/tabsContainer.d.ts +4 -0
  27. package/dist/cjs/dockview/components/titlebar/tabsContainer.js +13 -3
  28. package/dist/cjs/dockview/components/titlebar/voidContainer.d.ts +1 -4
  29. package/dist/cjs/dockview/components/titlebar/voidContainer.js +31 -155
  30. package/dist/cjs/dockview/dockviewComponent.d.ts +299 -44
  31. package/dist/cjs/dockview/dockviewComponent.js +1787 -993
  32. package/dist/cjs/dockview/dockviewFloatingGroupPanel.d.ts +33 -2
  33. package/dist/cjs/dockview/dockviewFloatingGroupPanel.js +39 -3
  34. package/dist/cjs/dockview/dockviewGroupPanel.d.ts +0 -1
  35. package/dist/cjs/dockview/dockviewGroupPanelModel.d.ts +36 -14
  36. package/dist/cjs/dockview/dockviewGroupPanelModel.js +133 -101
  37. package/dist/cjs/dockview/dockviewPanel.d.ts +2 -2
  38. package/dist/cjs/dockview/edgeGroupService.d.ts +38 -0
  39. package/dist/cjs/dockview/edgeGroupService.js +128 -0
  40. package/dist/cjs/dockview/floatingGroupService.d.ts +37 -0
  41. package/dist/cjs/dockview/floatingGroupService.js +231 -0
  42. package/dist/cjs/dockview/headerActionsService.d.ts +32 -0
  43. package/dist/cjs/dockview/headerActionsService.js +149 -0
  44. package/dist/cjs/dockview/liveRegionService.d.ts +53 -0
  45. package/dist/cjs/dockview/liveRegionService.js +185 -0
  46. package/dist/cjs/dockview/moduleContracts.d.ts +119 -0
  47. package/dist/cjs/dockview/moduleContracts.js +2 -0
  48. package/dist/cjs/dockview/modules.d.ts +110 -0
  49. package/dist/cjs/dockview/modules.js +304 -0
  50. package/dist/cjs/dockview/options.d.ts +159 -6
  51. package/dist/cjs/dockview/options.js +8 -1
  52. package/dist/cjs/dockview/popoutWindowService.d.ts +95 -0
  53. package/dist/cjs/dockview/popoutWindowService.js +261 -0
  54. package/dist/cjs/dockview/rootDropTargetService.d.ts +35 -0
  55. package/dist/cjs/dockview/rootDropTargetService.js +87 -0
  56. package/dist/cjs/dockview/watermarkService.d.ts +30 -0
  57. package/dist/cjs/dockview/watermarkService.js +61 -0
  58. package/dist/cjs/gridview/baseComponentGridview.d.ts +1 -1
  59. package/dist/cjs/gridview/baseComponentGridview.js +3 -2
  60. package/dist/cjs/gridview/gridviewComponent.d.ts +3 -3
  61. package/dist/cjs/gridview/gridviewPanel.d.ts +1 -1
  62. package/dist/cjs/index.d.ts +11 -4
  63. package/dist/cjs/index.js +14 -1
  64. package/dist/cjs/overlay/overlay.d.ts +43 -1
  65. package/dist/cjs/overlay/overlay.js +57 -8
  66. package/dist/cjs/paneview/draggablePaneviewPanel.d.ts +2 -2
  67. package/dist/cjs/paneview/draggablePaneviewPanel.js +4 -4
  68. package/dist/cjs/paneview/paneviewComponent.d.ts +3 -3
  69. package/dist/cjs/paneview/paneviewComponent.js +5 -5
  70. package/dist/dockview-core.js +3199 -1251
  71. package/dist/dockview-core.min.js +2 -2
  72. package/dist/dockview-core.min.js.map +1 -1
  73. package/dist/dockview-core.min.noStyle.js +2 -2
  74. package/dist/dockview-core.min.noStyle.js.map +1 -1
  75. package/dist/dockview-core.noStyle.js +3198 -1250
  76. package/dist/esm/api/component.api.d.ts +42 -21
  77. package/dist/esm/api/component.api.js +63 -18
  78. package/dist/esm/api/dockviewGroupPanelApi.d.ts +23 -8
  79. package/dist/esm/api/dockviewGroupPanelApi.js +19 -0
  80. package/dist/esm/api/dockviewPanelApi.d.ts +4 -3
  81. package/dist/esm/api/dockviewPanelApi.js +7 -0
  82. package/dist/esm/dnd/droptarget.d.ts +8 -0
  83. package/dist/esm/dnd/droptarget.js +28 -0
  84. package/dist/esm/dockview/accessibilityMessages.d.ts +32 -0
  85. package/dist/esm/dockview/accessibilityMessages.js +30 -0
  86. package/dist/esm/dockview/allModules.d.ts +8 -0
  87. package/dist/esm/dockview/allModules.js +22 -0
  88. package/dist/esm/dockview/components/panel/content.d.ts +2 -0
  89. package/dist/esm/dockview/components/panel/content.js +36 -5
  90. package/dist/esm/dockview/components/tab/tab.js +33 -5
  91. package/dist/esm/dockview/components/titlebar/floatingTitleBar.d.ts +35 -0
  92. package/dist/esm/dockview/components/titlebar/floatingTitleBar.js +65 -0
  93. package/dist/esm/dockview/components/titlebar/groupDragSource.d.ts +52 -0
  94. package/dist/esm/dockview/components/titlebar/groupDragSource.js +178 -0
  95. package/dist/esm/dockview/components/titlebar/tabGroupIndicator.d.ts +2 -1
  96. package/dist/esm/dockview/components/titlebar/tabGroupIndicator.js +31 -24
  97. package/dist/esm/dockview/components/titlebar/tabGroups.js +1 -0
  98. package/dist/esm/dockview/components/titlebar/tabs.d.ts +12 -0
  99. package/dist/esm/dockview/components/titlebar/tabs.js +102 -2
  100. package/dist/esm/dockview/components/titlebar/tabsContainer.d.ts +4 -0
  101. package/dist/esm/dockview/components/titlebar/tabsContainer.js +8 -2
  102. package/dist/esm/dockview/components/titlebar/voidContainer.d.ts +1 -4
  103. package/dist/esm/dockview/components/titlebar/voidContainer.js +33 -145
  104. package/dist/esm/dockview/dockviewComponent.d.ts +299 -44
  105. package/dist/esm/dockview/dockviewComponent.js +1421 -717
  106. package/dist/esm/dockview/dockviewFloatingGroupPanel.d.ts +33 -2
  107. package/dist/esm/dockview/dockviewFloatingGroupPanel.js +35 -3
  108. package/dist/esm/dockview/dockviewGroupPanel.d.ts +0 -1
  109. package/dist/esm/dockview/dockviewGroupPanelModel.d.ts +36 -14
  110. package/dist/esm/dockview/dockviewGroupPanelModel.js +109 -93
  111. package/dist/esm/dockview/dockviewPanel.d.ts +2 -2
  112. package/dist/esm/dockview/edgeGroupService.d.ts +38 -0
  113. package/dist/esm/dockview/edgeGroupService.js +63 -0
  114. package/dist/esm/dockview/floatingGroupService.d.ts +37 -0
  115. package/dist/esm/dockview/floatingGroupService.js +150 -0
  116. package/dist/esm/dockview/headerActionsService.d.ts +32 -0
  117. package/dist/esm/dockview/headerActionsService.js +86 -0
  118. package/dist/esm/dockview/liveRegionService.d.ts +53 -0
  119. package/dist/esm/dockview/liveRegionService.js +159 -0
  120. package/dist/esm/dockview/moduleContracts.d.ts +119 -0
  121. package/dist/esm/dockview/moduleContracts.js +1 -0
  122. package/dist/esm/dockview/modules.d.ts +110 -0
  123. package/dist/esm/dockview/modules.js +170 -0
  124. package/dist/esm/dockview/options.d.ts +159 -6
  125. package/dist/esm/dockview/options.js +8 -1
  126. package/dist/esm/dockview/popoutWindowService.d.ts +95 -0
  127. package/dist/esm/dockview/popoutWindowService.js +175 -0
  128. package/dist/esm/dockview/rootDropTargetService.d.ts +35 -0
  129. package/dist/esm/dockview/rootDropTargetService.js +82 -0
  130. package/dist/esm/dockview/watermarkService.d.ts +30 -0
  131. package/dist/esm/dockview/watermarkService.js +56 -0
  132. package/dist/esm/gridview/baseComponentGridview.d.ts +1 -1
  133. package/dist/esm/gridview/baseComponentGridview.js +2 -2
  134. package/dist/esm/gridview/gridviewComponent.d.ts +3 -3
  135. package/dist/esm/gridview/gridviewPanel.d.ts +1 -1
  136. package/dist/esm/index.d.ts +11 -4
  137. package/dist/esm/index.js +4 -0
  138. package/dist/esm/overlay/overlay.d.ts +43 -1
  139. package/dist/esm/overlay/overlay.js +53 -8
  140. package/dist/esm/paneview/draggablePaneviewPanel.d.ts +2 -2
  141. package/dist/esm/paneview/draggablePaneviewPanel.js +4 -4
  142. package/dist/esm/paneview/paneviewComponent.d.ts +3 -3
  143. package/dist/esm/paneview/paneviewComponent.js +5 -5
  144. package/dist/package/main.cjs.js +3234 -1286
  145. package/dist/package/main.cjs.min.js +2 -2
  146. package/dist/package/main.esm.min.mjs +2 -2
  147. package/dist/package/main.esm.mjs +3189 -1252
  148. package/dist/styles/dockview.css +275 -13
  149. package/package.json +10 -1
  150. package/dist/cjs/dockview/contextMenu.d.ts +0 -10
  151. package/dist/cjs/dockview/contextMenu.js +0 -313
  152. package/dist/esm/dockview/contextMenu.d.ts +0 -10
  153. package/dist/esm/dockview/contextMenu.js +0 -228
@@ -0,0 +1,63 @@
1
+ import { defineModule } from './modules';
2
+ export class EdgeGroupService {
3
+ constructor() {
4
+ this._edgeGroups = new Map();
5
+ this._edgeGroupDisposables = new Map();
6
+ }
7
+ // No constructor needed — the host is currently unused. The
8
+ // IEdgeGroupServiceHost slot stays for symmetry with the other modules
9
+ // and to leave room for future host callbacks.
10
+ add(position, group, autoCollapseDisposable) {
11
+ this._edgeGroups.set(position, group);
12
+ this._edgeGroupDisposables.set(position, autoCollapseDisposable);
13
+ }
14
+ remove(position) {
15
+ var _a;
16
+ (_a = this._edgeGroupDisposables.get(position)) === null || _a === void 0 ? void 0 : _a.dispose();
17
+ this._edgeGroupDisposables.delete(position);
18
+ this._edgeGroups.delete(position);
19
+ }
20
+ get(position) {
21
+ return this._edgeGroups.get(position);
22
+ }
23
+ has(position) {
24
+ return this._edgeGroups.has(position);
25
+ }
26
+ hasAny() {
27
+ return this._edgeGroups.size > 0;
28
+ }
29
+ entries() {
30
+ return this._edgeGroups.entries();
31
+ }
32
+ includes(group) {
33
+ for (const edgeGroup of this._edgeGroups.values()) {
34
+ if (edgeGroup === group) {
35
+ return true;
36
+ }
37
+ }
38
+ return false;
39
+ }
40
+ findPositionOf(group) {
41
+ for (const [position, edgeGroup] of this._edgeGroups) {
42
+ if (edgeGroup === group) {
43
+ return position;
44
+ }
45
+ }
46
+ return undefined;
47
+ }
48
+ disposeAll() {
49
+ for (const disposable of this._edgeGroupDisposables.values()) {
50
+ disposable.dispose();
51
+ }
52
+ this._edgeGroupDisposables.clear();
53
+ this._edgeGroups.clear();
54
+ }
55
+ dispose() {
56
+ this.disposeAll();
57
+ }
58
+ }
59
+ export const EdgeGroupModule = defineModule({
60
+ name: 'EdgeGroup',
61
+ serviceKey: 'edgeGroupService',
62
+ create: () => new EdgeGroupService(),
63
+ });
@@ -0,0 +1,37 @@
1
+ import { IDisposable } from '../lifecycle';
2
+ import { Gridview } from '../gridview/gridview';
3
+ import { Overlay } from '../overlay/overlay';
4
+ import { DockviewFloatingGroupPanel } from './dockviewFloatingGroupPanel';
5
+ import { DockviewGroupPanel } from './dockviewGroupPanel';
6
+ import { DockviewOptions } from './options';
7
+ import { SerializedFloatingGroup } from './dockviewComponent';
8
+ /**
9
+ * Narrow callback surface the FloatingGroupService needs from its host
10
+ * component. Keeps the service decoupled from DockviewComponent.
11
+ */
12
+ export interface IFloatingGroupHost {
13
+ fireLayoutChange(): void;
14
+ }
15
+ export interface IFloatingGroupService extends IDisposable {
16
+ readonly floatingGroups: readonly DockviewFloatingGroupPanel[];
17
+ add(group: DockviewGroupPanel, overlay: Overlay, gridview: Gridview): DockviewFloatingGroupPanel;
18
+ findByGroup(group: DockviewGroupPanel): DockviewFloatingGroupPanel | undefined;
19
+ serialize(): SerializedFloatingGroup[];
20
+ constrainBounds(): void;
21
+ updateBounds(options: Partial<DockviewOptions>): void;
22
+ disposeAll(): void;
23
+ }
24
+ export declare class FloatingGroupService implements IFloatingGroupService {
25
+ private readonly _host;
26
+ private readonly _floatingGroups;
27
+ get floatingGroups(): readonly DockviewFloatingGroupPanel[];
28
+ constructor(host: IFloatingGroupHost);
29
+ add(group: DockviewGroupPanel, overlay: Overlay, gridview: Gridview): DockviewFloatingGroupPanel;
30
+ findByGroup(group: DockviewGroupPanel): DockviewFloatingGroupPanel | undefined;
31
+ serialize(): SerializedFloatingGroup[];
32
+ constrainBounds(): void;
33
+ updateBounds(options: Partial<DockviewOptions>): void;
34
+ disposeAll(): void;
35
+ dispose(): void;
36
+ }
37
+ export declare const FloatingGroupModule: import("./modules").DockviewModule<IFloatingGroupHost>;
@@ -0,0 +1,150 @@
1
+ import { CompositeDisposable } from '../lifecycle';
2
+ import { remove } from '../array';
3
+ import { watchElementResize } from '../dom';
4
+ import { DEFAULT_FLOATING_GROUP_OVERFLOW_SIZE } from '../constants';
5
+ import { DockviewFloatingGroupPanel } from './dockviewFloatingGroupPanel';
6
+ import { defineModule } from './modules';
7
+ export class FloatingGroupService {
8
+ get floatingGroups() {
9
+ return this._floatingGroups;
10
+ }
11
+ constructor(host) {
12
+ this._floatingGroups = [];
13
+ this._host = host;
14
+ }
15
+ add(group, overlay, gridview) {
16
+ const floatingGroupPanel = new DockviewFloatingGroupPanel(group, overlay, gridview);
17
+ const disposable = new CompositeDisposable(group.api.onDidActiveChange((event) => {
18
+ if (event.isActive) {
19
+ overlay.bringToFront();
20
+ }
21
+ }), (() => {
22
+ // The floating window's nested gridview fills the overlay
23
+ // beneath the (optional) title bar; size it from its own
24
+ // measured box so it follows the overlay as the user drags
25
+ // / resizes the window.
26
+ let lastWidth = -1;
27
+ let lastHeight = -1;
28
+ return watchElementResize(gridview.element, (entry) => {
29
+ const width = Math.round(entry.contentRect.width);
30
+ const height = Math.round(entry.contentRect.height);
31
+ if (width === lastWidth && height === lastHeight) {
32
+ return;
33
+ }
34
+ lastWidth = width;
35
+ lastHeight = height;
36
+ gridview.layout(width, height);
37
+ });
38
+ })());
39
+ // Floating windows are non-modal dialogs (role set in Overlay). Give
40
+ // the dialog an accessible name from the representative group's active
41
+ // panel, refreshed as the active panel changes. An untitled panel
42
+ // leaves the dialog unnamed rather than hard-coding a label string.
43
+ const updateDialogLabel = () => {
44
+ var _a;
45
+ const title = (_a = group.activePanel) === null || _a === void 0 ? void 0 : _a.title;
46
+ if (title) {
47
+ overlay.element.setAttribute('aria-label', title);
48
+ }
49
+ else {
50
+ overlay.element.removeAttribute('aria-label');
51
+ }
52
+ };
53
+ updateDialogLabel();
54
+ floatingGroupPanel.addDisposables(group.api.onDidActivePanelChange(() => updateDialogLabel()), overlay.onDidChange(() => {
55
+ gridview.layout(gridview.width, gridview.height);
56
+ }), overlay.onDidChangeEnd(() => {
57
+ this._host.fireLayoutChange();
58
+ }), group.onDidChange((event) => {
59
+ // `event.height` is the group's requested *content* height.
60
+ // When a dedicated title bar is present the overlay's outer
61
+ // box is taller by the header, so add it back to preserve the
62
+ // requested content size.
63
+ overlay.setBounds({
64
+ height: typeof (event === null || event === void 0 ? void 0 : event.height) === 'number'
65
+ ? event.height + overlay.headerHeight
66
+ : event === null || event === void 0 ? void 0 : event.height,
67
+ width: event === null || event === void 0 ? void 0 : event.width,
68
+ });
69
+ }), {
70
+ dispose: () => {
71
+ disposable.dispose();
72
+ remove(this._floatingGroups, floatingGroupPanel);
73
+ group.model.location = { type: 'grid' };
74
+ },
75
+ });
76
+ this._floatingGroups.push(floatingGroupPanel);
77
+ return floatingGroupPanel;
78
+ }
79
+ findByGroup(group) {
80
+ // A floating window may host several groups in a nested gridview, so
81
+ // match by membership (DOM containment) rather than only the anchor
82
+ // group. `floating.group === group` covers the brief window before the
83
+ // anchor's element is attached to the gridview.
84
+ return this._floatingGroups.find((floating) => floating.group === group ||
85
+ floating.gridview.element.contains(group.element));
86
+ }
87
+ serialize() {
88
+ return this._floatingGroups.map((floating) => {
89
+ const grid = floating.gridview.serialize();
90
+ const position = floating.overlay.toJSON();
91
+ const root = grid.root;
92
+ // A single-group window keeps the legacy `data` shape so layouts
93
+ // round-trip byte-stably and older readers keep working; only
94
+ // genuine multi-group windows emit the nested `grid` form.
95
+ if (root.type === 'branch' &&
96
+ root.data.length === 1 &&
97
+ root.data[0].type === 'leaf') {
98
+ return {
99
+ data: root.data[0].data,
100
+ position,
101
+ };
102
+ }
103
+ return { grid, position };
104
+ });
105
+ }
106
+ constrainBounds() {
107
+ for (const floating of this._floatingGroups) {
108
+ floating.overlay.setBounds();
109
+ }
110
+ }
111
+ updateBounds(options) {
112
+ var _a, _b;
113
+ if (!('floatingGroupBounds' in options)) {
114
+ return;
115
+ }
116
+ for (const group of this._floatingGroups) {
117
+ switch (options.floatingGroupBounds) {
118
+ case 'boundedWithinViewport':
119
+ group.overlay.minimumInViewportHeight = undefined;
120
+ group.overlay.minimumInViewportWidth = undefined;
121
+ break;
122
+ case undefined:
123
+ group.overlay.minimumInViewportHeight =
124
+ DEFAULT_FLOATING_GROUP_OVERFLOW_SIZE;
125
+ group.overlay.minimumInViewportWidth =
126
+ DEFAULT_FLOATING_GROUP_OVERFLOW_SIZE;
127
+ break;
128
+ default:
129
+ group.overlay.minimumInViewportHeight =
130
+ (_a = options.floatingGroupBounds) === null || _a === void 0 ? void 0 : _a.minimumHeightWithinViewport;
131
+ group.overlay.minimumInViewportWidth =
132
+ (_b = options.floatingGroupBounds) === null || _b === void 0 ? void 0 : _b.minimumWidthWithinViewport;
133
+ }
134
+ group.overlay.setBounds();
135
+ }
136
+ }
137
+ disposeAll() {
138
+ for (const floating of [...this._floatingGroups]) {
139
+ floating.dispose();
140
+ }
141
+ }
142
+ dispose() {
143
+ this.disposeAll();
144
+ }
145
+ }
146
+ export const FloatingGroupModule = defineModule({
147
+ name: 'FloatingGroup',
148
+ serviceKey: 'floatingGroupService',
149
+ create: (host) => new FloatingGroupService(host),
150
+ });
@@ -0,0 +1,32 @@
1
+ import { IDisposable } from '../lifecycle';
2
+ import { Event } from '../events';
3
+ import { DockviewComponentOptions } from './options';
4
+ import { DockviewGroupPanel } from './dockviewGroupPanel';
5
+ import { DockviewApi } from '../api/component.api';
6
+ export interface IHeaderActionsHost {
7
+ readonly api: DockviewApi;
8
+ readonly options: DockviewComponentOptions;
9
+ readonly groups: DockviewGroupPanel[];
10
+ readonly onDidAddGroup: Event<DockviewGroupPanel>;
11
+ readonly onDidRemoveGroup: Event<DockviewGroupPanel>;
12
+ }
13
+ export interface IHeaderActionsService extends IDisposable {
14
+ /** Re-mount the three header action slots on a single group. */
15
+ refresh(group: DockviewGroupPanel): void;
16
+ /** Re-mount on every group; used when one of the three options changes. */
17
+ refreshAll(): void;
18
+ /** Tear down per-group renderer state. */
19
+ disposeGroup(group: DockviewGroupPanel): void;
20
+ }
21
+ export declare class HeaderActionsService implements IHeaderActionsService {
22
+ private readonly _host;
23
+ private readonly _perGroup;
24
+ constructor(host: IHeaderActionsHost);
25
+ refresh(group: DockviewGroupPanel): void;
26
+ refreshAll(): void;
27
+ disposeGroup(group: DockviewGroupPanel): void;
28
+ dispose(): void;
29
+ private _ensureState;
30
+ private _refreshSlot;
31
+ }
32
+ export declare const HeaderActionsModule: import("./modules").DockviewModule<IHeaderActionsHost>;
@@ -0,0 +1,86 @@
1
+ import { CompositeDisposable, MutableDisposable, } from '../lifecycle';
2
+ import { defineModule } from './modules';
3
+ const SLOT_OPTION_KEY = {
4
+ left: 'createLeftHeaderActionComponent',
5
+ right: 'createRightHeaderActionComponent',
6
+ prefix: 'createPrefixHeaderActionComponent',
7
+ };
8
+ export class HeaderActionsService {
9
+ constructor(host) {
10
+ this._perGroup = new Map();
11
+ this._host = host;
12
+ }
13
+ refresh(group) {
14
+ // The headerPosition setter on DockviewGroupPanelModel fires inside
15
+ // the model's constructor — before the parent DockviewGroupPanel has
16
+ // assigned its `_model` field, and in tests where the parent panel
17
+ // may be null. Skip; DockviewGroupPanel.initialize() will refresh
18
+ // once construction completes for real groups.
19
+ if (!(group === null || group === void 0 ? void 0 : group.model)) {
20
+ return;
21
+ }
22
+ const state = this._ensureState(group);
23
+ this._refreshSlot('left', group, state.left);
24
+ this._refreshSlot('right', group, state.right);
25
+ this._refreshSlot('prefix', group, state.prefix);
26
+ }
27
+ refreshAll() {
28
+ for (const group of this._host.groups) {
29
+ this.refresh(group);
30
+ }
31
+ }
32
+ disposeGroup(group) {
33
+ const state = this._perGroup.get(group);
34
+ if (!state) {
35
+ return;
36
+ }
37
+ state.left.dispose();
38
+ state.right.dispose();
39
+ state.prefix.dispose();
40
+ this._perGroup.delete(group);
41
+ }
42
+ dispose() {
43
+ for (const group of [...this._perGroup.keys()]) {
44
+ this.disposeGroup(group);
45
+ }
46
+ }
47
+ _ensureState(group) {
48
+ let state = this._perGroup.get(group);
49
+ if (!state) {
50
+ state = {
51
+ left: new MutableDisposable(),
52
+ right: new MutableDisposable(),
53
+ prefix: new MutableDisposable(),
54
+ };
55
+ this._perGroup.set(group, state);
56
+ }
57
+ return state;
58
+ }
59
+ _refreshSlot(slot, group, disposable) {
60
+ const factory = this._host.options[SLOT_OPTION_KEY[slot]];
61
+ if (factory) {
62
+ const renderer = factory(group);
63
+ disposable.value = renderer;
64
+ renderer.init({
65
+ containerApi: this._host.api,
66
+ api: group.api,
67
+ group,
68
+ });
69
+ group.model.attachHeaderAction(slot, renderer.element);
70
+ }
71
+ else {
72
+ disposable.dispose();
73
+ group.model.attachHeaderAction(slot, undefined);
74
+ }
75
+ }
76
+ }
77
+ export const HeaderActionsModule = defineModule({
78
+ name: 'HeaderActions',
79
+ serviceKey: 'headerActionsService',
80
+ create: (host) => new HeaderActionsService(host),
81
+ init: (host, service) => {
82
+ return new CompositeDisposable(host.onDidRemoveGroup((group) => {
83
+ service.disposeGroup(group);
84
+ }));
85
+ },
86
+ });
@@ -0,0 +1,53 @@
1
+ import { CompositeDisposable, IDisposable } from '../lifecycle';
2
+ import { Event } from '../events';
3
+ import { IDockviewPanel } from './dockviewPanel';
4
+ import { DockviewGroupPanel } from './dockviewGroupPanel';
5
+ import { DockviewLayoutMutationEvent, DockviewMaximizedGroupChangeEvent } from './dockviewComponent';
6
+ import { DockviewComponentOptions } from './options';
7
+ /**
8
+ * The narrow surface the {@link LiveRegionService} needs from the host
9
+ * (the `DockviewComponent`) — somewhere to mount the region and the layout
10
+ * events to narrate. `onWill/onDidMutateLayout` are used to suppress the
11
+ * bulk-load / clear burst (one transaction, not N panel announcements).
12
+ */
13
+ export interface ILiveRegionHost {
14
+ readonly element: HTMLElement;
15
+ readonly options: DockviewComponentOptions;
16
+ readonly onDidAddPanel: Event<IDockviewPanel>;
17
+ readonly onDidRemovePanel: Event<IDockviewPanel>;
18
+ readonly onWillMutateLayout: Event<DockviewLayoutMutationEvent>;
19
+ readonly onDidMutateLayout: Event<DockviewLayoutMutationEvent>;
20
+ readonly onDidMaximizedGroupChange: Event<DockviewMaximizedGroupChangeEvent>;
21
+ readonly onDidAddGroup: Event<DockviewGroupPanel>;
22
+ readonly onDidRemoveGroup: Event<DockviewGroupPanel>;
23
+ }
24
+ export interface ILiveRegionService extends IDisposable {
25
+ /**
26
+ * Announce a message to assistive technology via the live region. The
27
+ * shared sink — the accessibility module writes keyboard-docking
28
+ * narration here too, so all announcements use one region.
29
+ */
30
+ announce(message: string, politeness?: 'polite' | 'assertive'): void;
31
+ }
32
+ /**
33
+ * Narrates layout state changes to screen readers via visually-hidden
34
+ * `aria-live` regions. Free / core (WCAG 4.1.3). Announces panel open/close +
35
+ * the shared `announce()` sink (the accessibility module narrates docking here too).
36
+ * Two regions: a **polite** one for routine status and an **assertive** one
37
+ * for errors/cancellations. The bulk load/clear burst is suppressed via the
38
+ * mutation-transaction events, and an app can take over delivery entirely with
39
+ * the `announcer` option.
40
+ */
41
+ export declare class LiveRegionService extends CompositeDisposable implements ILiveRegionService {
42
+ private readonly _host;
43
+ private readonly _polite;
44
+ private readonly _assertive;
45
+ private _suppressDepth;
46
+ private readonly _locationSubs;
47
+ constructor(host: ILiveRegionHost);
48
+ private _trackLocation;
49
+ announce(message: string, politeness?: 'polite' | 'assertive'): void;
50
+ private _announce;
51
+ private _defaultMessage;
52
+ }
53
+ export declare const LiveRegionModule: import("./modules").DockviewModule<ILiveRegionHost>;
@@ -0,0 +1,159 @@
1
+ import { CompositeDisposable } from '../lifecycle';
2
+ import { resolveMessages } from './accessibilityMessages';
3
+ import { defineModule } from './modules';
4
+ /** Bulk transactions whose per-panel events should not each be announced. */
5
+ const isBulk = (kind) => kind === 'load' || kind === 'clear';
6
+ function createLiveRegion(politeness) {
7
+ const el = document.createElement('div');
8
+ el.className =
9
+ politeness === 'assertive'
10
+ ? 'dv-live-region-assertive'
11
+ : 'dv-live-region';
12
+ // assertive interrupts the SR (errors / cancellations); polite waits for a
13
+ // pause (routine status). `alert` implies assertive, `status` implies polite.
14
+ el.setAttribute('role', politeness === 'assertive' ? 'alert' : 'status');
15
+ el.setAttribute('aria-live', politeness);
16
+ el.setAttribute('aria-atomic', 'true');
17
+ // Visually hidden but kept in the accessibility tree (never display:none /
18
+ // visibility:hidden, which would drop it from AT). Standard clip pattern.
19
+ Object.assign(el.style, {
20
+ position: 'absolute',
21
+ width: '1px',
22
+ height: '1px',
23
+ margin: '-1px',
24
+ padding: '0',
25
+ overflow: 'hidden',
26
+ clip: 'rect(0 0 0 0)',
27
+ clipPath: 'inset(50%)',
28
+ whiteSpace: 'nowrap',
29
+ border: '0',
30
+ });
31
+ return el;
32
+ }
33
+ /**
34
+ * Narrates layout state changes to screen readers via visually-hidden
35
+ * `aria-live` regions. Free / core (WCAG 4.1.3). Announces panel open/close +
36
+ * the shared `announce()` sink (the accessibility module narrates docking here too).
37
+ * Two regions: a **polite** one for routine status and an **assertive** one
38
+ * for errors/cancellations. The bulk load/clear burst is suppressed via the
39
+ * mutation-transaction events, and an app can take over delivery entirely with
40
+ * the `announcer` option.
41
+ */
42
+ export class LiveRegionService extends CompositeDisposable {
43
+ constructor(host) {
44
+ super();
45
+ this._suppressDepth = 0;
46
+ this._locationSubs = new Map();
47
+ this._host = host;
48
+ this._polite = createLiveRegion('polite');
49
+ this._assertive = createLiveRegion('assertive');
50
+ host.element.appendChild(this._polite);
51
+ host.element.appendChild(this._assertive);
52
+ this.addDisposables({ dispose: () => this._polite.remove() }, { dispose: () => this._assertive.remove() }, host.onDidAddPanel((panel) => this._announce(panel, 'open')), host.onDidRemovePanel((panel) => this._announce(panel, 'close')),
53
+ // Bracket bulk transactions so a fromJSON / clear doesn't announce
54
+ // every nested add/remove.
55
+ host.onWillMutateLayout((e) => {
56
+ if (isBulk(e.kind)) {
57
+ this._suppressDepth++;
58
+ }
59
+ }), host.onDidMutateLayout((e) => {
60
+ if (isBulk(e.kind)) {
61
+ this._suppressDepth = Math.max(0, this._suppressDepth - 1);
62
+ }
63
+ }), host.onDidMaximizedGroupChange((e) => {
64
+ const panel = e.group.activePanel;
65
+ if (panel) {
66
+ this._announce(panel, e.isMaximized ? 'maximize' : 'restore');
67
+ }
68
+ }),
69
+ // Narrate a group floating / docking back / popping out. A group is
70
+ // born in the grid then transitions, so track each group's previous
71
+ // location and ignore the no-op initial `-> grid`.
72
+ host.onDidAddGroup((group) => this._trackLocation(group)), host.onDidRemoveGroup((group) => {
73
+ var _a;
74
+ (_a = this._locationSubs.get(group.id)) === null || _a === void 0 ? void 0 : _a.dispose();
75
+ this._locationSubs.delete(group.id);
76
+ }), {
77
+ dispose: () => {
78
+ this._locationSubs.forEach((sub) => sub.dispose());
79
+ this._locationSubs.clear();
80
+ },
81
+ });
82
+ }
83
+ _trackLocation(group) {
84
+ let prev = group.api.location.type;
85
+ const sub = group.api.onDidLocationChange((e) => {
86
+ const next = e.location.type;
87
+ if (next === prev) {
88
+ return;
89
+ }
90
+ prev = next;
91
+ const panel = group.activePanel;
92
+ if (!panel) {
93
+ return;
94
+ }
95
+ const kind = next === 'floating'
96
+ ? 'float'
97
+ : next === 'popout'
98
+ ? 'popout'
99
+ : 'dock';
100
+ this._announce(panel, kind);
101
+ });
102
+ this._locationSubs.set(group.id, sub);
103
+ }
104
+ announce(message, politeness = 'polite') {
105
+ // Opt-out (read live so `updateOptions({ announcements })` applies).
106
+ if (this._host.options.announcements === false ||
107
+ this._suppressDepth > 0 ||
108
+ !message) {
109
+ return;
110
+ }
111
+ // Apps can route announcements into their own SR system instead of the
112
+ // built-in regions (e.g. a shared app-wide live region).
113
+ const announcer = this._host.options.announcer;
114
+ if (announcer) {
115
+ announcer({ message, politeness });
116
+ return;
117
+ }
118
+ // Clearing first forces SRs to re-announce an identical message.
119
+ const region = politeness === 'assertive' ? this._assertive : this._polite;
120
+ region.textContent = '';
121
+ region.textContent = message;
122
+ }
123
+ _announce(panel, kind) {
124
+ var _a, _b;
125
+ // The app may localise/override the message, suppress it (null / ''),
126
+ // or fall through to the default (undefined).
127
+ const custom = (_b = (_a = this._host.options).getAnnouncement) === null || _b === void 0 ? void 0 : _b.call(_a, { kind, panel });
128
+ if (custom === null || custom === '') {
129
+ return;
130
+ }
131
+ this.announce(custom !== null && custom !== void 0 ? custom : this._defaultMessage(panel, kind));
132
+ }
133
+ _defaultMessage(panel, kind) {
134
+ var _a;
135
+ const m = resolveMessages(this._host.options.messages);
136
+ const name = (_a = panel.title) !== null && _a !== void 0 ? _a : panel.id;
137
+ switch (kind) {
138
+ case 'open':
139
+ return m.panelOpened(name);
140
+ case 'close':
141
+ return m.panelClosed(name);
142
+ case 'maximize':
143
+ return m.groupMaximized(name);
144
+ case 'restore':
145
+ return m.groupRestored(name);
146
+ case 'float':
147
+ return m.groupFloated(name);
148
+ case 'dock':
149
+ return m.groupDocked(name);
150
+ case 'popout':
151
+ return m.groupPoppedOut(name);
152
+ }
153
+ }
154
+ }
155
+ export const LiveRegionModule = defineModule({
156
+ name: 'LiveRegion',
157
+ serviceKey: 'liveRegionService',
158
+ create: (host) => new LiveRegionService(host),
159
+ });