Skip to content

Commit da0ffe5

Browse files
committed
feat: experimental work
1 parent 25489bf commit da0ffe5

File tree

5 files changed

+121
-17
lines changed

5 files changed

+121
-17
lines changed

packages/dockview-core/src/api/component.api.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -854,8 +854,11 @@ export class DockviewApi implements CommonApi<SerializedDockview> {
854854
/**
855855
* Create a component from a serialized object.
856856
*/
857-
fromJSON(data: SerializedDockview): void {
858-
this.component.fromJSON(data);
857+
fromJSON(
858+
data: SerializedDockview,
859+
options?: { keepExistingPanels: boolean }
860+
): void {
861+
this.component.fromJSON(data, options);
859862
}
860863

861864
/**

packages/dockview-core/src/dockview/dockviewComponent.ts

Lines changed: 70 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ type MoveGroupOrPanelOptions = {
147147
position: Position;
148148
index?: number;
149149
};
150+
keepEmptyGroups?: boolean;
150151
};
151152

152153
export interface FloatingGroupOptions {
@@ -219,6 +220,7 @@ export interface IDockviewComponent extends IBaseGrid<DockviewGroupPanel> {
219220
onWillClose?: (event: { id: string; window: Window }) => void;
220221
}
221222
): Promise<boolean>;
223+
fromJSON(data: any, options?: { keepExistingPanels: boolean }): void;
222224
}
223225

224226
export class DockviewComponent
@@ -1219,7 +1221,41 @@ export class DockviewComponent
12191221
return result;
12201222
}
12211223

1222-
fromJSON(data: SerializedDockview): void {
1224+
fromJSON(
1225+
data: SerializedDockview,
1226+
options?: { keepExistingPanels: boolean }
1227+
): void {
1228+
const existingPanels = new Map<string, IDockviewPanel>();
1229+
const tempGroup = this.createGroup();
1230+
this._groups.delete(tempGroup.api.id);
1231+
1232+
if (options?.keepExistingPanels) {
1233+
const newPanels = Object.keys(data.panels);
1234+
1235+
for (const panel of this.panels) {
1236+
if (newPanels.includes(panel.api.id)) {
1237+
existingPanels.set(panel.api.id, panel);
1238+
}
1239+
}
1240+
1241+
this.movingLock(() => {
1242+
Array.from(existingPanels.values()).forEach((panel) => {
1243+
this.moveGroupOrPanel({
1244+
from: {
1245+
groupId: panel.api.group.api.id,
1246+
panelId: panel.api.id,
1247+
},
1248+
to: {
1249+
group: tempGroup,
1250+
position: 'center',
1251+
},
1252+
keepEmptyGroups: true,
1253+
});
1254+
// panel.api.moveTo({ group: tempGroup });
1255+
});
1256+
});
1257+
}
1258+
12231259
this.clear();
12241260

12251261
if (typeof data !== 'object' || data === null) {
@@ -1260,11 +1296,23 @@ export class DockviewComponent
12601296
* In running this section first we avoid firing lots of 'add' events in the event of a failure
12611297
* due to a corruption of input data.
12621298
*/
1263-
const panel = this._deserializer.fromJSON(
1264-
panels[child],
1265-
group
1266-
);
1267-
createdPanels.push(panel);
1299+
1300+
const existingPanel = existingPanels.get(child);
1301+
1302+
if (existingPanel) {
1303+
this.movingLock(() => {
1304+
tempGroup.model.removePanel(existingPanel);
1305+
});
1306+
1307+
createdPanels.push(existingPanel);
1308+
existingPanel.updateFromStateModel(panels[child]);
1309+
} else {
1310+
const panel = this._deserializer.fromJSON(
1311+
panels[child],
1312+
group
1313+
);
1314+
createdPanels.push(panel);
1315+
}
12681316
}
12691317

12701318
this._onDidAddGroup.fire(group);
@@ -1276,10 +1324,21 @@ export class DockviewComponent
12761324
typeof activeView === 'string' &&
12771325
activeView === panel.id;
12781326

1279-
group.model.openPanel(panel, {
1280-
skipSetActive: !isActive,
1281-
skipSetGroupActive: true,
1282-
});
1327+
const hasExisting = existingPanels.has(panel.api.id);
1328+
1329+
if (hasExisting) {
1330+
this.movingLock(() => {
1331+
group.model.openPanel(panel, {
1332+
skipSetActive: !isActive,
1333+
skipSetGroupActive: true,
1334+
});
1335+
});
1336+
} else {
1337+
group.model.openPanel(panel, {
1338+
skipSetActive: !isActive,
1339+
skipSetGroupActive: true,
1340+
});
1341+
}
12831342
}
12841343

12851344
if (!group.activePanel && group.panels.length > 0) {
@@ -1952,7 +2011,7 @@ export class DockviewComponent
19522011
throw new Error(`No panel with id ${sourceItemId}`);
19532012
}
19542013

1955-
if (sourceGroup.model.size === 0) {
2014+
if (!options.keepEmptyGroups && sourceGroup.model.size === 0) {
19562015
// remove the group and do not set a new group as active
19572016
this.doRemoveGroup(sourceGroup, { skipActive: true });
19582017
}

packages/dockview-core/src/dockview/dockviewPanel.ts

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export interface IDockviewPanel extends IDisposable, IPanel {
2727
group: DockviewGroupPanel,
2828
options?: { skipSetActive?: boolean }
2929
): void;
30+
updateFromStateModel(state: GroupviewPanelState): void;
3031
init(params: IGroupPanelInitParameters): void;
3132
toJSON(): GroupviewPanelState;
3233
setTitle(title: string): void;
@@ -45,10 +46,10 @@ export class DockviewPanel
4546
private _title: string | undefined;
4647
private _renderer: DockviewPanelRenderer | undefined;
4748

48-
private readonly _minimumWidth: number | undefined;
49-
private readonly _minimumHeight: number | undefined;
50-
private readonly _maximumWidth: number | undefined;
51-
private readonly _maximumHeight: number | undefined;
49+
private _minimumWidth: number | undefined;
50+
private _minimumHeight: number | undefined;
51+
private _maximumWidth: number | undefined;
52+
private _maximumHeight: number | undefined;
5253

5354
get params(): Parameters | undefined {
5455
return this._params;
@@ -209,6 +210,20 @@ export class DockviewPanel
209210
});
210211
}
211212

213+
updateFromStateModel(state: GroupviewPanelState): void {
214+
this._maximumHeight = state.maximumHeight;
215+
this._minimumHeight = state.minimumHeight;
216+
this._maximumWidth = state.maximumWidth;
217+
this._minimumWidth = state.minimumWidth;
218+
219+
this.update({ params: state.params ?? {} });
220+
this.setTitle(state.title ?? this.id);
221+
this.setRenderer(state.renderer ?? this.accessor.renderer);
222+
223+
// state.contentComponent;
224+
// state.tabComponent;
225+
}
226+
212227
public updateParentGroup(
213228
group: DockviewGroupPanel,
214229
options?: { skipSetActive?: boolean }

packages/docs/sandboxes/react/dockview/demo-dockview/src/app.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ const components = {
3535
const isDebug = React.useContext(DebugContext);
3636
const metadata = usePanelApiMetadata(props.api);
3737

38+
const [firstRender, setFirstRender] = React.useState<string>('');
39+
40+
React.useEffect(() => {
41+
setFirstRender(new Date().toISOString());
42+
}, []);
43+
3844
return (
3945
<div
4046
style={{
@@ -59,6 +65,8 @@ const components = {
5965
{props.api.title}
6066
</span>
6167

68+
<div>{firstRender}</div>
69+
6270
{isDebug && (
6371
<div style={{ fontSize: '0.8em' }}>
6472
<Option

packages/docs/sandboxes/react/dockview/demo-dockview/src/gridActions.tsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,22 @@ export const GridActions = (props: {
110110
}
111111
};
112112

113+
const onLoad2 = () => {
114+
const state = localStorage.getItem('dv-demo-state');
115+
if (state) {
116+
try {
117+
props.api?.fromJSON(JSON.parse(state), {
118+
keepExistingPanels: true,
119+
});
120+
121+
setGap(props.api?.gap ?? 0);
122+
} catch (err) {
123+
console.error('failed to load state', err);
124+
localStorage.removeItem('dv-demo-state');
125+
}
126+
}
127+
};
128+
113129
const onSave = () => {
114130
if (props.api) {
115131
console.log(props.api.toJSON());
@@ -192,6 +208,9 @@ export const GridActions = (props: {
192208
<button className="text-button" onClick={onLoad}>
193209
Load
194210
</button>
211+
<button className="text-button" onClick={onLoad2}>
212+
Load2
213+
</button>
195214
<button className="text-button" onClick={onSave}>
196215
Save
197216
</button>

0 commit comments

Comments
 (0)