dockview 1.8.3 → 1.8.4

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,6 @@
1
1
  /**
2
2
  * dockview
3
- * @version 1.8.3
3
+ * @version 1.8.4
4
4
  * @link https://github.com/mathuo/dockview
5
5
  * @license MIT
6
6
  */
@@ -892,7 +892,17 @@
892
892
  size = typeof size === 'number' ? size : item.size;
893
893
  size = clamp(size, item.minimumSize, item.maximumSize);
894
894
  item.size = size;
895
- this.relayout([index]);
895
+ const indexes = range(this.viewItems.length).filter((i) => i !== index);
896
+ const lowPriorityIndexes = [
897
+ ...indexes.filter((i) => this.viewItems[i].priority === exports.LayoutPriority.Low),
898
+ index,
899
+ ];
900
+ const highPriorityIndexes = indexes.filter((i) => this.viewItems[i].priority === exports.LayoutPriority.High);
901
+ /**
902
+ * add this view we are changing to the low-index list since we have determined the size
903
+ * here and don't want it changed
904
+ */
905
+ this.relayout([...lowPriorityIndexes, index], highPriorityIndexes);
896
906
  }
897
907
  addView(view, size = { type: 'distribute' }, index = this.viewItems.length, skipLayout) {
898
908
  const container = document.createElement('div');
@@ -1649,6 +1659,7 @@
1649
1659
  orientation: this.orientation,
1650
1660
  descriptor,
1651
1661
  proportionalLayout,
1662
+ styles,
1652
1663
  });
1653
1664
  }
1654
1665
  this.addDisposables(this._onDidChange, this.splitview.onDidSashEnd(() => {
@@ -2160,6 +2171,14 @@
2160
2171
  const child = sibling.children[i];
2161
2172
  grandParent.addChild(child, child.size, parentIndex + i);
2162
2173
  }
2174
+ /**
2175
+ * clean down the branch node since we need to dipose of it and
2176
+ * when .dispose() it called on a branch it will dispose of any
2177
+ * views it is holding onto.
2178
+ */
2179
+ while (sibling.children.length > 0) {
2180
+ sibling.removeChild(0);
2181
+ }
2163
2182
  }
2164
2183
  else {
2165
2184
  // otherwise create a new leaf node and add that to the grandparent
@@ -3218,6 +3237,19 @@
3218
3237
  this.leftActions = element;
3219
3238
  }
3220
3239
  }
3240
+ setPrefixActionsElement(element) {
3241
+ if (this.preActions === element) {
3242
+ return;
3243
+ }
3244
+ if (this.preActions) {
3245
+ this.preActions.remove();
3246
+ this.preActions = undefined;
3247
+ }
3248
+ if (element) {
3249
+ this.preActionsContainer.appendChild(element);
3250
+ this.preActions = element;
3251
+ }
3252
+ }
3221
3253
  get element() {
3222
3254
  return this._element;
3223
3255
  }
@@ -3258,9 +3290,12 @@
3258
3290
  this.rightActionsContainer.className = 'right-actions-container';
3259
3291
  this.leftActionsContainer = document.createElement('div');
3260
3292
  this.leftActionsContainer.className = 'left-actions-container';
3293
+ this.preActionsContainer = document.createElement('div');
3294
+ this.preActionsContainer.className = 'pre-actions-container';
3261
3295
  this.tabContainer = document.createElement('div');
3262
3296
  this.tabContainer.className = 'tabs-container';
3263
3297
  this.voidContainer = new VoidContainer(this.accessor, this.group);
3298
+ this._element.appendChild(this.preActionsContainer);
3264
3299
  this._element.appendChild(this.tabContainer);
3265
3300
  this._element.appendChild(this.leftActionsContainer);
3266
3301
  this._element.appendChild(this.voidContainer.element);
@@ -3550,6 +3585,16 @@
3550
3585
  });
3551
3586
  this.tabsContainer.setLeftActionsElement(this._leftHeaderActions.element);
3552
3587
  }
3588
+ if (this.accessor.options.createPrefixHeaderActionsElement) {
3589
+ this._prefixHeaderActions =
3590
+ this.accessor.options.createPrefixHeaderActionsElement(this.groupPanel);
3591
+ this.addDisposables(this._prefixHeaderActions);
3592
+ this._prefixHeaderActions.init({
3593
+ containerApi: new DockviewApi(this.accessor),
3594
+ api: this.groupPanel.api,
3595
+ });
3596
+ this.tabsContainer.setPrefixActionsElement(this._prefixHeaderActions.element);
3597
+ }
3553
3598
  }
3554
3599
  indexOf(panel) {
3555
3600
  return this.tabsContainer.indexOf(panel.id);
@@ -3892,6 +3937,14 @@
3892
3937
  */
3893
3938
  return;
3894
3939
  }
3940
+ if (!document.body.contains(this._element)) {
3941
+ /**
3942
+ * since the event is dispatched through requestAnimationFrame there is a small chance
3943
+ * the component is no longer attached to the DOM, if that is the case the dimensions
3944
+ * are mostly likely all zero and meaningless. we should skip this case.
3945
+ */
3946
+ return;
3947
+ }
3895
3948
  const { width, height } = entry.contentRect;
3896
3949
  this.layout(width, height);
3897
3950
  }));
@@ -5920,61 +5973,114 @@
5920
5973
  fromJSON(data) {
5921
5974
  var _a;
5922
5975
  this.clear();
5976
+ if (typeof data !== 'object' || data === null) {
5977
+ throw new Error('serialized layout must be a non-null object');
5978
+ }
5923
5979
  const { grid, panels, activeGroup } = data;
5924
5980
  if (grid.root.type !== 'branch' || !Array.isArray(grid.root.data)) {
5925
5981
  throw new Error('root must be of type branch');
5926
5982
  }
5927
- // take note of the existing dimensions
5928
- const width = this.width;
5929
- const height = this.height;
5930
- const createGroupFromSerializedState = (data) => {
5931
- const { id, locked, hideHeader, views, activeView } = data;
5932
- const group = this.createGroup({
5933
- id,
5934
- locked: !!locked,
5935
- hideHeader: !!hideHeader,
5936
- });
5937
- this._onDidAddGroup.fire(group);
5938
- for (const child of views) {
5939
- const panel = this._deserializer.fromJSON(panels[child], group);
5940
- const isActive = typeof activeView === 'string' && activeView === panel.id;
5941
- group.model.openPanel(panel, {
5942
- skipSetPanelActive: !isActive,
5943
- skipSetGroupActive: true,
5983
+ try {
5984
+ // take note of the existing dimensions
5985
+ const width = this.width;
5986
+ const height = this.height;
5987
+ const createGroupFromSerializedState = (data) => {
5988
+ const { id, locked, hideHeader, views, activeView } = data;
5989
+ if (typeof id !== 'string') {
5990
+ throw new Error('group id must be of type string');
5991
+ }
5992
+ const group = this.createGroup({
5993
+ id,
5994
+ locked: !!locked,
5995
+ hideHeader: !!hideHeader,
5944
5996
  });
5997
+ const createdPanels = [];
5998
+ for (const child of views) {
5999
+ /**
6000
+ * Run the deserializer step seperately since this may fail to due corrupted external state.
6001
+ * In running this section first we avoid firing lots of 'add' events in the event of a failure
6002
+ * due to a corruption of input data.
6003
+ */
6004
+ const panel = this._deserializer.fromJSON(panels[child], group);
6005
+ createdPanels.push(panel);
6006
+ }
6007
+ this._onDidAddGroup.fire(group);
6008
+ for (let i = 0; i < views.length; i++) {
6009
+ const panel = createdPanels[i];
6010
+ const isActive = typeof activeView === 'string' &&
6011
+ activeView === panel.id;
6012
+ group.model.openPanel(panel, {
6013
+ skipSetPanelActive: !isActive,
6014
+ skipSetGroupActive: true,
6015
+ });
6016
+ }
6017
+ if (!group.activePanel && group.panels.length > 0) {
6018
+ group.model.openPanel(group.panels[group.panels.length - 1], {
6019
+ skipSetGroupActive: true,
6020
+ });
6021
+ }
6022
+ return group;
6023
+ };
6024
+ this.gridview.deserialize(grid, {
6025
+ fromJSON: (node) => {
6026
+ return createGroupFromSerializedState(node.data);
6027
+ },
6028
+ });
6029
+ this.layout(width, height, true);
6030
+ const serializedFloatingGroups = (_a = data.floatingGroups) !== null && _a !== void 0 ? _a : [];
6031
+ for (const serializedFloatingGroup of serializedFloatingGroups) {
6032
+ const { data, position } = serializedFloatingGroup;
6033
+ const group = createGroupFromSerializedState(data);
6034
+ this.addFloatingGroup(group, {
6035
+ x: position.left,
6036
+ y: position.top,
6037
+ height: position.height,
6038
+ width: position.width,
6039
+ }, { skipRemoveGroup: true, inDragMode: false });
6040
+ }
6041
+ for (const floatingGroup of this.floatingGroups) {
6042
+ floatingGroup.overlay.setBounds();
6043
+ }
6044
+ if (typeof activeGroup === 'string') {
6045
+ const panel = this.getPanel(activeGroup);
6046
+ if (panel) {
6047
+ this.doSetGroupActive(panel);
6048
+ }
5945
6049
  }
5946
- if (!group.activePanel && group.panels.length > 0) {
5947
- group.model.openPanel(group.panels[group.panels.length - 1], {
5948
- skipSetGroupActive: true,
5949
- });
6050
+ }
6051
+ catch (err) {
6052
+ /**
6053
+ * Takes all the successfully created groups and remove all of their panels.
6054
+ */
6055
+ for (const group of this.groups) {
6056
+ for (const panel of group.panels) {
6057
+ this.removePanel(panel, {
6058
+ removeEmptyGroup: false,
6059
+ skipDispose: false,
6060
+ });
6061
+ }
5950
6062
  }
5951
- return group;
5952
- };
5953
- this.gridview.deserialize(grid, {
5954
- fromJSON: (node) => {
5955
- return createGroupFromSerializedState(node.data);
5956
- },
5957
- });
5958
- this.layout(width, height, true);
5959
- const serializedFloatingGroups = (_a = data.floatingGroups) !== null && _a !== void 0 ? _a : [];
5960
- for (const serializedFloatingGroup of serializedFloatingGroups) {
5961
- const { data, position } = serializedFloatingGroup;
5962
- const group = createGroupFromSerializedState(data);
5963
- this.addFloatingGroup(group, {
5964
- x: position.left,
5965
- y: position.top,
5966
- height: position.height,
5967
- width: position.width,
5968
- }, { skipRemoveGroup: true, inDragMode: false });
5969
- }
5970
- for (const floatingGroup of this.floatingGroups) {
5971
- floatingGroup.overlay.setBounds();
5972
- }
5973
- if (typeof activeGroup === 'string') {
5974
- const panel = this.getPanel(activeGroup);
5975
- if (panel) {
5976
- this.doSetGroupActive(panel);
6063
+ /**
6064
+ * To remove a group we cannot call this.removeGroup(...) since this makes assumptions about
6065
+ * the underlying HTMLElement existing in the Gridview.
6066
+ */
6067
+ for (const group of this.groups) {
6068
+ group.dispose();
6069
+ this._groups.delete(group.id);
6070
+ this._onDidRemoveGroup.fire(group);
5977
6071
  }
6072
+ // iterate over a reassigned array since original array will be modified
6073
+ for (const floatingGroup of [...this.floatingGroups]) {
6074
+ floatingGroup.dispose();
6075
+ }
6076
+ // fires clean-up events and clears the underlying HTML gridview.
6077
+ this.clear();
6078
+ /**
6079
+ * even though we have cleaned-up we still want to inform the caller of their error
6080
+ * and we'll do this through re-throwing the original error since afterall you would
6081
+ * expect trying to load a corrupted layout to result in an error and not silently fail...
6082
+ */
6083
+ throw err;
5978
6084
  }
5979
6085
  this._onDidLayoutFromJSON.fire();
5980
6086
  }
@@ -6188,6 +6294,7 @@
6188
6294
  if (!(options === null || options === void 0 ? void 0 : options.skipDispose)) {
6189
6295
  floatingGroup.group.dispose();
6190
6296
  this._groups.delete(group.id);
6297
+ // TODO: fire group removed event?
6191
6298
  }
6192
6299
  floatingGroup.dispose();
6193
6300
  return floatingGroup.group;
@@ -6428,43 +6535,64 @@
6428
6535
  fromJSON(serializedGridview) {
6429
6536
  this.clear();
6430
6537
  const { grid, activePanel } = serializedGridview;
6431
- const queue = [];
6432
- // take note of the existing dimensions
6433
- const width = this.width;
6434
- const height = this.height;
6435
- this.gridview.deserialize(grid, {
6436
- fromJSON: (node) => {
6437
- const { data } = node;
6438
- const view = createComponent(data.id, data.component, this.options.components || {}, this.options.frameworkComponents || {}, this.options.frameworkComponentFactory
6439
- ? {
6440
- createComponent: this.options.frameworkComponentFactory
6441
- .createComponent,
6442
- }
6443
- : undefined);
6444
- queue.push(() => view.init({
6445
- params: data.params,
6446
- minimumWidth: data.minimumWidth,
6447
- maximumWidth: data.maximumWidth,
6448
- minimumHeight: data.minimumHeight,
6449
- maximumHeight: data.maximumHeight,
6450
- priority: data.priority,
6451
- snap: !!data.snap,
6452
- accessor: this,
6453
- isVisible: node.visible,
6454
- }));
6455
- this._onDidAddGroup.fire(view);
6456
- this.registerPanel(view);
6457
- return view;
6458
- },
6459
- });
6460
- this.layout(width, height, true);
6461
- queue.forEach((f) => f());
6462
- if (typeof activePanel === 'string') {
6463
- const panel = this.getPanel(activePanel);
6464
- if (panel) {
6465
- this.doSetGroupActive(panel);
6538
+ try {
6539
+ const queue = [];
6540
+ // take note of the existing dimensions
6541
+ const width = this.width;
6542
+ const height = this.height;
6543
+ this.gridview.deserialize(grid, {
6544
+ fromJSON: (node) => {
6545
+ const { data } = node;
6546
+ const view = createComponent(data.id, data.component, this.options.components || {}, this.options.frameworkComponents || {}, this.options.frameworkComponentFactory
6547
+ ? {
6548
+ createComponent: this.options.frameworkComponentFactory
6549
+ .createComponent,
6550
+ }
6551
+ : undefined);
6552
+ queue.push(() => view.init({
6553
+ params: data.params,
6554
+ minimumWidth: data.minimumWidth,
6555
+ maximumWidth: data.maximumWidth,
6556
+ minimumHeight: data.minimumHeight,
6557
+ maximumHeight: data.maximumHeight,
6558
+ priority: data.priority,
6559
+ snap: !!data.snap,
6560
+ accessor: this,
6561
+ isVisible: node.visible,
6562
+ }));
6563
+ this._onDidAddGroup.fire(view);
6564
+ this.registerPanel(view);
6565
+ return view;
6566
+ },
6567
+ });
6568
+ this.layout(width, height, true);
6569
+ queue.forEach((f) => f());
6570
+ if (typeof activePanel === 'string') {
6571
+ const panel = this.getPanel(activePanel);
6572
+ if (panel) {
6573
+ this.doSetGroupActive(panel);
6574
+ }
6466
6575
  }
6467
6576
  }
6577
+ catch (err) {
6578
+ /**
6579
+ * To remove a group we cannot call this.removeGroup(...) since this makes assumptions about
6580
+ * the underlying HTMLElement existing in the Gridview.
6581
+ */
6582
+ for (const group of this.groups) {
6583
+ group.dispose();
6584
+ this._groups.delete(group.id);
6585
+ this._onDidRemoveGroup.fire(group);
6586
+ }
6587
+ // fires clean-up events and clears the underlying HTML gridview.
6588
+ this.clear();
6589
+ /**
6590
+ * even though we have cleaned-up we still want to inform the caller of their error
6591
+ * and we'll do this through re-throwing the original error since afterall you would
6592
+ * expect trying to load a corrupted layout to result in an error and not silently fail...
6593
+ */
6594
+ throw err;
6595
+ }
6468
6596
  this._onDidLayoutfromJSON.fire();
6469
6597
  }
6470
6598
  clear() {
@@ -7648,6 +7776,7 @@
7648
7776
  showDndOverlay: props.showDndOverlay,
7649
7777
  createLeftHeaderActionsElement: createGroupControlElement(props.leftHeaderActionsComponent, { addPortal }),
7650
7778
  createRightHeaderActionsElement: createGroupControlElement(props.rightHeaderActionsComponent, { addPortal }),
7779
+ createPrefixHeaderActionsElement: createGroupControlElement(props.prefixHeaderActionsComponent, { addPortal }),
7651
7780
  singleTabMode: props.singleTabMode,
7652
7781
  disableFloatingGroups: props.disableFloatingGroups,
7653
7782
  floatingGroupBounds: props.floatingGroupBounds,
@@ -7757,6 +7886,14 @@
7757
7886
  createLeftHeaderActionsElement: createGroupControlElement(props.leftHeaderActionsComponent, { addPortal }),
7758
7887
  });
7759
7888
  }, [props.leftHeaderActionsComponent]);
7889
+ React__namespace.useEffect(() => {
7890
+ if (!dockviewRef.current) {
7891
+ return;
7892
+ }
7893
+ dockviewRef.current.updateOptions({
7894
+ createPrefixHeaderActionsElement: createGroupControlElement(props.prefixHeaderActionsComponent, { addPortal }),
7895
+ });
7896
+ }, [props.prefixHeaderActionsComponent]);
7760
7897
  return (React__namespace.createElement("div", { className: props.className, style: { height: '100%', width: '100%' }, ref: domRef }, portals));
7761
7898
  });
7762
7899
  DockviewReact.displayName = 'DockviewComponent';