Merge branch 'master' of https://github.com/mathuo/dockview into 562-dockview-framework-wrappers-vuejs-angular-javascript-etc-1

This commit is contained in:
mathuo 2024-05-09 20:48:58 +01:00
commit 56457fe269
No known key found for this signature in database
GPG Key ID: C6EEDEFD6CA07281
13 changed files with 214 additions and 33 deletions

View File

@ -2,7 +2,7 @@
"packages": [ "packages": [
"packages/*" "packages/*"
], ],
"version": "1.13.0", "version": "1.13.1",
"npmClient": "yarn", "npmClient": "yarn",
"command": { "command": {
"publish": { "publish": {

View File

@ -1,6 +1,6 @@
{ {
"name": "dockview-angular", "name": "dockview-angular",
"version": "1.13.0", "version": "1.13.1",
"description": "Zero dependency layout manager supporting tabs, grids and splitviews", "description": "Zero dependency layout manager supporting tabs, grids and splitviews",
"keywords": [ "keywords": [
"splitview", "splitview",
@ -54,6 +54,6 @@
"test:cov": "cross-env ../../node_modules/.bin/jest --selectProjects dockview --coverage" "test:cov": "cross-env ../../node_modules/.bin/jest --selectProjects dockview --coverage"
}, },
"dependencies": { "dependencies": {
"dockview-core": "^1.13.0" "dockview-core": "^1.13.1"
} }
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "dockview-core", "name": "dockview-core",
"version": "1.13.0", "version": "1.13.1",
"description": "Zero dependency layout manager supporting tabs, grids and splitviews", "description": "Zero dependency layout manager supporting tabs, grids and splitviews",
"keywords": [ "keywords": [
"splitview", "splitview",

View File

@ -5331,4 +5331,102 @@ describe('dockviewComponent', () => {
expect(addGroupCount).toBe(2); expect(addGroupCount).toBe(2);
}); });
}); });
test('that `onDidLayoutChange` only subscribes to events after initial subscription time', () => {
jest.useFakeTimers();
const container = document.createElement('div');
const dockview = new DockviewComponent({
parentElement: container,
createComponent(options) {
switch (options.name) {
case 'default':
return new PanelContentPartTest(
options.id,
options.name
);
default:
throw new Error(`unsupported`);
}
},
});
const api = new DockviewApi(dockview);
dockview.layout(1000, 1000);
let a = 0;
api.onDidLayoutChange((e) => {
a++;
});
api.addPanel({
id: 'panel_1',
component: 'default',
});
api.addPanel({
id: 'panel_2',
component: 'default',
});
api.addPanel({
id: 'panel_3',
component: 'default',
});
let b = 0;
api.onDidLayoutChange((e) => {
b++;
});
jest.runAllTicks();
expect(a).toBe(1);
expect(b).toBe(0);
});
test('addGroup with absolute position', () => {
const container = document.createElement('div');
const dockview = new DockviewComponent({
parentElement: container,
createComponent(options) {
switch (options.name) {
case 'default':
return new PanelContentPartTest(
options.id,
options.name
);
default:
throw new Error(`unsupported`);
}
},
});
const api = new DockviewApi(dockview);
dockview.layout(1000, 1000);
api.addPanel({
id: 'panel_1',
component: 'default',
});
api.addPanel({
id: 'panel_2',
component: 'default',
});
const panel3 = api.addPanel({
id: 'panel_3',
component: 'default',
position: { direction: 'right' },
});
expect(api.panels.length).toBe(3);
expect(api.groups.length).toBe(2);
api.addGroup({ direction: 'left' });
expect(api.panels.length).toBe(3);
expect(api.groups.length).toBe(3);
});
}); });

View File

@ -1,4 +1,5 @@
import { import {
AsapEvent,
Emitter, Emitter,
Event, Event,
addDisposableListener, addDisposableListener,
@ -82,6 +83,41 @@ describe('events', () => {
}); });
}); });
describe('asapEvent', () => {
test('that asapEvents fire once per event-loop-cycle', () => {
jest.useFakeTimers();
const event = new AsapEvent();
let preFireCount = 0;
let postFireCount = 0;
event.onEvent(() => {
preFireCount++;
});
for (let i = 0; i < 100; i++) {
event.fire();
}
/**
* check that subscribing after the events have fired but before the event-loop cycle completes
* results in no event fires.
*/
event.onEvent((e) => {
postFireCount++;
});
expect(preFireCount).toBe(0);
expect(postFireCount).toBe(0);
jest.runAllTimers();
expect(preFireCount).toBe(1);
expect(postFireCount).toBe(0);
});
});
it('should emit a value when any event fires', () => { it('should emit a value when any event fires', () => {
const emitter1 = new Emitter<number>(); const emitter1 = new Emitter<number>();
const emitter2 = new Emitter<number>(); const emitter2 = new Emitter<number>();

View File

@ -1620,8 +1620,6 @@ export class DockviewComponent
} }
addGroup(options?: AddGroupOptions): DockviewGroupPanel { addGroup(options?: AddGroupOptions): DockviewGroupPanel {
const group = this.createGroup(options);
if (options) { if (options) {
let referenceGroup: DockviewGroupPanel | undefined; let referenceGroup: DockviewGroupPanel | undefined;
@ -1675,12 +1673,16 @@ export class DockviewComponent
location, location,
target target
); );
const group = this.createGroup(options);
this.doAddGroup(group, relativeLocation); this.doAddGroup(group, relativeLocation);
if (!options.skipSetActive) { if (!options.skipSetActive) {
this.doSetGroupAndPanelActive(group); this.doSetGroupAndPanelActive(group);
} }
return group; return group;
} else { } else {
const group = this.createGroup(options);
this.doAddGroup(group); this.doAddGroup(group);
this.doSetGroupAndPanelActive(group); this.doSetGroupAndPanelActive(group);
return group; return group;

View File

@ -203,19 +203,53 @@ export function addDisposableListener<K extends keyof HTMLElementEventMap>(
}; };
} }
export class TickDelayedEvent implements IDisposable { /**
private timer: any; *
* Event Emitter that fires events from a Microtask callback, only one event will fire per event-loop cycle.
*
* It's kind of like using an `asapScheduler` in RxJs with additional logic to only fire once per event-loop cycle.
* This implementation exists to avoid external dependencies.
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/queueMicrotask
* @see https://rxjs.dev/api/index/const/asapScheduler
*/
export class AsapEvent implements IDisposable {
private readonly _onFired = new Emitter<void>(); private readonly _onFired = new Emitter<void>();
readonly onEvent = this._onFired.event; private _currentFireCount = 0;
private _queued = false;
readonly onEvent: Event<void> = (e) => {
/**
* when the event is first subscribed to take note of the current fire count
*/
const fireCountAtTimeOfEventSubscription = this._currentFireCount;
return this._onFired.event(() => {
/**
* if the current fire count is greater than the fire count at event subscription
* then the event has been fired since we subscribed and it's ok to "on_next" the event.
*
* if the count is not greater then what we are recieving is an event from the microtask
* queue that was triggered before we actually subscribed and therfore we should ignore it.
*/
if (this._currentFireCount > fireCountAtTimeOfEventSubscription) {
e();
}
});
};
fire(): void { fire(): void {
if (this.timer) { this._currentFireCount++;
clearTimeout(this.timer);
if (this._queued) {
return;
} }
this.timer = setTimeout(() => {
this._queued = true;
queueMicrotask(() => {
this._queued = false;
this._onFired.fire(); this._onFired.fire();
clearTimeout(this.timer);
}); });
} }

View File

@ -1,4 +1,4 @@
import { Emitter, Event, TickDelayedEvent } from '../events'; import { Emitter, Event, AsapEvent } from '../events';
import { getGridLocation, Gridview, IGridView } from './gridview'; import { getGridLocation, Gridview, IGridView } from './gridview';
import { Position } from '../dnd/droptarget'; import { Position } from '../dnd/droptarget';
import { Disposable, IValueDisposable } from '../lifecycle'; import { Disposable, IValueDisposable } from '../lifecycle';
@ -76,11 +76,8 @@ export abstract class BaseGrid<T extends IGridPanelView>
private readonly _id = nextLayoutId.next(); private readonly _id = nextLayoutId.next();
protected readonly _groups = new Map<string, IValueDisposable<T>>(); protected readonly _groups = new Map<string, IValueDisposable<T>>();
protected readonly gridview: Gridview; protected readonly gridview: Gridview;
//
protected _activeGroup: T | undefined;
private _onDidLayoutChange = new Emitter<void>(); protected _activeGroup: T | undefined;
readonly onDidLayoutChange = this._onDidLayoutChange.event;
private readonly _onDidRemove = new Emitter<T>(); private readonly _onDidRemove = new Emitter<T>();
readonly onDidRemove: Event<T> = this._onDidRemove.event; readonly onDidRemove: Event<T> = this._onDidRemove.event;
@ -92,7 +89,9 @@ export abstract class BaseGrid<T extends IGridPanelView>
readonly onDidActiveChange: Event<T | undefined> = readonly onDidActiveChange: Event<T | undefined> =
this._onDidActiveChange.event; this._onDidActiveChange.event;
protected readonly _bufferOnDidLayoutChange = new TickDelayedEvent(); protected readonly _bufferOnDidLayoutChange = new AsapEvent();
readonly onDidLayoutChange: Event<void> =
this._bufferOnDidLayoutChange.onEvent;
get id(): string { get id(): string {
return this._id; return this._id;
@ -172,9 +171,6 @@ export abstract class BaseGrid<T extends IGridPanelView>
)(() => { )(() => {
this._bufferOnDidLayoutChange.fire(); this._bufferOnDidLayoutChange.fire();
}), }),
this._bufferOnDidLayoutChange.onEvent(() => {
this._onDidLayoutChange.fire();
}),
this._bufferOnDidLayoutChange this._bufferOnDidLayoutChange
); );
} }
@ -187,7 +183,7 @@ export abstract class BaseGrid<T extends IGridPanelView>
public setVisible(panel: T, visible: boolean): void { public setVisible(panel: T, visible: boolean): void {
this.gridview.setViewVisible(getGridLocation(panel.element), visible); this.gridview.setViewVisible(getGridLocation(panel.element), visible);
this._onDidLayoutChange.fire(); this._bufferOnDidLayoutChange.fire();
} }
public isVisible(panel: T): boolean { public isVisible(panel: T): boolean {
@ -330,7 +326,6 @@ export abstract class BaseGrid<T extends IGridPanelView>
this._onDidActiveChange.dispose(); this._onDidActiveChange.dispose();
this._onDidAdd.dispose(); this._onDidAdd.dispose();
this._onDidRemove.dispose(); this._onDidRemove.dispose();
this._onDidLayoutChange.dispose();
for (const group of this.groups) { for (const group of this.groups) {
group.dispose(); group.dispose();

View File

@ -1,6 +1,6 @@
{ {
"name": "dockview-react", "name": "dockview-react",
"version": "1.13.0", "version": "1.13.1",
"description": "Zero dependency layout manager supporting tabs, grids and splitviews", "description": "Zero dependency layout manager supporting tabs, grids and splitviews",
"keywords": [ "keywords": [
"splitview", "splitview",
@ -54,6 +54,6 @@
"test:cov": "cross-env ../../node_modules/.bin/jest --selectProjects dockview --coverage" "test:cov": "cross-env ../../node_modules/.bin/jest --selectProjects dockview --coverage"
}, },
"dependencies": { "dependencies": {
"dockview": "^1.13.0" "dockview": "^1.13.1"
} }
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "dockview-vue", "name": "dockview-vue",
"version": "1.13.0", "version": "1.13.1",
"description": "Zero dependency layout manager supporting tabs, grids and splitviews", "description": "Zero dependency layout manager supporting tabs, grids and splitviews",
"keywords": [ "keywords": [
"splitview", "splitview",
@ -56,6 +56,6 @@
"build:types": "vue-tsc --project tsconfig.build-types.json --declaration --emitDeclarationOnly --outDir dist/types " "build:types": "vue-tsc --project tsconfig.build-types.json --declaration --emitDeclarationOnly --outDir dist/types "
}, },
"dependencies": { "dependencies": {
"dockview-core": "^1.13.0" "dockview-core": "^1.13.1"
} }
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "dockview", "name": "dockview",
"version": "1.13.0", "version": "1.13.1",
"description": "Zero dependency layout manager supporting tabs, grids and splitviews", "description": "Zero dependency layout manager supporting tabs, grids and splitviews",
"keywords": [ "keywords": [
"splitview", "splitview",
@ -54,6 +54,6 @@
"test:cov": "cross-env ../../node_modules/.bin/jest --selectProjects dockview --coverage" "test:cov": "cross-env ../../node_modules/.bin/jest --selectProjects dockview --coverage"
}, },
"dependencies": { "dependencies": {
"dockview-core": "^1.13.0" "dockview-core": "^1.13.1"
} }
} }

View File

@ -0,0 +1,16 @@
---
slug: dockview-1.13.1-release
title: Dockview 1.13.1
tags: [release]
---
# Release Notes
Please reference docs @ [dockview.dev](https://dockview.dev).
## 🛠 Miscs
- Bug: fix duplicate group added when adding group with absolute position [#596](https://github.com/mathuo/dockview/issues/596)
- Bug: Adjust onDidLayoutChange behaviour [#597](https://github.com/mathuo/dockview/issues/597)
- `onDidLayoutChange` is an aggregation of events that constitute a layout change. Previously these events were aggregated and the events were then fired once through a `setTimeout(..., 0)` approach. This has been altered to fire on a `queueMicrotask` event and will only subscribe to events that happen after the event is subscribed to, previously you may have recieved events yet to fire on the `setTimeout` function but within the same event-loop cycle which was a bug.

View File

@ -1,6 +1,6 @@
{ {
"name": "dockview-docs", "name": "dockview-docs",
"version": "1.13.0", "version": "1.13.1",
"private": true, "private": true,
"scripts": { "scripts": {
"build": "npm run build-templates && docusaurus build", "build": "npm run build-templates && docusaurus build",
@ -37,7 +37,7 @@
"ag-grid-react": "^31.0.2", "ag-grid-react": "^31.0.2",
"axios": "^1.6.3", "axios": "^1.6.3",
"clsx": "^2.1.0", "clsx": "^2.1.0",
"dockview": "^1.13.0", "dockview": "^1.13.1",
"prism-react-renderer": "^2.3.1", "prism-react-renderer": "^2.3.1",
"react-dnd": "^16.0.1", "react-dnd": "^16.0.1",
"react-laag": "^2.0.5", "react-laag": "^2.0.5",