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
  */
@@ -921,7 +921,17 @@ class Splitview {
921
921
  size = typeof size === 'number' ? size : item.size;
922
922
  size = clamp(size, item.minimumSize, item.maximumSize);
923
923
  item.size = size;
924
- this.relayout([index]);
924
+ const indexes = range(this.viewItems.length).filter((i) => i !== index);
925
+ const lowPriorityIndexes = [
926
+ ...indexes.filter((i) => this.viewItems[i].priority === exports.LayoutPriority.Low),
927
+ index,
928
+ ];
929
+ const highPriorityIndexes = indexes.filter((i) => this.viewItems[i].priority === exports.LayoutPriority.High);
930
+ /**
931
+ * add this view we are changing to the low-index list since we have determined the size
932
+ * here and don't want it changed
933
+ */
934
+ this.relayout([...lowPriorityIndexes, index], highPriorityIndexes);
925
935
  }
926
936
  addView(view, size = { type: 'distribute' }, index = this.viewItems.length, skipLayout) {
927
937
  const container = document.createElement('div');
@@ -1678,6 +1688,7 @@ class BranchNode extends CompositeDisposable {
1678
1688
  orientation: this.orientation,
1679
1689
  descriptor,
1680
1690
  proportionalLayout,
1691
+ styles,
1681
1692
  });
1682
1693
  }
1683
1694
  this.addDisposables(this._onDidChange, this.splitview.onDidSashEnd(() => {
@@ -2189,6 +2200,14 @@ class Gridview {
2189
2200
  const child = sibling.children[i];
2190
2201
  grandParent.addChild(child, child.size, parentIndex + i);
2191
2202
  }
2203
+ /**
2204
+ * clean down the branch node since we need to dipose of it and
2205
+ * when .dispose() it called on a branch it will dispose of any
2206
+ * views it is holding onto.
2207
+ */
2208
+ while (sibling.children.length > 0) {
2209
+ sibling.removeChild(0);
2210
+ }
2192
2211
  }
2193
2212
  else {
2194
2213
  // otherwise create a new leaf node and add that to the grandparent
@@ -3247,6 +3266,19 @@ class TabsContainer extends CompositeDisposable {
3247
3266
  this.leftActions = element;
3248
3267
  }
3249
3268
  }
3269
+ setPrefixActionsElement(element) {
3270
+ if (this.preActions === element) {
3271
+ return;
3272
+ }
3273
+ if (this.preActions) {
3274
+ this.preActions.remove();
3275
+ this.preActions = undefined;
3276
+ }
3277
+ if (element) {
3278
+ this.preActionsContainer.appendChild(element);
3279
+ this.preActions = element;
3280
+ }
3281
+ }
3250
3282
  get element() {
3251
3283
  return this._element;
3252
3284
  }
@@ -3287,9 +3319,12 @@ class TabsContainer extends CompositeDisposable {
3287
3319
  this.rightActionsContainer.className = 'right-actions-container';
3288
3320
  this.leftActionsContainer = document.createElement('div');
3289
3321
  this.leftActionsContainer.className = 'left-actions-container';
3322
+ this.preActionsContainer = document.createElement('div');
3323
+ this.preActionsContainer.className = 'pre-actions-container';
3290
3324
  this.tabContainer = document.createElement('div');
3291
3325
  this.tabContainer.className = 'tabs-container';
3292
3326
  this.voidContainer = new VoidContainer(this.accessor, this.group);
3327
+ this._element.appendChild(this.preActionsContainer);
3293
3328
  this._element.appendChild(this.tabContainer);
3294
3329
  this._element.appendChild(this.leftActionsContainer);
3295
3330
  this._element.appendChild(this.voidContainer.element);
@@ -3579,6 +3614,16 @@ class DockviewGroupPanelModel extends CompositeDisposable {
3579
3614
  });
3580
3615
  this.tabsContainer.setLeftActionsElement(this._leftHeaderActions.element);
3581
3616
  }
3617
+ if (this.accessor.options.createPrefixHeaderActionsElement) {
3618
+ this._prefixHeaderActions =
3619
+ this.accessor.options.createPrefixHeaderActionsElement(this.groupPanel);
3620
+ this.addDisposables(this._prefixHeaderActions);
3621
+ this._prefixHeaderActions.init({
3622
+ containerApi: new DockviewApi(this.accessor),
3623
+ api: this.groupPanel.api,
3624
+ });
3625
+ this.tabsContainer.setPrefixActionsElement(this._prefixHeaderActions.element);
3626
+ }
3582
3627
  }
3583
3628
  indexOf(panel) {
3584
3629
  return this.tabsContainer.indexOf(panel.id);
@@ -3921,6 +3966,14 @@ class Resizable extends CompositeDisposable {
3921
3966
  */
3922
3967
  return;
3923
3968
  }
3969
+ if (!document.body.contains(this._element)) {
3970
+ /**
3971
+ * since the event is dispatched through requestAnimationFrame there is a small chance
3972
+ * the component is no longer attached to the DOM, if that is the case the dimensions
3973
+ * are mostly likely all zero and meaningless. we should skip this case.
3974
+ */
3975
+ return;
3976
+ }
3924
3977
  const { width, height } = entry.contentRect;
3925
3978
  this.layout(width, height);
3926
3979
  }));
@@ -5949,61 +6002,114 @@ class DockviewComponent extends BaseGrid {
5949
6002
  fromJSON(data) {
5950
6003
  var _a;
5951
6004
  this.clear();
6005
+ if (typeof data !== 'object' || data === null) {
6006
+ throw new Error('serialized layout must be a non-null object');
6007
+ }
5952
6008
  const { grid, panels, activeGroup } = data;
5953
6009
  if (grid.root.type !== 'branch' || !Array.isArray(grid.root.data)) {
5954
6010
  throw new Error('root must be of type branch');
5955
6011
  }
5956
- // take note of the existing dimensions
5957
- const width = this.width;
5958
- const height = this.height;
5959
- const createGroupFromSerializedState = (data) => {
5960
- const { id, locked, hideHeader, views, activeView } = data;
5961
- const group = this.createGroup({
5962
- id,
5963
- locked: !!locked,
5964
- hideHeader: !!hideHeader,
5965
- });
5966
- this._onDidAddGroup.fire(group);
5967
- for (const child of views) {
5968
- const panel = this._deserializer.fromJSON(panels[child], group);
5969
- const isActive = typeof activeView === 'string' && activeView === panel.id;
5970
- group.model.openPanel(panel, {
5971
- skipSetPanelActive: !isActive,
5972
- skipSetGroupActive: true,
6012
+ try {
6013
+ // take note of the existing dimensions
6014
+ const width = this.width;
6015
+ const height = this.height;
6016
+ const createGroupFromSerializedState = (data) => {
6017
+ const { id, locked, hideHeader, views, activeView } = data;
6018
+ if (typeof id !== 'string') {
6019
+ throw new Error('group id must be of type string');
6020
+ }
6021
+ const group = this.createGroup({
6022
+ id,
6023
+ locked: !!locked,
6024
+ hideHeader: !!hideHeader,
5973
6025
  });
6026
+ const createdPanels = [];
6027
+ for (const child of views) {
6028
+ /**
6029
+ * Run the deserializer step seperately since this may fail to due corrupted external state.
6030
+ * In running this section first we avoid firing lots of 'add' events in the event of a failure
6031
+ * due to a corruption of input data.
6032
+ */
6033
+ const panel = this._deserializer.fromJSON(panels[child], group);
6034
+ createdPanels.push(panel);
6035
+ }
6036
+ this._onDidAddGroup.fire(group);
6037
+ for (let i = 0; i < views.length; i++) {
6038
+ const panel = createdPanels[i];
6039
+ const isActive = typeof activeView === 'string' &&
6040
+ activeView === panel.id;
6041
+ group.model.openPanel(panel, {
6042
+ skipSetPanelActive: !isActive,
6043
+ skipSetGroupActive: true,
6044
+ });
6045
+ }
6046
+ if (!group.activePanel && group.panels.length > 0) {
6047
+ group.model.openPanel(group.panels[group.panels.length - 1], {
6048
+ skipSetGroupActive: true,
6049
+ });
6050
+ }
6051
+ return group;
6052
+ };
6053
+ this.gridview.deserialize(grid, {
6054
+ fromJSON: (node) => {
6055
+ return createGroupFromSerializedState(node.data);
6056
+ },
6057
+ });
6058
+ this.layout(width, height, true);
6059
+ const serializedFloatingGroups = (_a = data.floatingGroups) !== null && _a !== void 0 ? _a : [];
6060
+ for (const serializedFloatingGroup of serializedFloatingGroups) {
6061
+ const { data, position } = serializedFloatingGroup;
6062
+ const group = createGroupFromSerializedState(data);
6063
+ this.addFloatingGroup(group, {
6064
+ x: position.left,
6065
+ y: position.top,
6066
+ height: position.height,
6067
+ width: position.width,
6068
+ }, { skipRemoveGroup: true, inDragMode: false });
6069
+ }
6070
+ for (const floatingGroup of this.floatingGroups) {
6071
+ floatingGroup.overlay.setBounds();
6072
+ }
6073
+ if (typeof activeGroup === 'string') {
6074
+ const panel = this.getPanel(activeGroup);
6075
+ if (panel) {
6076
+ this.doSetGroupActive(panel);
6077
+ }
5974
6078
  }
5975
- if (!group.activePanel && group.panels.length > 0) {
5976
- group.model.openPanel(group.panels[group.panels.length - 1], {
5977
- skipSetGroupActive: true,
5978
- });
6079
+ }
6080
+ catch (err) {
6081
+ /**
6082
+ * Takes all the successfully created groups and remove all of their panels.
6083
+ */
6084
+ for (const group of this.groups) {
6085
+ for (const panel of group.panels) {
6086
+ this.removePanel(panel, {
6087
+ removeEmptyGroup: false,
6088
+ skipDispose: false,
6089
+ });
6090
+ }
5979
6091
  }
5980
- return group;
5981
- };
5982
- this.gridview.deserialize(grid, {
5983
- fromJSON: (node) => {
5984
- return createGroupFromSerializedState(node.data);
5985
- },
5986
- });
5987
- this.layout(width, height, true);
5988
- const serializedFloatingGroups = (_a = data.floatingGroups) !== null && _a !== void 0 ? _a : [];
5989
- for (const serializedFloatingGroup of serializedFloatingGroups) {
5990
- const { data, position } = serializedFloatingGroup;
5991
- const group = createGroupFromSerializedState(data);
5992
- this.addFloatingGroup(group, {
5993
- x: position.left,
5994
- y: position.top,
5995
- height: position.height,
5996
- width: position.width,
5997
- }, { skipRemoveGroup: true, inDragMode: false });
5998
- }
5999
- for (const floatingGroup of this.floatingGroups) {
6000
- floatingGroup.overlay.setBounds();
6001
- }
6002
- if (typeof activeGroup === 'string') {
6003
- const panel = this.getPanel(activeGroup);
6004
- if (panel) {
6005
- this.doSetGroupActive(panel);
6092
+ /**
6093
+ * To remove a group we cannot call this.removeGroup(...) since this makes assumptions about
6094
+ * the underlying HTMLElement existing in the Gridview.
6095
+ */
6096
+ for (const group of this.groups) {
6097
+ group.dispose();
6098
+ this._groups.delete(group.id);
6099
+ this._onDidRemoveGroup.fire(group);
6006
6100
  }
6101
+ // iterate over a reassigned array since original array will be modified
6102
+ for (const floatingGroup of [...this.floatingGroups]) {
6103
+ floatingGroup.dispose();
6104
+ }
6105
+ // fires clean-up events and clears the underlying HTML gridview.
6106
+ this.clear();
6107
+ /**
6108
+ * even though we have cleaned-up we still want to inform the caller of their error
6109
+ * and we'll do this through re-throwing the original error since afterall you would
6110
+ * expect trying to load a corrupted layout to result in an error and not silently fail...
6111
+ */
6112
+ throw err;
6007
6113
  }
6008
6114
  this._onDidLayoutFromJSON.fire();
6009
6115
  }
@@ -6217,6 +6323,7 @@ class DockviewComponent extends BaseGrid {
6217
6323
  if (!(options === null || options === void 0 ? void 0 : options.skipDispose)) {
6218
6324
  floatingGroup.group.dispose();
6219
6325
  this._groups.delete(group.id);
6326
+ // TODO: fire group removed event?
6220
6327
  }
6221
6328
  floatingGroup.dispose();
6222
6329
  return floatingGroup.group;
@@ -6457,43 +6564,64 @@ class GridviewComponent extends BaseGrid {
6457
6564
  fromJSON(serializedGridview) {
6458
6565
  this.clear();
6459
6566
  const { grid, activePanel } = serializedGridview;
6460
- const queue = [];
6461
- // take note of the existing dimensions
6462
- const width = this.width;
6463
- const height = this.height;
6464
- this.gridview.deserialize(grid, {
6465
- fromJSON: (node) => {
6466
- const { data } = node;
6467
- const view = createComponent(data.id, data.component, this.options.components || {}, this.options.frameworkComponents || {}, this.options.frameworkComponentFactory
6468
- ? {
6469
- createComponent: this.options.frameworkComponentFactory
6470
- .createComponent,
6471
- }
6472
- : undefined);
6473
- queue.push(() => view.init({
6474
- params: data.params,
6475
- minimumWidth: data.minimumWidth,
6476
- maximumWidth: data.maximumWidth,
6477
- minimumHeight: data.minimumHeight,
6478
- maximumHeight: data.maximumHeight,
6479
- priority: data.priority,
6480
- snap: !!data.snap,
6481
- accessor: this,
6482
- isVisible: node.visible,
6483
- }));
6484
- this._onDidAddGroup.fire(view);
6485
- this.registerPanel(view);
6486
- return view;
6487
- },
6488
- });
6489
- this.layout(width, height, true);
6490
- queue.forEach((f) => f());
6491
- if (typeof activePanel === 'string') {
6492
- const panel = this.getPanel(activePanel);
6493
- if (panel) {
6494
- this.doSetGroupActive(panel);
6567
+ try {
6568
+ const queue = [];
6569
+ // take note of the existing dimensions
6570
+ const width = this.width;
6571
+ const height = this.height;
6572
+ this.gridview.deserialize(grid, {
6573
+ fromJSON: (node) => {
6574
+ const { data } = node;
6575
+ const view = createComponent(data.id, data.component, this.options.components || {}, this.options.frameworkComponents || {}, this.options.frameworkComponentFactory
6576
+ ? {
6577
+ createComponent: this.options.frameworkComponentFactory
6578
+ .createComponent,
6579
+ }
6580
+ : undefined);
6581
+ queue.push(() => view.init({
6582
+ params: data.params,
6583
+ minimumWidth: data.minimumWidth,
6584
+ maximumWidth: data.maximumWidth,
6585
+ minimumHeight: data.minimumHeight,
6586
+ maximumHeight: data.maximumHeight,
6587
+ priority: data.priority,
6588
+ snap: !!data.snap,
6589
+ accessor: this,
6590
+ isVisible: node.visible,
6591
+ }));
6592
+ this._onDidAddGroup.fire(view);
6593
+ this.registerPanel(view);
6594
+ return view;
6595
+ },
6596
+ });
6597
+ this.layout(width, height, true);
6598
+ queue.forEach((f) => f());
6599
+ if (typeof activePanel === 'string') {
6600
+ const panel = this.getPanel(activePanel);
6601
+ if (panel) {
6602
+ this.doSetGroupActive(panel);
6603
+ }
6495
6604
  }
6496
6605
  }
6606
+ catch (err) {
6607
+ /**
6608
+ * To remove a group we cannot call this.removeGroup(...) since this makes assumptions about
6609
+ * the underlying HTMLElement existing in the Gridview.
6610
+ */
6611
+ for (const group of this.groups) {
6612
+ group.dispose();
6613
+ this._groups.delete(group.id);
6614
+ this._onDidRemoveGroup.fire(group);
6615
+ }
6616
+ // fires clean-up events and clears the underlying HTML gridview.
6617
+ this.clear();
6618
+ /**
6619
+ * even though we have cleaned-up we still want to inform the caller of their error
6620
+ * and we'll do this through re-throwing the original error since afterall you would
6621
+ * expect trying to load a corrupted layout to result in an error and not silently fail...
6622
+ */
6623
+ throw err;
6624
+ }
6497
6625
  this._onDidLayoutfromJSON.fire();
6498
6626
  }
6499
6627
  clear() {
@@ -7677,6 +7805,7 @@ const DockviewReact = React__namespace.forwardRef((props, ref) => {
7677
7805
  showDndOverlay: props.showDndOverlay,
7678
7806
  createLeftHeaderActionsElement: createGroupControlElement(props.leftHeaderActionsComponent, { addPortal }),
7679
7807
  createRightHeaderActionsElement: createGroupControlElement(props.rightHeaderActionsComponent, { addPortal }),
7808
+ createPrefixHeaderActionsElement: createGroupControlElement(props.prefixHeaderActionsComponent, { addPortal }),
7680
7809
  singleTabMode: props.singleTabMode,
7681
7810
  disableFloatingGroups: props.disableFloatingGroups,
7682
7811
  floatingGroupBounds: props.floatingGroupBounds,
@@ -7786,6 +7915,14 @@ const DockviewReact = React__namespace.forwardRef((props, ref) => {
7786
7915
  createLeftHeaderActionsElement: createGroupControlElement(props.leftHeaderActionsComponent, { addPortal }),
7787
7916
  });
7788
7917
  }, [props.leftHeaderActionsComponent]);
7918
+ React__namespace.useEffect(() => {
7919
+ if (!dockviewRef.current) {
7920
+ return;
7921
+ }
7922
+ dockviewRef.current.updateOptions({
7923
+ createPrefixHeaderActionsElement: createGroupControlElement(props.prefixHeaderActionsComponent, { addPortal }),
7924
+ });
7925
+ }, [props.prefixHeaderActionsComponent]);
7789
7926
  return (React__namespace.createElement("div", { className: props.className, style: { height: '100%', width: '100%' }, ref: domRef }, portals));
7790
7927
  });
7791
7928
  DockviewReact.displayName = 'DockviewComponent';