dock-spawn-ts 3.19.0 → 3.21.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.
@@ -1,6 +1,7 @@
1
- import { SplitterBar } from "./SplitterBar.js";
2
- import { Utils } from "./Utils.js";
3
- import { IDockContainer } from "./interfaces/IDockContainer.js";
1
+ import { SplitterBar } from "./SplitterBar.js";
2
+ import { Utils } from "./Utils.js";
3
+ import { ContainerType } from "./ContainerType.js";
4
+ import { IDockContainer } from "./interfaces/IDockContainer.js";
4
5
 
5
6
  /**
6
7
  * A splitter panel manages the child containers inside it with splitter bars.
@@ -8,9 +9,11 @@ import { IDockContainer } from "./interfaces/IDockContainer.js";
8
9
  */
9
10
  export class SplitterPanel {
10
11
  panelElement: HTMLDivElement;
11
- spiltterBars: SplitterBar[];
12
- stackedVertical: boolean;
13
- childContainers: IDockContainer[];
12
+ spiltterBars: SplitterBar[];
13
+ stackedVertical: boolean;
14
+ childContainers: IDockContainer[];
15
+ private preferredChildSizes = new WeakMap<IDockContainer, number>();
16
+ private preserveNonElasticSizes = false;
14
17
 
15
18
  constructor(childContainers: IDockContainer[], stackedVertical: boolean) {
16
19
  this.childContainers = childContainers;
@@ -45,10 +48,15 @@ export class SplitterPanel {
45
48
 
46
49
  performLayout(children: IDockContainer[], relayoutEvenIfEqual: boolean) {
47
50
  let containersEqual = Utils.arrayEqual(this.childContainers, children);
48
- if (!containersEqual || relayoutEvenIfEqual) {
49
- this.childContainers.forEach((container) => {
50
- if (!children.some((item) => item == container)) {
51
- if (container.containerElement) {
51
+ if (!containersEqual || relayoutEvenIfEqual) {
52
+ if (!relayoutEvenIfEqual) {
53
+ this.preferredChildSizes = new WeakMap<IDockContainer, number>();
54
+ this.preserveNonElasticSizes = false;
55
+ }
56
+
57
+ this.childContainers.forEach((container) => {
58
+ if (!children.some((item) => item == container)) {
59
+ if (container.containerElement) {
52
60
  container.containerElement.classList.remove('splitter-container-vertical');
53
61
  container.containerElement.classList.remove('splitter-container-horizontal');
54
62
  Utils.removeNode(container.containerElement);
@@ -123,12 +131,14 @@ export class SplitterPanel {
123
131
  else
124
132
  size = newContainerSize;
125
133
 
126
- if (this.stackedVertical)
127
- child.resize(child.width, Math.floor(size));
128
- else
129
- child.resize(Math.floor(size), child.height);
130
- }
131
- }
134
+ if (this.stackedVertical)
135
+ child.resize(child.width, Math.floor(size));
136
+ else
137
+ child.resize(Math.floor(size), child.height);
138
+ this.preferredChildSizes.set(child, Math.floor(size));
139
+ }
140
+ this.preserveNonElasticSizes = this.hasElasticChild();
141
+ }
132
142
 
133
143
  getRatios(): number[] {
134
144
  let barSize = this.stackedVertical ? this.spiltterBars[0].barElement.clientHeight : this.spiltterBars[0].barElement.clientWidth;
@@ -153,80 +163,147 @@ export class SplitterPanel {
153
163
  // Fix rounding error on last child so panels fill the available space exactly
154
164
  if (i === this.childContainers.length - 1)
155
165
  size += splitPanelSize - updatedTotalSize;
156
- if (this.stackedVertical)
157
- child.resize(child.width, size);
158
- else
159
- child.resize(size, child.height);
160
- }
161
- }
162
-
163
- resize(width: number, height: number) {
164
- if (this.childContainers.length <= 1)
165
- return;
166
-
167
- this.panelElement.style.width = width + 'px';
168
- this.panelElement.style.height = height + 'px';
169
-
170
- let i;
171
-
172
- // Adjust the fixed dimension that is common to all (i.e. width, if stacked vertical; height, if stacked horizontally)
173
- for (i = 0; i < this.childContainers.length; i++) {
174
- let childContainer = this.childContainers[i];
175
- if (this.stackedVertical)
176
- childContainer.resize(width, !childContainer.height ? height : childContainer.height);
177
- else
178
- childContainer.resize(!childContainer.width ? width : childContainer.width, height);
179
-
180
- if (i < this.spiltterBars.length) {
181
- let splitBar = this.spiltterBars[i];
182
- if (this.stackedVertical)
183
- splitBar.barElement.style.width = width + 'px';
184
- else
185
- splitBar.barElement.style.height = height + 'px';
186
- }
187
- }
188
-
189
- // Adjust the varying dimension
190
- let totalChildPanelSize = 0;
191
- // Find out how much space existing child containers take up (excluding the splitter bars)
192
- this.childContainers.forEach((container) => {
193
- let size = this.stackedVertical ?
194
- container.height :
195
- container.width;
196
- totalChildPanelSize += size;
197
- });
198
-
199
- // Get the thickness of the bar
200
- let barSize = this.stackedVertical ? this.spiltterBars[0].barElement.clientHeight : this.spiltterBars[0].barElement.clientWidth;
201
-
202
- // Find out how much space existing child containers will take after being resized (excluding the splitter bars)
203
- let targetTotalChildPanelSize = this.stackedVertical ? height : width;
204
- targetTotalChildPanelSize -= barSize * this.spiltterBars.length;
205
-
206
- // Get the scale multiplier
207
- totalChildPanelSize = Math.max(totalChildPanelSize, 1);
208
- let scaleMultiplier = targetTotalChildPanelSize / totalChildPanelSize;
166
+ if (this.stackedVertical)
167
+ child.resize(child.width, size);
168
+ else
169
+ child.resize(size, child.height);
170
+ this.preferredChildSizes.set(child, size);
171
+ }
172
+ this.preserveNonElasticSizes = this.hasElasticChild();
173
+ }
209
174
 
210
-
211
- // Update the size with this multiplier
212
- let updatedTotalChildPanelSize = 0;
213
- for (i = 0; i < this.childContainers.length; i++) {
214
- let child = this.childContainers[i];
215
- if (child.containerElement.style.display == 'none')
216
- child.containerElement.style.display = 'block';
217
- let original = this.stackedVertical ? child.containerElement.clientHeight : child.containerElement.clientWidth;
218
- let newSize = Math.floor(original * scaleMultiplier);
219
- updatedTotalChildPanelSize += newSize;
220
-
221
- // If this is the last node, add any extra pixels to fix the rounding off errors and match the requested size
222
- if (i === this.childContainers.length - 1)
223
- newSize += targetTotalChildPanelSize - updatedTotalChildPanelSize;
224
-
225
- // Set the size of the panel
226
- if (this.stackedVertical)
227
- child.resize(child.width, newSize);
228
- else
229
- child.resize(newSize, child.height);
230
- }
231
- }
232
- }
175
+ resize(width: number, height: number) {
176
+ if (this.childContainers.length <= 1)
177
+ return;
178
+
179
+ this.panelElement.style.width = width + 'px';
180
+ this.panelElement.style.height = height + 'px';
181
+
182
+ for (let i = 0; i < this.childContainers.length; i++) {
183
+ if (i < this.spiltterBars.length) {
184
+ let splitBar = this.spiltterBars[i];
185
+ if (this.stackedVertical)
186
+ splitBar.barElement.style.width = width + 'px';
187
+ else
188
+ splitBar.barElement.style.height = height + 'px';
189
+ }
190
+ }
191
+
192
+ let barSize = this.stackedVertical ? this.spiltterBars[0].barElement.clientHeight : this.spiltterBars[0].barElement.clientWidth;
193
+ let targetTotalChildPanelSize = this.stackedVertical ? height : width;
194
+ targetTotalChildPanelSize -= barSize * this.spiltterBars.length;
195
+
196
+ if (!this.preserveNonElasticSizes || !this.hasElasticChild()) {
197
+ this.resizeProportionally(width, height, targetTotalChildPanelSize);
198
+ return;
199
+ }
200
+
201
+ let resizeIndex = this.getElasticChildIndex();
202
+ let childSizes = this.childContainers.map((container, index) => {
203
+ let currentSize = this.getChildSize(container);
204
+ if (index === resizeIndex)
205
+ return currentSize;
206
+ let preferredSize = this.preferredChildSizes.get(container);
207
+ if (preferredSize === undefined || currentSize > preferredSize)
208
+ preferredSize = currentSize;
209
+ this.preferredChildSizes.set(container, preferredSize);
210
+ return preferredSize;
211
+ });
212
+ let totalChildPanelSize = childSizes.reduce((sum, size) => sum + size, 0);
213
+ if (totalChildPanelSize <= 0) {
214
+ let size = targetTotalChildPanelSize / this.childContainers.length;
215
+ childSizes = this.childContainers.map(() => size);
216
+ totalChildPanelSize = targetTotalChildPanelSize;
217
+ }
218
+
219
+ let sizeDelta = targetTotalChildPanelSize - totalChildPanelSize;
220
+ childSizes[resizeIndex] += sizeDelta;
221
+ if (childSizes[resizeIndex] < 0) {
222
+ let deficit = -childSizes[resizeIndex];
223
+ childSizes[resizeIndex] = 0;
224
+ for (let i = this.childContainers.length - 1; i >= 0 && deficit > 0; i--) {
225
+ if (i === resizeIndex)
226
+ continue;
227
+ let reduction = Math.min(childSizes[i], deficit);
228
+ childSizes[i] -= reduction;
229
+ deficit -= reduction;
230
+ }
231
+ }
232
+
233
+ childSizes = childSizes.map((size) => Math.floor(size));
234
+ childSizes[resizeIndex] += targetTotalChildPanelSize - childSizes.reduce((sum, size) => sum + size, 0);
235
+
236
+ for (let i = 0; i < this.childContainers.length; i++) {
237
+ let child = this.childContainers[i];
238
+ if (child.containerElement.style.display == 'none')
239
+ child.containerElement.style.display = 'block';
240
+ let newSize = childSizes[i];
241
+
242
+ if (this.stackedVertical)
243
+ child.resize(width, newSize);
244
+ else
245
+ child.resize(newSize, height);
246
+ }
247
+ }
248
+
249
+ private resizeProportionally(width: number, height: number, targetTotalChildPanelSize: number) {
250
+ for (let i = 0; i < this.childContainers.length; i++) {
251
+ let childContainer = this.childContainers[i];
252
+ if (this.stackedVertical)
253
+ childContainer.resize(width, !childContainer.height ? height : childContainer.height);
254
+ else
255
+ childContainer.resize(!childContainer.width ? width : childContainer.width, height);
256
+ }
257
+
258
+ let totalChildPanelSize = 0;
259
+ this.childContainers.forEach((container) => {
260
+ let size = this.stackedVertical ? container.height : container.width;
261
+ totalChildPanelSize += size;
262
+ });
263
+ totalChildPanelSize = Math.max(totalChildPanelSize, 1);
264
+ let scaleMultiplier = targetTotalChildPanelSize / totalChildPanelSize;
265
+
266
+ let updatedTotalChildPanelSize = 0;
267
+ for (let i = 0; i < this.childContainers.length; i++) {
268
+ let child = this.childContainers[i];
269
+ if (child.containerElement.style.display == 'none')
270
+ child.containerElement.style.display = 'block';
271
+ let original = this.stackedVertical ? child.containerElement.clientHeight : child.containerElement.clientWidth;
272
+ let newSize = Math.floor(original * scaleMultiplier);
273
+ updatedTotalChildPanelSize += newSize;
274
+
275
+ if (i === this.childContainers.length - 1)
276
+ newSize += targetTotalChildPanelSize - updatedTotalChildPanelSize;
277
+
278
+ if (this.stackedVertical)
279
+ child.resize(child.width, newSize);
280
+ else
281
+ child.resize(newSize, child.height);
282
+ this.preferredChildSizes.set(child, newSize);
283
+ }
284
+ }
285
+
286
+ private hasElasticChild(): boolean {
287
+ return this.childContainers.some((container) =>
288
+ container.containerType === ContainerType.fill ||
289
+ container.containerType === ContainerType.horizontal ||
290
+ container.containerType === ContainerType.vertical);
291
+ }
292
+
293
+ private getElasticChildIndex(): number {
294
+ let fillIndex = this.childContainers.findIndex((container) => container.containerType === ContainerType.fill);
295
+ if (fillIndex >= 0)
296
+ return fillIndex;
297
+
298
+ let compositeIndex = this.childContainers.findIndex((container) =>
299
+ container.containerType === ContainerType.horizontal || container.containerType === ContainerType.vertical);
300
+ if (compositeIndex >= 0)
301
+ return compositeIndex;
302
+
303
+ return this.childContainers.length - 1;
304
+ }
305
+
306
+ private getChildSize(container: IDockContainer): number {
307
+ return this.stackedVertical ? container.height : container.width;
308
+ }
309
+ }