mirror of
https://github.com/mathuo/dockview
synced 2025-02-10 10:25:46 +00:00
Merge branch 'master' of https://github.com/mathuo/dockview into 230-explore-floating-groups
This commit is contained in:
commit
c53d2690c3
@ -13,6 +13,7 @@
|
|||||||
"/packages/docs/sandboxes/externaldnd-dockview",
|
"/packages/docs/sandboxes/externaldnd-dockview",
|
||||||
"/packages/docs/sandboxes/fullwidthtab-dockview",
|
"/packages/docs/sandboxes/fullwidthtab-dockview",
|
||||||
"/packages/docs/sandboxes/groupcontol-dockview",
|
"/packages/docs/sandboxes/groupcontol-dockview",
|
||||||
|
"/packages/docs/sandboxes/iframe-dockview",
|
||||||
"/packages/docs/sandboxes/layout-dockview",
|
"/packages/docs/sandboxes/layout-dockview",
|
||||||
"/packages/docs/sandboxes/nativeapp-dockview",
|
"/packages/docs/sandboxes/nativeapp-dockview",
|
||||||
"/packages/docs/sandboxes/nested-dockview",
|
"/packages/docs/sandboxes/nested-dockview",
|
||||||
|
2
.github/workflows/codeql-analysis.yml
vendored
2
.github/workflows/codeql-analysis.yml
vendored
@ -30,7 +30,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
|
8
.github/workflows/deploy-docs.yml
vendored
8
.github/workflows/deploy-docs.yml
vendored
@ -9,16 +9,13 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout 🛎️
|
- name: Checkout 🛎️
|
||||||
uses: actions/checkout@v2.3.1 # If you're using actions/checkout@v2 you must set persist-credentials to false in most cases for the deployment to work correctly.
|
uses: actions/checkout@v3
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
|
|
||||||
- name: Use Node.js
|
- name: Use Node.js
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: '16.x'
|
node-version: '16.x'
|
||||||
|
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: ~/.npm
|
path: ~/.npm
|
||||||
key: ${{ runner.os }}-node-${{ hashFiles('**/yarn.lock') }}
|
key: ${{ runner.os }}-node-${{ hashFiles('**/yarn.lock') }}
|
||||||
@ -26,7 +23,6 @@ jobs:
|
|||||||
${{ runner.os }}-node-
|
${{ runner.os }}-node-
|
||||||
|
|
||||||
- run: yarn install
|
- run: yarn install
|
||||||
- run: lerna bootstrap
|
|
||||||
- run: npm run build
|
- run: npm run build
|
||||||
working-directory: packages/dockview-core
|
working-directory: packages/dockview-core
|
||||||
- run: npm run build
|
- run: npm run build
|
||||||
|
4
.github/workflows/main.yml
vendored
4
.github/workflows/main.yml
vendored
@ -7,7 +7,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
# might be required for sonar to work correctly
|
# might be required for sonar to work correctly
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
|
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
|
||||||
@ -16,7 +16,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
node-version: '16.x'
|
node-version: '16.x'
|
||||||
|
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: ~/.npm
|
path: ~/.npm
|
||||||
key: ${{ runner.os }}-node-${{ hashFiles('**/yarn.lock') }}
|
key: ${{ runner.os }}-node-${{ hashFiles('**/yarn.lock') }}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"packages/*"
|
"packages/*"
|
||||||
],
|
],
|
||||||
"useWorkspaces": true,
|
"useWorkspaces": true,
|
||||||
"version": "1.7.3",
|
"version": "1.7.6",
|
||||||
"npmClient": "yarn",
|
"npmClient": "yarn",
|
||||||
"command": {
|
"command": {
|
||||||
"publish": {
|
"publish": {
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
"homepage": "https://github.com/mathuo/dockview#readme",
|
"homepage": "https://github.com/mathuo/dockview#readme",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@testing-library/dom": "^8.20.0",
|
"@testing-library/dom": "^8.20.0",
|
||||||
|
"@testing-library/jest-dom": "^5.16.5",
|
||||||
"@types/jest": "^29.4.0",
|
"@types/jest": "^29.4.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.52.0",
|
"@typescript-eslint/eslint-plugin": "^5.52.0",
|
||||||
"@typescript-eslint/parser": "^5.52.0",
|
"@typescript-eslint/parser": "^5.52.0",
|
||||||
@ -58,8 +59,8 @@
|
|||||||
"style-loader": "^3.3.1",
|
"style-loader": "^3.3.1",
|
||||||
"ts-jest": "^29.0.5",
|
"ts-jest": "^29.0.5",
|
||||||
"ts-loader": "^9.4.2",
|
"ts-loader": "^9.4.2",
|
||||||
"tslib": "^2.5.0",
|
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
|
"tslib": "^2.5.0",
|
||||||
"typedoc": "^0.24.7",
|
"typedoc": "^0.24.7",
|
||||||
"typescript": "^4.9.5",
|
"typescript": "^4.9.5",
|
||||||
"webpack": "^5.75.0",
|
"webpack": "^5.75.0",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "dockview-core",
|
"name": "dockview-core",
|
||||||
"version": "1.7.3",
|
"version": "1.7.6",
|
||||||
"description": "Zero dependency layout manager supporting tabs, grids and splitviews with ReactJS support",
|
"description": "Zero dependency layout manager supporting tabs, grids and splitviews with ReactJS support",
|
||||||
"main": "./dist/cjs/index.js",
|
"main": "./dist/cjs/index.js",
|
||||||
"types": "./dist/cjs/index.d.ts",
|
"types": "./dist/cjs/index.d.ts",
|
||||||
|
@ -2,10 +2,10 @@ import { IDockviewPanelModel } from '../../dockview/dockviewPanelModel';
|
|||||||
import { DockviewGroupPanel } from '../../dockview/dockviewGroupPanel';
|
import { DockviewGroupPanel } from '../../dockview/dockviewGroupPanel';
|
||||||
import {
|
import {
|
||||||
GroupPanelPartInitParameters,
|
GroupPanelPartInitParameters,
|
||||||
GroupPanelUpdateEvent,
|
|
||||||
IContentRenderer,
|
IContentRenderer,
|
||||||
ITabRenderer,
|
ITabRenderer,
|
||||||
} from '../../dockview/types';
|
} from '../../dockview/types';
|
||||||
|
import { PanelUpdateEvent } from '../../panel/types';
|
||||||
|
|
||||||
export class DockviewPanelModelMock implements IDockviewPanelModel {
|
export class DockviewPanelModelMock implements IDockviewPanelModel {
|
||||||
constructor(
|
constructor(
|
||||||
@ -21,7 +21,14 @@ export class DockviewPanelModelMock implements IDockviewPanelModel {
|
|||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
update(event: GroupPanelUpdateEvent): void {
|
updateParentGroup(
|
||||||
|
group: DockviewGroupPanel,
|
||||||
|
isPanelVisible: boolean
|
||||||
|
): void {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
update(event: PanelUpdateEvent): void {
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { PanelApiImpl } from '../../api/panelApi';
|
import { PanelApiImpl } from '../../api/panelApi';
|
||||||
|
import { IPanel } from '../../panel/types';
|
||||||
|
|
||||||
describe('api', () => {
|
describe('api', () => {
|
||||||
let api: PanelApiImpl;
|
let api: PanelApiImpl;
|
||||||
@ -7,7 +8,23 @@ describe('api', () => {
|
|||||||
api = new PanelApiImpl('dummy_id');
|
api = new PanelApiImpl('dummy_id');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update isFcoused getter', () => {
|
test('updateParameters', () => {
|
||||||
|
const panel = {
|
||||||
|
update: jest.fn(),
|
||||||
|
} as Partial<IPanel>;
|
||||||
|
|
||||||
|
api.initialize(panel as IPanel);
|
||||||
|
|
||||||
|
expect(panel.update).toHaveBeenCalledTimes(0);
|
||||||
|
|
||||||
|
api.updateParameters({ keyA: 'valueA' });
|
||||||
|
expect(panel.update).toHaveBeenCalledTimes(1);
|
||||||
|
expect(panel.update).toHaveBeenCalledWith({
|
||||||
|
params: { keyA: 'valueA' },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should update isFcoused getter', () => {
|
||||||
expect(api.isFocused).toBeFalsy();
|
expect(api.isFocused).toBeFalsy();
|
||||||
|
|
||||||
api._onDidChangeFocus.fire({ isFocused: true });
|
api._onDidChangeFocus.fire({ isFocused: true });
|
||||||
@ -17,7 +34,7 @@ describe('api', () => {
|
|||||||
expect(api.isFocused).toBeFalsy();
|
expect(api.isFocused).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update isActive getter', () => {
|
test('should update isActive getter', () => {
|
||||||
expect(api.isFocused).toBeFalsy();
|
expect(api.isFocused).toBeFalsy();
|
||||||
|
|
||||||
api._onDidActiveChange.fire({ isActive: true });
|
api._onDidActiveChange.fire({ isActive: true });
|
||||||
@ -27,7 +44,7 @@ describe('api', () => {
|
|||||||
expect(api.isActive).toBeFalsy();
|
expect(api.isActive).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update isActive getter', () => {
|
test('should update isActive getter', () => {
|
||||||
expect(api.isVisible).toBeTruthy();
|
expect(api.isVisible).toBeTruthy();
|
||||||
|
|
||||||
api._onDidVisibilityChange.fire({ isVisible: false });
|
api._onDidVisibilityChange.fire({ isVisible: false });
|
||||||
@ -37,7 +54,7 @@ describe('api', () => {
|
|||||||
expect(api.isVisible).toBeTruthy();
|
expect(api.isVisible).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update width and height getter', () => {
|
test('should update width and height getter', () => {
|
||||||
expect(api.height).toBe(0);
|
expect(api.height).toBe(0);
|
||||||
expect(api.width).toBe(0);
|
expect(api.width).toBe(0);
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { DockviewPanelApiImpl, TitleEvent } from '../../api/dockviewPanelApi';
|
import { DockviewPanelApiImpl } from '../../api/dockviewPanelApi';
|
||||||
import { DockviewComponent } from '../../dockview/dockviewComponent';
|
import { DockviewComponent } from '../../dockview/dockviewComponent';
|
||||||
import { DockviewPanel, IDockviewPanel } from '../../dockview/dockviewPanel';
|
import { DockviewPanel, IDockviewPanel } from '../../dockview/dockviewPanel';
|
||||||
import { DockviewGroupPanel } from '../../dockview/dockviewGroupPanel';
|
import { DockviewGroupPanel } from '../../dockview/dockviewGroupPanel';
|
||||||
@ -8,6 +8,7 @@ describe('groupPanelApi', () => {
|
|||||||
const panelMock = jest.fn<DockviewPanel, []>(() => {
|
const panelMock = jest.fn<DockviewPanel, []>(() => {
|
||||||
return {
|
return {
|
||||||
update: jest.fn(),
|
update: jest.fn(),
|
||||||
|
setTitle: jest.fn(),
|
||||||
} as any;
|
} as any;
|
||||||
});
|
});
|
||||||
const groupMock = jest.fn<DockviewGroupPanel, []>(() => {
|
const groupMock = jest.fn<DockviewGroupPanel, []>(() => {
|
||||||
@ -20,11 +21,38 @@ describe('groupPanelApi', () => {
|
|||||||
const cut = new DockviewPanelApiImpl(panel, group);
|
const cut = new DockviewPanelApiImpl(panel, group);
|
||||||
|
|
||||||
cut.setTitle('test_title');
|
cut.setTitle('test_title');
|
||||||
|
expect(panel.setTitle).toBeCalledTimes(1);
|
||||||
expect(panel.update).toBeCalledTimes(1);
|
expect(panel.setTitle).toBeCalledWith('test_title');
|
||||||
expect(panel.update).toBeCalledWith({
|
|
||||||
params: { title: 'test_title' },
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('updateParameters', () => {
|
||||||
|
const groupPanel: Partial<IDockviewPanel> = {
|
||||||
|
id: 'test_id',
|
||||||
|
update: jest.fn(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const accessor: Partial<DockviewComponent> = {
|
||||||
|
onDidAddPanel: jest.fn(),
|
||||||
|
onDidRemovePanel: jest.fn(),
|
||||||
|
options: {},
|
||||||
|
};
|
||||||
|
const groupViewPanel = new DockviewGroupPanel(
|
||||||
|
<DockviewComponent>accessor,
|
||||||
|
'',
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
|
||||||
|
const cut = new DockviewPanelApiImpl(
|
||||||
|
<IDockviewPanel>groupPanel,
|
||||||
|
<DockviewGroupPanel>groupViewPanel
|
||||||
|
);
|
||||||
|
|
||||||
|
cut.updateParameters({ keyA: 'valueA' });
|
||||||
|
|
||||||
|
expect(groupPanel.update).toHaveBeenCalledWith({
|
||||||
|
params: { keyA: 'valueA' },
|
||||||
|
});
|
||||||
|
expect(groupPanel.update).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('onDidGroupChange', () => {
|
test('onDidGroupChange', () => {
|
||||||
|
@ -20,10 +20,6 @@ describe('abstractDragHandler', () => {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
dispose(): void {
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
})(element);
|
})(element);
|
||||||
|
|
||||||
expect(element.classList.contains('dv-dragged')).toBeFalsy();
|
expect(element.classList.contains('dv-dragged')).toBeFalsy();
|
||||||
@ -62,10 +58,6 @@ describe('abstractDragHandler', () => {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
dispose(): void {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
})(element);
|
})(element);
|
||||||
|
|
||||||
expect(iframe.style.pointerEvents).toBeFalsy();
|
expect(iframe.style.pointerEvents).toBeFalsy();
|
||||||
@ -84,4 +76,46 @@ describe('abstractDragHandler', () => {
|
|||||||
|
|
||||||
handler.dispose();
|
handler.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('that the disabling of pointerEvents is restored on a premature disposal of the handler', () => {
|
||||||
|
jest.useFakeTimers();
|
||||||
|
|
||||||
|
const element = document.createElement('div');
|
||||||
|
const iframe = document.createElement('iframe');
|
||||||
|
const webview = document.createElement('webview');
|
||||||
|
const span = document.createElement('span');
|
||||||
|
|
||||||
|
document.body.appendChild(element);
|
||||||
|
document.body.appendChild(iframe);
|
||||||
|
document.body.appendChild(webview);
|
||||||
|
document.body.appendChild(span);
|
||||||
|
|
||||||
|
const handler = new (class TestClass extends DragHandler {
|
||||||
|
constructor(el: HTMLElement) {
|
||||||
|
super(el);
|
||||||
|
}
|
||||||
|
|
||||||
|
getData(): IDisposable {
|
||||||
|
return {
|
||||||
|
dispose: () => {
|
||||||
|
// /
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
})(element);
|
||||||
|
|
||||||
|
expect(iframe.style.pointerEvents).toBeFalsy();
|
||||||
|
expect(webview.style.pointerEvents).toBeFalsy();
|
||||||
|
expect(span.style.pointerEvents).toBeFalsy();
|
||||||
|
|
||||||
|
fireEvent.dragStart(element);
|
||||||
|
expect(iframe.style.pointerEvents).toBe('none');
|
||||||
|
expect(webview.style.pointerEvents).toBe('none');
|
||||||
|
expect(span.style.pointerEvents).toBeFalsy();
|
||||||
|
|
||||||
|
handler.dispose();
|
||||||
|
expect(iframe.style.pointerEvents).toBe('auto');
|
||||||
|
expect(webview.style.pointerEvents).toBe('auto');
|
||||||
|
expect(span.style.pointerEvents).toBeFalsy();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
import { fireEvent } from '@testing-library/dom';
|
import { fireEvent } from '@testing-library/dom';
|
||||||
import { Emitter, Event } from '../../../events';
|
import { Emitter, Event } from '../../../../events';
|
||||||
import { ContentContainer } from '../../../dockview/components/panel/content';
|
import { ContentContainer } from '../../../../dockview/components/panel/content';
|
||||||
import {
|
import {
|
||||||
GroupPanelContentPartInitParameters,
|
GroupPanelContentPartInitParameters,
|
||||||
IContentRenderer,
|
IContentRenderer,
|
||||||
} from '../../../dockview/types';
|
} from '../../../../dockview/types';
|
||||||
import { CompositeDisposable } from '../../../lifecycle';
|
import { CompositeDisposable } from '../../../../lifecycle';
|
||||||
import { PanelUpdateEvent } from '../../../panel/types';
|
import { PanelUpdateEvent } from '../../../../panel/types';
|
||||||
import { IDockviewPanel } from '../../../dockview/dockviewPanel';
|
import { IDockviewPanel } from '../../../../dockview/dockviewPanel';
|
||||||
import { IDockviewPanelModel } from '../../../dockview/dockviewPanelModel';
|
import { IDockviewPanelModel } from '../../../../dockview/dockviewPanelModel';
|
||||||
|
|
||||||
class TestContentRenderer
|
class TestContentRenderer
|
||||||
extends CompositeDisposable
|
extends CompositeDisposable
|
@ -1,9 +1,9 @@
|
|||||||
import { fireEvent } from '@testing-library/dom';
|
import { fireEvent } from '@testing-library/dom';
|
||||||
import { LocalSelectionTransfer, PanelTransfer } from '../../dnd/dataTransfer';
|
import { LocalSelectionTransfer, PanelTransfer } from '../../../dnd/dataTransfer';
|
||||||
import { DockviewComponent } from '../../dockview/dockviewComponent';
|
import { DockviewComponent } from '../../../dockview/dockviewComponent';
|
||||||
import { DockviewGroupPanel } from '../../dockview/dockviewGroupPanel';
|
import { DockviewGroupPanel } from '../../../dockview/dockviewGroupPanel';
|
||||||
import { DockviewGroupPanelModel } from '../../dockview/dockviewGroupPanelModel';
|
import { DockviewGroupPanelModel } from '../../../dockview/dockviewGroupPanelModel';
|
||||||
import { Tab } from '../../dockview/components/tab/tab';
|
import { Tab } from '../../../dockview/components/tab/tab';
|
||||||
|
|
||||||
describe('tab', () => {
|
describe('tab', () => {
|
||||||
test('that empty tab has inactive-tab class', () => {
|
test('that empty tab has inactive-tab class', () => {
|
@ -1,13 +1,13 @@
|
|||||||
import { DockviewComponent } from '../../../dockview/dockviewComponent';
|
|
||||||
import { TabsContainer } from '../../../dockview/components/titlebar/tabsContainer';
|
|
||||||
import { fireEvent } from '@testing-library/dom';
|
|
||||||
import {
|
import {
|
||||||
LocalSelectionTransfer,
|
LocalSelectionTransfer,
|
||||||
PanelTransfer,
|
PanelTransfer,
|
||||||
} from '../../../dnd/dataTransfer';
|
} from '../../../../dnd/dataTransfer';
|
||||||
import { TestPanel } from '../dockviewGroupPanelModel.spec';
|
import { TabsContainer } from '../../../../dockview/components/titlebar/tabsContainer';
|
||||||
import { DockviewGroupPanelModel } from '../../../dockview/dockviewGroupPanelModel';
|
import { DockviewComponent } from '../../../../dockview/dockviewComponent';
|
||||||
import { DockviewGroupPanel } from '../../../dockview/dockviewGroupPanel';
|
import { DockviewGroupPanel } from '../../../../dockview/dockviewGroupPanel';
|
||||||
|
import { DockviewGroupPanelModel } from '../../../../dockview/dockviewGroupPanelModel';
|
||||||
|
import { fireEvent } from '@testing-library/dom';
|
||||||
|
import { TestPanel } from '../../dockviewGroupPanelModel.spec';
|
||||||
|
|
||||||
describe('tabsContainer', () => {
|
describe('tabsContainer', () => {
|
||||||
test('that an external event does not render a drop target and calls through to the group mode', () => {
|
test('that an external event does not render a drop target and calls through to the group mode', () => {
|
||||||
@ -331,4 +331,136 @@ describe('tabsContainer', () => {
|
|||||||
cut.element.getElementsByClassName('drop-target-dropzone').length
|
cut.element.getElementsByClassName('drop-target-dropzone').length
|
||||||
).toBe(0);
|
).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('left actions', () => {
|
||||||
|
const accessorMock = jest.fn<DockviewComponent, []>(() => {
|
||||||
|
return (<Partial<DockviewComponent>>{
|
||||||
|
options: {},
|
||||||
|
onDidAddPanel: jest.fn(),
|
||||||
|
onDidRemovePanel: jest.fn(),
|
||||||
|
}) as DockviewComponent;
|
||||||
|
});
|
||||||
|
|
||||||
|
const groupPanelMock = jest.fn<DockviewGroupPanel, []>(() => {
|
||||||
|
return (<Partial<DockviewGroupPanel>>{}) as DockviewGroupPanel;
|
||||||
|
});
|
||||||
|
|
||||||
|
const accessor = new accessorMock();
|
||||||
|
const groupPanel = new groupPanelMock();
|
||||||
|
|
||||||
|
const cut = new TabsContainer(accessor, groupPanel);
|
||||||
|
|
||||||
|
let query = cut.element.querySelectorAll(
|
||||||
|
'.tabs-and-actions-container > .left-actions-container'
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(query.length).toBe(1);
|
||||||
|
expect(query[0].children.length).toBe(0);
|
||||||
|
|
||||||
|
// add left action
|
||||||
|
|
||||||
|
const left = document.createElement('div');
|
||||||
|
left.className = 'test-left-actions-element';
|
||||||
|
cut.setLeftActionsElement(left);
|
||||||
|
|
||||||
|
query = cut.element.querySelectorAll(
|
||||||
|
'.tabs-and-actions-container > .left-actions-container'
|
||||||
|
);
|
||||||
|
expect(query.length).toBe(1);
|
||||||
|
expect(query[0].children.item(0)?.className).toBe(
|
||||||
|
'test-left-actions-element'
|
||||||
|
);
|
||||||
|
expect(query[0].children.length).toBe(1);
|
||||||
|
|
||||||
|
// add left action
|
||||||
|
|
||||||
|
const left2 = document.createElement('div');
|
||||||
|
left2.className = 'test-left-actions-element-2';
|
||||||
|
cut.setLeftActionsElement(left2);
|
||||||
|
|
||||||
|
query = cut.element.querySelectorAll(
|
||||||
|
'.tabs-and-actions-container > .left-actions-container'
|
||||||
|
);
|
||||||
|
expect(query.length).toBe(1);
|
||||||
|
expect(query[0].children.item(0)?.className).toBe(
|
||||||
|
'test-left-actions-element-2'
|
||||||
|
);
|
||||||
|
expect(query[0].children.length).toBe(1);
|
||||||
|
|
||||||
|
// remove left action
|
||||||
|
|
||||||
|
cut.setLeftActionsElement(undefined);
|
||||||
|
query = cut.element.querySelectorAll(
|
||||||
|
'.tabs-and-actions-container > .left-actions-container'
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(query.length).toBe(1);
|
||||||
|
expect(query[0].children.length).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('right actions', () => {
|
||||||
|
const accessorMock = jest.fn<DockviewComponent, []>(() => {
|
||||||
|
return (<Partial<DockviewComponent>>{
|
||||||
|
options: {},
|
||||||
|
onDidAddPanel: jest.fn(),
|
||||||
|
onDidRemovePanel: jest.fn(),
|
||||||
|
}) as DockviewComponent;
|
||||||
|
});
|
||||||
|
|
||||||
|
const groupPanelMock = jest.fn<DockviewGroupPanel, []>(() => {
|
||||||
|
return (<Partial<DockviewGroupPanel>>{}) as DockviewGroupPanel;
|
||||||
|
});
|
||||||
|
|
||||||
|
const accessor = new accessorMock();
|
||||||
|
const groupPanel = new groupPanelMock();
|
||||||
|
|
||||||
|
const cut = new TabsContainer(accessor, groupPanel);
|
||||||
|
|
||||||
|
let query = cut.element.querySelectorAll(
|
||||||
|
'.tabs-and-actions-container > .right-actions-container'
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(query.length).toBe(1);
|
||||||
|
expect(query[0].children.length).toBe(0);
|
||||||
|
|
||||||
|
// add right action
|
||||||
|
|
||||||
|
const right = document.createElement('div');
|
||||||
|
right.className = 'test-right-actions-element';
|
||||||
|
cut.setRightActionsElement(right);
|
||||||
|
|
||||||
|
query = cut.element.querySelectorAll(
|
||||||
|
'.tabs-and-actions-container > .right-actions-container'
|
||||||
|
);
|
||||||
|
expect(query.length).toBe(1);
|
||||||
|
expect(query[0].children.item(0)?.className).toBe(
|
||||||
|
'test-right-actions-element'
|
||||||
|
);
|
||||||
|
expect(query[0].children.length).toBe(1);
|
||||||
|
|
||||||
|
// add right action
|
||||||
|
|
||||||
|
const right2 = document.createElement('div');
|
||||||
|
right2.className = 'test-right-actions-element-2';
|
||||||
|
cut.setRightActionsElement(right2);
|
||||||
|
|
||||||
|
query = cut.element.querySelectorAll(
|
||||||
|
'.tabs-and-actions-container > .right-actions-container'
|
||||||
|
);
|
||||||
|
expect(query.length).toBe(1);
|
||||||
|
expect(query[0].children.item(0)?.className).toBe(
|
||||||
|
'test-right-actions-element-2'
|
||||||
|
);
|
||||||
|
expect(query[0].children.length).toBe(1);
|
||||||
|
|
||||||
|
// remove right action
|
||||||
|
|
||||||
|
cut.setRightActionsElement(undefined);
|
||||||
|
query = cut.element.querySelectorAll(
|
||||||
|
'.tabs-and-actions-container > .right-actions-container'
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(query.length).toBe(1);
|
||||||
|
expect(query[0].children.length).toBe(0);
|
||||||
|
});
|
||||||
});
|
});
|
@ -541,6 +541,8 @@ describe('dockviewComponent', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// dockview.layout(1000, 1000, true);
|
||||||
|
|
||||||
expect(JSON.parse(JSON.stringify(dockview.toJSON()))).toEqual({
|
expect(JSON.parse(JSON.stringify(dockview.toJSON()))).toEqual({
|
||||||
activeGroup: 'group-1',
|
activeGroup: 'group-1',
|
||||||
grid: {
|
grid: {
|
||||||
@ -1723,6 +1725,9 @@ describe('dockviewComponent', () => {
|
|||||||
test_tab_id: PanelTabPartTest,
|
test_tab_id: PanelTabPartTest,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
dockview.layout(1000, 1000);
|
||||||
|
|
||||||
dockview.fromJSON({
|
dockview.fromJSON({
|
||||||
activeGroup: 'group-1',
|
activeGroup: 'group-1',
|
||||||
grid: {
|
grid: {
|
||||||
@ -1918,6 +1923,8 @@ describe('dockviewComponent', () => {
|
|||||||
orientation: Orientation.HORIZONTAL,
|
orientation: Orientation.HORIZONTAL,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
dockview.layout(1000, 1000);
|
||||||
|
|
||||||
expect(dockview.orientation).toBe(Orientation.HORIZONTAL);
|
expect(dockview.orientation).toBe(Orientation.HORIZONTAL);
|
||||||
|
|
||||||
dockview.fromJSON({
|
dockview.fromJSON({
|
||||||
@ -2023,6 +2030,8 @@ describe('dockviewComponent', () => {
|
|||||||
orientation: Orientation.HORIZONTAL,
|
orientation: Orientation.HORIZONTAL,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
dockview.layout(1000, 1000);
|
||||||
|
|
||||||
expect(dockview.orientation).toBe(Orientation.HORIZONTAL);
|
expect(dockview.orientation).toBe(Orientation.HORIZONTAL);
|
||||||
|
|
||||||
dockview.fromJSON({
|
dockview.fromJSON({
|
||||||
@ -2163,6 +2172,8 @@ describe('dockviewComponent', () => {
|
|||||||
orientation: Orientation.HORIZONTAL,
|
orientation: Orientation.HORIZONTAL,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
dockview.layout(1000, 1000);
|
||||||
|
|
||||||
expect(dockview.orientation).toBe(Orientation.HORIZONTAL);
|
expect(dockview.orientation).toBe(Orientation.HORIZONTAL);
|
||||||
|
|
||||||
dockview.fromJSON({
|
dockview.fromJSON({
|
||||||
@ -2448,4 +2459,164 @@ describe('dockviewComponent', () => {
|
|||||||
activeGroup: '1',
|
activeGroup: '1',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('check dockview component is rendering to the DOM as expected', () => {
|
||||||
|
const container = document.createElement('div');
|
||||||
|
|
||||||
|
const dockview = new DockviewComponent({
|
||||||
|
parentElement: container,
|
||||||
|
components: {
|
||||||
|
default: PanelContentPartTest,
|
||||||
|
},
|
||||||
|
tabComponents: {
|
||||||
|
test_tab_id: PanelTabPartTest,
|
||||||
|
},
|
||||||
|
orientation: Orientation.HORIZONTAL,
|
||||||
|
});
|
||||||
|
|
||||||
|
dockview.layout(100, 100);
|
||||||
|
|
||||||
|
const panel1 = dockview.addPanel({
|
||||||
|
id: 'panel1',
|
||||||
|
component: 'default',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(dockview.element.querySelectorAll('.view').length).toBe(1);
|
||||||
|
|
||||||
|
const panel2 = dockview.addPanel({
|
||||||
|
id: 'panel2',
|
||||||
|
component: 'default',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(dockview.element.querySelectorAll('.view').length).toBe(1);
|
||||||
|
|
||||||
|
const panel3 = dockview.addPanel({
|
||||||
|
id: 'panel3',
|
||||||
|
component: 'default',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(dockview.element.querySelectorAll('.view').length).toBe(1);
|
||||||
|
|
||||||
|
dockview.moveGroupOrPanel(
|
||||||
|
panel3.group,
|
||||||
|
panel3.group.id,
|
||||||
|
panel3.id,
|
||||||
|
'right'
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(dockview.groups.length).toBe(2);
|
||||||
|
expect(dockview.element.querySelectorAll('.view').length).toBe(2);
|
||||||
|
|
||||||
|
dockview.moveGroupOrPanel(
|
||||||
|
panel3.group,
|
||||||
|
panel2.group.id,
|
||||||
|
panel2.id,
|
||||||
|
'bottom'
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(dockview.groups.length).toBe(3);
|
||||||
|
expect(dockview.element.querySelectorAll('.view').length).toBe(4);
|
||||||
|
|
||||||
|
dockview.moveGroupOrPanel(
|
||||||
|
panel2.group,
|
||||||
|
panel1.group.id,
|
||||||
|
panel1.id,
|
||||||
|
'center'
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(dockview.groups.length).toBe(2);
|
||||||
|
|
||||||
|
expect(dockview.element.querySelectorAll('.view').length).toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('that fromJSON layouts are resized to the current dimensions', async () => {
|
||||||
|
const container = document.createElement('div');
|
||||||
|
|
||||||
|
const dockview = new DockviewComponent({
|
||||||
|
parentElement: container,
|
||||||
|
components: {
|
||||||
|
default: PanelContentPartTest,
|
||||||
|
},
|
||||||
|
tabComponents: {
|
||||||
|
test_tab_id: PanelTabPartTest,
|
||||||
|
},
|
||||||
|
orientation: Orientation.HORIZONTAL,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(dockview.orientation).toBe(Orientation.HORIZONTAL);
|
||||||
|
|
||||||
|
dockview.layout(1000, 500);
|
||||||
|
|
||||||
|
dockview.fromJSON({
|
||||||
|
activeGroup: 'group-1',
|
||||||
|
grid: {
|
||||||
|
root: {
|
||||||
|
type: 'branch',
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
type: 'leaf',
|
||||||
|
data: {
|
||||||
|
views: ['panel1', 'panel2'],
|
||||||
|
id: 'group-1',
|
||||||
|
activeView: 'panel2',
|
||||||
|
},
|
||||||
|
size: 2000,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
size: 1000,
|
||||||
|
},
|
||||||
|
height: 1000,
|
||||||
|
width: 2000,
|
||||||
|
orientation: Orientation.HORIZONTAL,
|
||||||
|
},
|
||||||
|
panels: {
|
||||||
|
panel1: {
|
||||||
|
id: 'panel1',
|
||||||
|
contentComponent: 'default',
|
||||||
|
title: 'panel1',
|
||||||
|
},
|
||||||
|
panel2: {
|
||||||
|
id: 'panel2',
|
||||||
|
contentComponent: 'default',
|
||||||
|
title: 'panel2',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(JSON.parse(JSON.stringify(dockview.toJSON()))).toEqual({
|
||||||
|
activeGroup: 'group-1',
|
||||||
|
grid: {
|
||||||
|
root: {
|
||||||
|
type: 'branch',
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
type: 'leaf',
|
||||||
|
data: {
|
||||||
|
views: ['panel1', 'panel2'],
|
||||||
|
id: 'group-1',
|
||||||
|
activeView: 'panel2',
|
||||||
|
},
|
||||||
|
size: 1000,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
size: 500,
|
||||||
|
},
|
||||||
|
height: 500,
|
||||||
|
width: 1000,
|
||||||
|
orientation: Orientation.HORIZONTAL,
|
||||||
|
},
|
||||||
|
panels: {
|
||||||
|
panel1: {
|
||||||
|
id: 'panel1',
|
||||||
|
contentComponent: 'default',
|
||||||
|
title: 'panel1',
|
||||||
|
},
|
||||||
|
panel2: {
|
||||||
|
id: 'panel2',
|
||||||
|
contentComponent: 'default',
|
||||||
|
title: 'panel2',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { DockviewComponent } from '../../dockview/dockviewComponent';
|
import { DockviewComponent } from '../../dockview/dockviewComponent';
|
||||||
import {
|
import {
|
||||||
GroupPanelUpdateEvent,
|
|
||||||
GroupviewPanelState,
|
GroupviewPanelState,
|
||||||
IGroupPanelInitParameters,
|
IGroupPanelInitParameters,
|
||||||
GroupPanelPartInitParameters,
|
GroupPanelPartInitParameters,
|
||||||
@ -39,7 +38,7 @@ class TestModel implements IDockviewPanelModel {
|
|||||||
this.tab = new TestContentPart(id);
|
this.tab = new TestContentPart(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
update(event: GroupPanelUpdateEvent): void {
|
update(event: PanelUpdateEvent): void {
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,6 +202,10 @@ export class TestPanel implements IDockviewPanel {
|
|||||||
//noop
|
//noop
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setTitle(title: string): void {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
update(event: PanelUpdateEvent) {
|
update(event: PanelUpdateEvent) {
|
||||||
//noop
|
//noop
|
||||||
}
|
}
|
@ -43,7 +43,7 @@ describe('dockviewPanel', () => {
|
|||||||
expect(latestTitle).toBe('new title');
|
expect(latestTitle).toBe('new title');
|
||||||
expect(cut.title).toBe('new title');
|
expect(cut.title).toBe('new title');
|
||||||
|
|
||||||
cut.update({ params: { title: 'another title' } });
|
cut.setTitle('another title');
|
||||||
expect(latestTitle).toBe('another title');
|
expect(latestTitle).toBe('another title');
|
||||||
expect(cut.title).toBe('another title');
|
expect(cut.title).toBe('another title');
|
||||||
|
|
||||||
@ -81,6 +81,9 @@ describe('dockviewPanel', () => {
|
|||||||
|
|
||||||
cut.setTitle('newTitle');
|
cut.setTitle('newTitle');
|
||||||
expect(cut.title).toBe('newTitle');
|
expect(cut.title).toBe('newTitle');
|
||||||
|
|
||||||
|
cut.api.setTitle('new title 2');
|
||||||
|
expect(cut.title).toBe('new title 2');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('dispose cleanup', () => {
|
test('dispose cleanup', () => {
|
||||||
@ -142,7 +145,7 @@ describe('dockviewPanel', () => {
|
|||||||
|
|
||||||
expect(cut.params).toEqual(undefined);
|
expect(cut.params).toEqual(undefined);
|
||||||
|
|
||||||
cut.update({ params: { params: { variableA: 'A', variableB: 'B' } } });
|
cut.update({ params: { variableA: 'A', variableB: 'B' } });
|
||||||
|
|
||||||
expect(cut.params).toEqual({ variableA: 'A', variableB: 'B' });
|
expect(cut.params).toEqual({ variableA: 'A', variableB: 'B' });
|
||||||
});
|
});
|
||||||
@ -181,4 +184,67 @@ describe('dockviewPanel', () => {
|
|||||||
expect(group.api.setSize).toBeCalledWith({ height: 123, width: 456 });
|
expect(group.api.setSize).toBeCalledWith({ height: 123, width: 456 });
|
||||||
expect(group.api.setSize).toBeCalledTimes(1);
|
expect(group.api.setSize).toBeCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('updateParameter', () => {
|
||||||
|
const dockviewApiMock = jest.fn<DockviewApi, []>(() => {
|
||||||
|
return {} as any;
|
||||||
|
});
|
||||||
|
const accessorMock = jest.fn<DockviewComponent, []>(() => {
|
||||||
|
return {} as any;
|
||||||
|
});
|
||||||
|
const groupMock = jest.fn<DockviewGroupPanel, []>(() => {
|
||||||
|
return {} as any;
|
||||||
|
});
|
||||||
|
const panelModelMock = jest.fn<Partial<IDockviewPanelModel>, []>(() => {
|
||||||
|
return {
|
||||||
|
update: jest.fn(),
|
||||||
|
init: jest.fn(),
|
||||||
|
dispose: jest.fn(),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const api = new dockviewApiMock();
|
||||||
|
const accessor = new accessorMock();
|
||||||
|
const group = new groupMock();
|
||||||
|
const model = <IDockviewPanelModel>new panelModelMock();
|
||||||
|
|
||||||
|
const cut = new DockviewPanel('fake-id', accessor, api, group, model);
|
||||||
|
|
||||||
|
cut.init({ params: { a: '1', b: '2' }, title: 'A title' });
|
||||||
|
expect(cut.params).toEqual({ a: '1', b: '2' });
|
||||||
|
|
||||||
|
// update 'a' and add 'c'
|
||||||
|
cut.update({ params: { a: '-1', c: '3' } });
|
||||||
|
expect(cut.params).toEqual({ a: '-1', b: '2', c: '3' });
|
||||||
|
|
||||||
|
cut.update({ params: { d: '4', e: '5', f: '6' } });
|
||||||
|
expect(cut.params).toEqual({
|
||||||
|
a: '-1',
|
||||||
|
b: '2',
|
||||||
|
c: '3',
|
||||||
|
d: '4',
|
||||||
|
e: '5',
|
||||||
|
f: '6',
|
||||||
|
});
|
||||||
|
|
||||||
|
cut.update({
|
||||||
|
params: {
|
||||||
|
d: '',
|
||||||
|
e: null,
|
||||||
|
f: undefined,
|
||||||
|
g: '',
|
||||||
|
h: null,
|
||||||
|
i: undefined,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(cut.params).toEqual({
|
||||||
|
a: '-1',
|
||||||
|
b: '2',
|
||||||
|
c: '3',
|
||||||
|
d: '',
|
||||||
|
e: null,
|
||||||
|
g: '',
|
||||||
|
h: null,
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,16 @@
|
|||||||
import { Emitter, Event } from '../events';
|
import {
|
||||||
|
Emitter,
|
||||||
|
Event,
|
||||||
|
addDisposableListener,
|
||||||
|
addDisposableWindowListener,
|
||||||
|
} from '../events';
|
||||||
|
|
||||||
describe('events', () => {
|
describe('events', () => {
|
||||||
describe('emitter', () => {
|
describe('emitter', () => {
|
||||||
|
it('debug mode is off', () => {
|
||||||
|
expect(Emitter.ENABLE_TRACKING).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
it('should emit values', () => {
|
it('should emit values', () => {
|
||||||
const emitter = new Emitter<number>();
|
const emitter = new Emitter<number>();
|
||||||
let value: number | undefined = undefined;
|
let value: number | undefined = undefined;
|
||||||
@ -97,4 +106,138 @@ describe('events', () => {
|
|||||||
emitter3.fire(3);
|
emitter3.fire(3);
|
||||||
expect(value).toBe(3);
|
expect(value).toBe(3);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('addDisposableWindowListener with capture options', () => {
|
||||||
|
const element = {
|
||||||
|
addEventListener: jest.fn(),
|
||||||
|
removeEventListener: jest.fn(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const handler = jest.fn();
|
||||||
|
|
||||||
|
const disposable = addDisposableWindowListener(
|
||||||
|
element as any,
|
||||||
|
'mousedown',
|
||||||
|
handler,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(element.addEventListener).toBeCalledTimes(1);
|
||||||
|
expect(element.addEventListener).toHaveBeenCalledWith(
|
||||||
|
'mousedown',
|
||||||
|
handler,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
expect(element.removeEventListener).toBeCalledTimes(0);
|
||||||
|
|
||||||
|
disposable.dispose();
|
||||||
|
|
||||||
|
expect(element.addEventListener).toBeCalledTimes(1);
|
||||||
|
expect(element.removeEventListener).toBeCalledTimes(1);
|
||||||
|
expect(element.removeEventListener).toBeCalledWith(
|
||||||
|
'mousedown',
|
||||||
|
handler,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('addDisposableWindowListener without capture options', () => {
|
||||||
|
const element = {
|
||||||
|
addEventListener: jest.fn(),
|
||||||
|
removeEventListener: jest.fn(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const handler = jest.fn();
|
||||||
|
|
||||||
|
const disposable = addDisposableWindowListener(
|
||||||
|
element as any,
|
||||||
|
'mousedown',
|
||||||
|
handler
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(element.addEventListener).toBeCalledTimes(1);
|
||||||
|
expect(element.addEventListener).toHaveBeenCalledWith(
|
||||||
|
'mousedown',
|
||||||
|
handler,
|
||||||
|
undefined
|
||||||
|
);
|
||||||
|
expect(element.removeEventListener).toBeCalledTimes(0);
|
||||||
|
|
||||||
|
disposable.dispose();
|
||||||
|
|
||||||
|
expect(element.addEventListener).toBeCalledTimes(1);
|
||||||
|
expect(element.removeEventListener).toBeCalledTimes(1);
|
||||||
|
expect(element.removeEventListener).toBeCalledWith(
|
||||||
|
'mousedown',
|
||||||
|
handler,
|
||||||
|
undefined
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('addDisposableListener with capture options', () => {
|
||||||
|
const element = {
|
||||||
|
addEventListener: jest.fn(),
|
||||||
|
removeEventListener: jest.fn(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const handler = jest.fn();
|
||||||
|
|
||||||
|
const disposable = addDisposableListener(
|
||||||
|
element as any,
|
||||||
|
'mousedown',
|
||||||
|
handler,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(element.addEventListener).toBeCalledTimes(1);
|
||||||
|
expect(element.addEventListener).toHaveBeenCalledWith(
|
||||||
|
'mousedown',
|
||||||
|
handler,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
expect(element.removeEventListener).toBeCalledTimes(0);
|
||||||
|
|
||||||
|
disposable.dispose();
|
||||||
|
|
||||||
|
expect(element.addEventListener).toBeCalledTimes(1);
|
||||||
|
expect(element.removeEventListener).toBeCalledTimes(1);
|
||||||
|
expect(element.removeEventListener).toBeCalledWith(
|
||||||
|
'mousedown',
|
||||||
|
handler,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('addDisposableListener without capture options', () => {
|
||||||
|
const element = {
|
||||||
|
addEventListener: jest.fn(),
|
||||||
|
removeEventListener: jest.fn(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const handler = jest.fn();
|
||||||
|
|
||||||
|
const disposable = addDisposableListener(
|
||||||
|
element as any,
|
||||||
|
'mousedown',
|
||||||
|
handler
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(element.addEventListener).toBeCalledTimes(1);
|
||||||
|
expect(element.addEventListener).toHaveBeenCalledWith(
|
||||||
|
'mousedown',
|
||||||
|
handler,
|
||||||
|
undefined
|
||||||
|
);
|
||||||
|
expect(element.removeEventListener).toBeCalledTimes(0);
|
||||||
|
|
||||||
|
disposable.dispose();
|
||||||
|
|
||||||
|
expect(element.addEventListener).toBeCalledTimes(1);
|
||||||
|
expect(element.removeEventListener).toBeCalledTimes(1);
|
||||||
|
expect(element.removeEventListener).toBeCalledWith(
|
||||||
|
'mousedown',
|
||||||
|
handler,
|
||||||
|
undefined
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -18,6 +18,10 @@ class MockGridview implements IGridView {
|
|||||||
>().event;
|
>().event;
|
||||||
element: HTMLElement = document.createElement('div');
|
element: HTMLElement = document.createElement('div');
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.element.className = 'mock-grid-view';
|
||||||
|
}
|
||||||
|
|
||||||
layout(width: number, height: number): void {
|
layout(width: number, height: number): void {
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
@ -116,4 +120,574 @@ describe('gridview', () => {
|
|||||||
|
|
||||||
checkOrientationFlipsAtEachLevel((gridview as any).root as BranchNode);
|
checkOrientationFlipsAtEachLevel((gridview as any).root as BranchNode);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('removeView: remove leaf from branch where branch becomes leaf and parent is root', () => {
|
||||||
|
const gridview = new Gridview(
|
||||||
|
false,
|
||||||
|
{ separatorBorder: '' },
|
||||||
|
Orientation.HORIZONTAL
|
||||||
|
);
|
||||||
|
gridview.layout(1000, 1000);
|
||||||
|
|
||||||
|
gridview.addView(new MockGridview(), Sizing.Distribute, [0]);
|
||||||
|
gridview.addView(new MockGridview(), Sizing.Distribute, [1]);
|
||||||
|
|
||||||
|
gridview.addView(new MockGridview(), Sizing.Distribute, [1, 0]);
|
||||||
|
|
||||||
|
expect(gridview.serialize()).toEqual({
|
||||||
|
height: 1000,
|
||||||
|
orientation: 'HORIZONTAL',
|
||||||
|
root: {
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
data: {},
|
||||||
|
size: 500,
|
||||||
|
type: 'leaf',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
data: {},
|
||||||
|
size: 500,
|
||||||
|
type: 'leaf',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: {},
|
||||||
|
size: 500,
|
||||||
|
type: 'leaf',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
size: 500,
|
||||||
|
type: 'branch',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
size: 1000,
|
||||||
|
type: 'branch',
|
||||||
|
},
|
||||||
|
width: 1000,
|
||||||
|
});
|
||||||
|
expect(
|
||||||
|
gridview.element.querySelectorAll('.mock-grid-view').length
|
||||||
|
).toBe(3);
|
||||||
|
|
||||||
|
gridview.removeView([1, 0], Sizing.Distribute);
|
||||||
|
|
||||||
|
expect(gridview.serialize()).toEqual({
|
||||||
|
height: 1000,
|
||||||
|
orientation: 'HORIZONTAL',
|
||||||
|
root: {
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
data: {},
|
||||||
|
size: 500,
|
||||||
|
type: 'leaf',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: {},
|
||||||
|
size: 500,
|
||||||
|
type: 'leaf',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
size: 1000,
|
||||||
|
type: 'branch',
|
||||||
|
},
|
||||||
|
width: 1000,
|
||||||
|
});
|
||||||
|
expect(
|
||||||
|
gridview.element.querySelectorAll('.mock-grid-view').length
|
||||||
|
).toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('removeView: remove leaf from branch where branch remains branch and parent is root', () => {
|
||||||
|
const gridview = new Gridview(
|
||||||
|
false,
|
||||||
|
{ separatorBorder: '' },
|
||||||
|
Orientation.HORIZONTAL
|
||||||
|
);
|
||||||
|
gridview.layout(1000, 1000);
|
||||||
|
|
||||||
|
gridview.addView(new MockGridview(), Sizing.Distribute, [0]);
|
||||||
|
gridview.addView(new MockGridview(), Sizing.Distribute, [1]);
|
||||||
|
|
||||||
|
gridview.addView(new MockGridview(), Sizing.Distribute, [1, 0]);
|
||||||
|
gridview.addView(new MockGridview(), Sizing.Distribute, [1, 1]);
|
||||||
|
|
||||||
|
expect(gridview.serialize()).toEqual({
|
||||||
|
height: 1000,
|
||||||
|
orientation: 'HORIZONTAL',
|
||||||
|
root: {
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
data: {},
|
||||||
|
size: 500,
|
||||||
|
type: 'leaf',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
data: {},
|
||||||
|
size: 333,
|
||||||
|
type: 'leaf',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: {},
|
||||||
|
size: 333,
|
||||||
|
type: 'leaf',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: {},
|
||||||
|
size: 334,
|
||||||
|
type: 'leaf',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
size: 500,
|
||||||
|
type: 'branch',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
size: 1000,
|
||||||
|
type: 'branch',
|
||||||
|
},
|
||||||
|
width: 1000,
|
||||||
|
});
|
||||||
|
expect(
|
||||||
|
gridview.element.querySelectorAll('.mock-grid-view').length
|
||||||
|
).toBe(4);
|
||||||
|
|
||||||
|
gridview.removeView([1, 0], Sizing.Distribute);
|
||||||
|
|
||||||
|
expect(gridview.serialize()).toEqual({
|
||||||
|
height: 1000,
|
||||||
|
orientation: 'HORIZONTAL',
|
||||||
|
root: {
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
data: {},
|
||||||
|
size: 500,
|
||||||
|
type: 'leaf',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
data: {},
|
||||||
|
size: 500,
|
||||||
|
type: 'leaf',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: {},
|
||||||
|
size: 500,
|
||||||
|
type: 'leaf',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
size: 500,
|
||||||
|
type: 'branch',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
size: 1000,
|
||||||
|
type: 'branch',
|
||||||
|
},
|
||||||
|
width: 1000,
|
||||||
|
});
|
||||||
|
expect(
|
||||||
|
gridview.element.querySelectorAll('.mock-grid-view').length
|
||||||
|
).toBe(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('removeView: remove leaf where parent is root', () => {
|
||||||
|
const gridview = new Gridview(
|
||||||
|
false,
|
||||||
|
{ separatorBorder: '' },
|
||||||
|
Orientation.HORIZONTAL
|
||||||
|
);
|
||||||
|
gridview.layout(1000, 1000);
|
||||||
|
|
||||||
|
gridview.addView(new MockGridview(), Sizing.Distribute, [0]);
|
||||||
|
gridview.addView(new MockGridview(), Sizing.Distribute, [1]);
|
||||||
|
|
||||||
|
gridview.addView(new MockGridview(), Sizing.Distribute, [1, 0]);
|
||||||
|
|
||||||
|
expect(gridview.serialize()).toEqual({
|
||||||
|
height: 1000,
|
||||||
|
orientation: 'HORIZONTAL',
|
||||||
|
root: {
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
data: {},
|
||||||
|
size: 500,
|
||||||
|
type: 'leaf',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
data: {},
|
||||||
|
size: 500,
|
||||||
|
type: 'leaf',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: {},
|
||||||
|
size: 500,
|
||||||
|
type: 'leaf',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
size: 500,
|
||||||
|
type: 'branch',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
size: 1000,
|
||||||
|
type: 'branch',
|
||||||
|
},
|
||||||
|
width: 1000,
|
||||||
|
});
|
||||||
|
expect(
|
||||||
|
gridview.element.querySelectorAll('.mock-grid-view').length
|
||||||
|
).toBe(3);
|
||||||
|
|
||||||
|
gridview.removeView([0], Sizing.Distribute);
|
||||||
|
|
||||||
|
expect(gridview.serialize()).toEqual({
|
||||||
|
height: 1000,
|
||||||
|
orientation: 'VERTICAL',
|
||||||
|
root: {
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
data: {},
|
||||||
|
size: 500,
|
||||||
|
type: 'leaf',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: {},
|
||||||
|
size: 500,
|
||||||
|
type: 'leaf',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
size: 1000,
|
||||||
|
type: 'branch',
|
||||||
|
},
|
||||||
|
width: 1000,
|
||||||
|
});
|
||||||
|
expect(
|
||||||
|
gridview.element.querySelectorAll('.mock-grid-view').length
|
||||||
|
).toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('removeView: remove leaf from branch where branch becomes leaf and parent is not root', () => {
|
||||||
|
const gridview = new Gridview(
|
||||||
|
false,
|
||||||
|
{ separatorBorder: '' },
|
||||||
|
Orientation.HORIZONTAL
|
||||||
|
);
|
||||||
|
gridview.layout(1000, 1000);
|
||||||
|
|
||||||
|
gridview.addView(new MockGridview(), Sizing.Distribute, [0]);
|
||||||
|
gridview.addView(new MockGridview(), Sizing.Distribute, [1]);
|
||||||
|
|
||||||
|
gridview.addView(new MockGridview(), Sizing.Distribute, [1, 0]);
|
||||||
|
gridview.addView(new MockGridview(), Sizing.Distribute, [1, 0, 0]);
|
||||||
|
|
||||||
|
expect(gridview.serialize()).toEqual({
|
||||||
|
height: 1000,
|
||||||
|
orientation: 'HORIZONTAL',
|
||||||
|
root: {
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
data: {},
|
||||||
|
size: 500,
|
||||||
|
type: 'leaf',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
data: {},
|
||||||
|
size: 250,
|
||||||
|
type: 'leaf',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: {},
|
||||||
|
size: 250,
|
||||||
|
type: 'leaf',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
size: 500,
|
||||||
|
type: 'branch',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: {},
|
||||||
|
size: 500,
|
||||||
|
type: 'leaf',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
size: 500,
|
||||||
|
type: 'branch',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
size: 1000,
|
||||||
|
type: 'branch',
|
||||||
|
},
|
||||||
|
width: 1000,
|
||||||
|
});
|
||||||
|
expect(
|
||||||
|
gridview.element.querySelectorAll('.mock-grid-view').length
|
||||||
|
).toBe(4);
|
||||||
|
|
||||||
|
gridview.removeView([1, 0, 0], Sizing.Distribute);
|
||||||
|
|
||||||
|
expect(gridview.serialize()).toEqual({
|
||||||
|
height: 1000,
|
||||||
|
orientation: 'HORIZONTAL',
|
||||||
|
root: {
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
data: {},
|
||||||
|
size: 500,
|
||||||
|
type: 'leaf',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
data: {},
|
||||||
|
size: 500,
|
||||||
|
type: 'leaf',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: {},
|
||||||
|
size: 500,
|
||||||
|
type: 'leaf',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
size: 500,
|
||||||
|
type: 'branch',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
size: 1000,
|
||||||
|
type: 'branch',
|
||||||
|
},
|
||||||
|
width: 1000,
|
||||||
|
});
|
||||||
|
expect(
|
||||||
|
gridview.element.querySelectorAll('.mock-grid-view').length
|
||||||
|
).toBe(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('removeView: remove leaf from branch where branch remains branch and parent is not root', () => {
|
||||||
|
const gridview = new Gridview(
|
||||||
|
false,
|
||||||
|
{ separatorBorder: '' },
|
||||||
|
Orientation.HORIZONTAL
|
||||||
|
);
|
||||||
|
gridview.layout(1000, 1000);
|
||||||
|
|
||||||
|
gridview.addView(new MockGridview(), Sizing.Distribute, [0]);
|
||||||
|
gridview.addView(new MockGridview(), Sizing.Distribute, [1]);
|
||||||
|
|
||||||
|
gridview.addView(new MockGridview(), Sizing.Distribute, [1, 0]);
|
||||||
|
gridview.addView(new MockGridview(), Sizing.Distribute, [1, 0, 0]);
|
||||||
|
gridview.addView(new MockGridview(), Sizing.Distribute, [1, 0, 1]);
|
||||||
|
|
||||||
|
expect(gridview.serialize()).toEqual({
|
||||||
|
height: 1000,
|
||||||
|
orientation: 'HORIZONTAL',
|
||||||
|
root: {
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
data: {},
|
||||||
|
size: 500,
|
||||||
|
type: 'leaf',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
data: {},
|
||||||
|
size: 166,
|
||||||
|
type: 'leaf',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: {},
|
||||||
|
size: 166,
|
||||||
|
type: 'leaf',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: {},
|
||||||
|
size: 168,
|
||||||
|
type: 'leaf',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
size: 500,
|
||||||
|
type: 'branch',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: {},
|
||||||
|
size: 500,
|
||||||
|
type: 'leaf',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
size: 500,
|
||||||
|
type: 'branch',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
size: 1000,
|
||||||
|
type: 'branch',
|
||||||
|
},
|
||||||
|
width: 1000,
|
||||||
|
});
|
||||||
|
expect(
|
||||||
|
gridview.element.querySelectorAll('.mock-grid-view').length
|
||||||
|
).toBe(5);
|
||||||
|
|
||||||
|
gridview.removeView([1, 0, 1], Sizing.Distribute);
|
||||||
|
|
||||||
|
expect(gridview.serialize()).toEqual({
|
||||||
|
height: 1000,
|
||||||
|
orientation: 'HORIZONTAL',
|
||||||
|
root: {
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
data: {},
|
||||||
|
size: 500,
|
||||||
|
type: 'leaf',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
data: {},
|
||||||
|
size: 250,
|
||||||
|
type: 'leaf',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: {},
|
||||||
|
size: 250,
|
||||||
|
type: 'leaf',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
size: 500,
|
||||||
|
type: 'branch',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: {},
|
||||||
|
size: 500,
|
||||||
|
type: 'leaf',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
size: 500,
|
||||||
|
type: 'branch',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
size: 1000,
|
||||||
|
type: 'branch',
|
||||||
|
},
|
||||||
|
width: 1000,
|
||||||
|
});
|
||||||
|
expect(
|
||||||
|
gridview.element.querySelectorAll('.mock-grid-view').length
|
||||||
|
).toBe(4);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('removeView: remove leaf where parent is root', () => {
|
||||||
|
const gridview = new Gridview(
|
||||||
|
false,
|
||||||
|
{ separatorBorder: '' },
|
||||||
|
Orientation.HORIZONTAL
|
||||||
|
);
|
||||||
|
gridview.layout(1000, 1000);
|
||||||
|
|
||||||
|
gridview.addView(new MockGridview(), Sizing.Distribute, [0]);
|
||||||
|
gridview.addView(new MockGridview(), Sizing.Distribute, [1]);
|
||||||
|
|
||||||
|
gridview.addView(new MockGridview(), Sizing.Distribute, [1, 0]);
|
||||||
|
gridview.addView(new MockGridview(), Sizing.Distribute, [1, 0, 0]);
|
||||||
|
gridview.addView(new MockGridview(), Sizing.Distribute, [1, 0, 1]);
|
||||||
|
|
||||||
|
expect(gridview.serialize()).toEqual({
|
||||||
|
height: 1000,
|
||||||
|
orientation: 'HORIZONTAL',
|
||||||
|
root: {
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
data: {},
|
||||||
|
size: 500,
|
||||||
|
type: 'leaf',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
data: {},
|
||||||
|
size: 166,
|
||||||
|
type: 'leaf',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: {},
|
||||||
|
size: 166,
|
||||||
|
type: 'leaf',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: {},
|
||||||
|
size: 168,
|
||||||
|
type: 'leaf',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
size: 500,
|
||||||
|
type: 'branch',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: {},
|
||||||
|
size: 500,
|
||||||
|
type: 'leaf',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
size: 500,
|
||||||
|
type: 'branch',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
size: 1000,
|
||||||
|
type: 'branch',
|
||||||
|
},
|
||||||
|
width: 1000,
|
||||||
|
});
|
||||||
|
expect(
|
||||||
|
gridview.element.querySelectorAll('.mock-grid-view').length
|
||||||
|
).toBe(5);
|
||||||
|
|
||||||
|
gridview.removeView([1, 1], Sizing.Distribute);
|
||||||
|
|
||||||
|
expect(gridview.serialize()).toEqual({
|
||||||
|
height: 1000,
|
||||||
|
orientation: 'HORIZONTAL',
|
||||||
|
root: {
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
data: {},
|
||||||
|
size: 500,
|
||||||
|
type: 'leaf',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: {},
|
||||||
|
size: 166,
|
||||||
|
type: 'leaf',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: {},
|
||||||
|
size: 166,
|
||||||
|
type: 'leaf',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: {},
|
||||||
|
size: 168,
|
||||||
|
type: 'leaf',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
size: 1000,
|
||||||
|
type: 'branch',
|
||||||
|
},
|
||||||
|
width: 1000,
|
||||||
|
});
|
||||||
|
expect(
|
||||||
|
gridview.element.querySelectorAll('.mock-grid-view').length
|
||||||
|
).toBe(4);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -471,6 +471,8 @@ describe('gridview', () => {
|
|||||||
components: { default: TestGridview },
|
components: { default: TestGridview },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
gridview.layout(800, 400);
|
||||||
|
|
||||||
gridview.fromJSON({
|
gridview.fromJSON({
|
||||||
grid: {
|
grid: {
|
||||||
height: 400,
|
height: 400,
|
||||||
@ -528,7 +530,8 @@ describe('gridview', () => {
|
|||||||
components: { default: TestGridview },
|
components: { default: TestGridview },
|
||||||
});
|
});
|
||||||
|
|
||||||
// gridview.layout(800, 400);
|
gridview.layout(800, 400);
|
||||||
|
|
||||||
gridview.fromJSON({
|
gridview.fromJSON({
|
||||||
grid: {
|
grid: {
|
||||||
height: 400,
|
height: 400,
|
||||||
@ -552,7 +555,6 @@ describe('gridview', () => {
|
|||||||
},
|
},
|
||||||
activePanel: 'panel_1',
|
activePanel: 'panel_1',
|
||||||
});
|
});
|
||||||
// gridview.layout(800, 400, true);
|
|
||||||
|
|
||||||
expect(JSON.parse(JSON.stringify(gridview.toJSON()))).toEqual({
|
expect(JSON.parse(JSON.stringify(gridview.toJSON()))).toEqual({
|
||||||
grid: {
|
grid: {
|
||||||
@ -587,7 +589,8 @@ describe('gridview', () => {
|
|||||||
components: { default: TestGridview },
|
components: { default: TestGridview },
|
||||||
});
|
});
|
||||||
|
|
||||||
// gridview.layout(800, 400);
|
gridview.layout(800, 400);
|
||||||
|
|
||||||
gridview.fromJSON({
|
gridview.fromJSON({
|
||||||
grid: {
|
grid: {
|
||||||
height: 400,
|
height: 400,
|
||||||
@ -620,7 +623,6 @@ describe('gridview', () => {
|
|||||||
},
|
},
|
||||||
activePanel: 'panel_1',
|
activePanel: 'panel_1',
|
||||||
});
|
});
|
||||||
// gridview.layout(800, 400, true);
|
|
||||||
|
|
||||||
expect(JSON.parse(JSON.stringify(gridview.toJSON()))).toEqual({
|
expect(JSON.parse(JSON.stringify(gridview.toJSON()))).toEqual({
|
||||||
grid: {
|
grid: {
|
||||||
@ -664,7 +666,8 @@ describe('gridview', () => {
|
|||||||
components: { default: TestGridview },
|
components: { default: TestGridview },
|
||||||
});
|
});
|
||||||
|
|
||||||
// gridview.layout(800, 400);
|
gridview.layout(800, 400);
|
||||||
|
|
||||||
gridview.fromJSON({
|
gridview.fromJSON({
|
||||||
grid: {
|
grid: {
|
||||||
height: 400,
|
height: 400,
|
||||||
@ -706,7 +709,6 @@ describe('gridview', () => {
|
|||||||
},
|
},
|
||||||
activePanel: 'panel_1',
|
activePanel: 'panel_1',
|
||||||
});
|
});
|
||||||
// gridview.layout(800, 400, true);
|
|
||||||
|
|
||||||
expect(JSON.parse(JSON.stringify(gridview.toJSON()))).toEqual({
|
expect(JSON.parse(JSON.stringify(gridview.toJSON()))).toEqual({
|
||||||
grid: {
|
grid: {
|
||||||
@ -759,7 +761,8 @@ describe('gridview', () => {
|
|||||||
components: { default: TestGridview },
|
components: { default: TestGridview },
|
||||||
});
|
});
|
||||||
|
|
||||||
// gridview.layout(800, 400);
|
gridview.layout(800, 400);
|
||||||
|
|
||||||
gridview.fromJSON({
|
gridview.fromJSON({
|
||||||
grid: {
|
grid: {
|
||||||
height: 400,
|
height: 400,
|
||||||
@ -801,7 +804,6 @@ describe('gridview', () => {
|
|||||||
},
|
},
|
||||||
activePanel: 'panel_1',
|
activePanel: 'panel_1',
|
||||||
});
|
});
|
||||||
// gridview.layout(800, 400, true);
|
|
||||||
|
|
||||||
expect(JSON.parse(JSON.stringify(gridview.toJSON()))).toEqual({
|
expect(JSON.parse(JSON.stringify(gridview.toJSON()))).toEqual({
|
||||||
grid: {
|
grid: {
|
||||||
@ -854,6 +856,8 @@ describe('gridview', () => {
|
|||||||
components: { default: TestGridview },
|
components: { default: TestGridview },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
gridview.layout(800, 400);
|
||||||
|
|
||||||
gridview.fromJSON({
|
gridview.fromJSON({
|
||||||
grid: {
|
grid: {
|
||||||
height: 400,
|
height: 400,
|
||||||
@ -895,7 +899,6 @@ describe('gridview', () => {
|
|||||||
},
|
},
|
||||||
activePanel: 'panel_1',
|
activePanel: 'panel_1',
|
||||||
});
|
});
|
||||||
gridview.layout(800, 400, true);
|
|
||||||
|
|
||||||
expect(JSON.parse(JSON.stringify(gridview.toJSON()))).toEqual({
|
expect(JSON.parse(JSON.stringify(gridview.toJSON()))).toEqual({
|
||||||
grid: {
|
grid: {
|
||||||
@ -948,7 +951,8 @@ describe('gridview', () => {
|
|||||||
components: { default: TestGridview },
|
components: { default: TestGridview },
|
||||||
});
|
});
|
||||||
|
|
||||||
// gridview.layout(800, 400);
|
gridview.layout(800, 400);
|
||||||
|
|
||||||
gridview.fromJSON({
|
gridview.fromJSON({
|
||||||
grid: {
|
grid: {
|
||||||
height: 400,
|
height: 400,
|
||||||
@ -1005,7 +1009,6 @@ describe('gridview', () => {
|
|||||||
},
|
},
|
||||||
activePanel: 'panel_1',
|
activePanel: 'panel_1',
|
||||||
});
|
});
|
||||||
// gridview.layout(800, 400, true);
|
|
||||||
|
|
||||||
expect(JSON.parse(JSON.stringify(gridview.toJSON()))).toEqual({
|
expect(JSON.parse(JSON.stringify(gridview.toJSON()))).toEqual({
|
||||||
grid: {
|
grid: {
|
||||||
@ -1198,6 +1201,8 @@ describe('gridview', () => {
|
|||||||
components: { default: TestGridview },
|
components: { default: TestGridview },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
gridview.layout(800, 400);
|
||||||
|
|
||||||
gridview.fromJSON({
|
gridview.fromJSON({
|
||||||
grid: {
|
grid: {
|
||||||
height: 400,
|
height: 400,
|
||||||
@ -1254,7 +1259,8 @@ describe('gridview', () => {
|
|||||||
},
|
},
|
||||||
activePanel: 'panel_1',
|
activePanel: 'panel_1',
|
||||||
});
|
});
|
||||||
gridview.layout(800, 400, true);
|
|
||||||
|
// gridview.layout(800, 400, true);
|
||||||
|
|
||||||
expect(JSON.parse(JSON.stringify(gridview.toJSON()))).toEqual({
|
expect(JSON.parse(JSON.stringify(gridview.toJSON()))).toEqual({
|
||||||
grid: {
|
grid: {
|
||||||
@ -1322,6 +1328,8 @@ describe('gridview', () => {
|
|||||||
components: { default: TestGridview },
|
components: { default: TestGridview },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
gridview.layout(800, 400);
|
||||||
|
|
||||||
gridview.fromJSON({
|
gridview.fromJSON({
|
||||||
grid: {
|
grid: {
|
||||||
height: 400,
|
height: 400,
|
||||||
@ -1445,6 +1453,8 @@ describe('gridview', () => {
|
|||||||
components: { default: TestGridview },
|
components: { default: TestGridview },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
gridview.layout(800, 400);
|
||||||
|
|
||||||
gridview.fromJSON({
|
gridview.fromJSON({
|
||||||
grid: {
|
grid: {
|
||||||
height: 400,
|
height: 400,
|
||||||
@ -1908,4 +1918,318 @@ describe('gridview', () => {
|
|||||||
|
|
||||||
return disposable.dispose();
|
return disposable.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('that fromJSON layouts are resized to the current dimensions', async () => {
|
||||||
|
const container = document.createElement('div');
|
||||||
|
|
||||||
|
const gridview = new GridviewComponent({
|
||||||
|
parentElement: container,
|
||||||
|
proportionalLayout: true,
|
||||||
|
orientation: Orientation.VERTICAL,
|
||||||
|
components: { default: TestGridview },
|
||||||
|
});
|
||||||
|
|
||||||
|
gridview.layout(1600, 800);
|
||||||
|
|
||||||
|
gridview.fromJSON({
|
||||||
|
grid: {
|
||||||
|
height: 400,
|
||||||
|
width: 800,
|
||||||
|
orientation: Orientation.HORIZONTAL,
|
||||||
|
root: {
|
||||||
|
type: 'branch',
|
||||||
|
size: 400,
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
type: 'leaf',
|
||||||
|
size: 200,
|
||||||
|
data: {
|
||||||
|
id: 'panel_1',
|
||||||
|
component: 'default',
|
||||||
|
snap: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'branch',
|
||||||
|
size: 400,
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
type: 'leaf',
|
||||||
|
size: 250,
|
||||||
|
data: {
|
||||||
|
id: 'panel_2',
|
||||||
|
component: 'default',
|
||||||
|
snap: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'leaf',
|
||||||
|
size: 150,
|
||||||
|
data: {
|
||||||
|
id: 'panel_3',
|
||||||
|
component: 'default',
|
||||||
|
snap: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'leaf',
|
||||||
|
size: 200,
|
||||||
|
data: {
|
||||||
|
id: 'panel_4',
|
||||||
|
component: 'default',
|
||||||
|
snap: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
activePanel: 'panel_1',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(JSON.parse(JSON.stringify(gridview.toJSON()))).toEqual({
|
||||||
|
grid: {
|
||||||
|
height: 800,
|
||||||
|
width: 1600,
|
||||||
|
orientation: Orientation.HORIZONTAL,
|
||||||
|
root: {
|
||||||
|
type: 'branch',
|
||||||
|
size: 800,
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
type: 'leaf',
|
||||||
|
size: 400,
|
||||||
|
data: {
|
||||||
|
id: 'panel_1',
|
||||||
|
component: 'default',
|
||||||
|
snap: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'branch',
|
||||||
|
size: 800,
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
type: 'leaf',
|
||||||
|
size: 500,
|
||||||
|
data: {
|
||||||
|
id: 'panel_2',
|
||||||
|
component: 'default',
|
||||||
|
snap: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'leaf',
|
||||||
|
size: 300,
|
||||||
|
data: {
|
||||||
|
id: 'panel_3',
|
||||||
|
component: 'default',
|
||||||
|
snap: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'leaf',
|
||||||
|
size: 400,
|
||||||
|
data: {
|
||||||
|
id: 'panel_4',
|
||||||
|
component: 'default',
|
||||||
|
snap: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
activePanel: 'panel_1',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('that a deep layout with fromJSON dimensions identical to the current dimensions loads', async () => {
|
||||||
|
const container = document.createElement('div');
|
||||||
|
|
||||||
|
const gridview = new GridviewComponent({
|
||||||
|
parentElement: container,
|
||||||
|
proportionalLayout: true,
|
||||||
|
orientation: Orientation.VERTICAL,
|
||||||
|
components: { default: TestGridview },
|
||||||
|
});
|
||||||
|
|
||||||
|
gridview.layout(5000, 5000);
|
||||||
|
|
||||||
|
gridview.fromJSON({
|
||||||
|
grid: {
|
||||||
|
height: 5000,
|
||||||
|
width: 5000,
|
||||||
|
orientation: Orientation.HORIZONTAL,
|
||||||
|
root: {
|
||||||
|
type: 'branch',
|
||||||
|
size: 5000,
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
type: 'leaf',
|
||||||
|
size: 1000,
|
||||||
|
data: {
|
||||||
|
id: 'panel_1',
|
||||||
|
component: 'default',
|
||||||
|
snap: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'branch',
|
||||||
|
size: 2000,
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
type: 'branch',
|
||||||
|
size: 4000,
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
type: 'leaf',
|
||||||
|
size: 1000,
|
||||||
|
data: {
|
||||||
|
id: 'panel_2',
|
||||||
|
component: 'default',
|
||||||
|
snap: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'branch',
|
||||||
|
size: 1000,
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
type: 'leaf',
|
||||||
|
size: 2000,
|
||||||
|
data: {
|
||||||
|
id: 'panel_3',
|
||||||
|
component: 'default',
|
||||||
|
snap: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'leaf',
|
||||||
|
size: 2000,
|
||||||
|
data: {
|
||||||
|
id: 'panel_4',
|
||||||
|
component: 'default',
|
||||||
|
snap: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'leaf',
|
||||||
|
size: 1000,
|
||||||
|
data: {
|
||||||
|
id: 'panel_5',
|
||||||
|
component: 'default',
|
||||||
|
snap: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'leaf',
|
||||||
|
size: 2000,
|
||||||
|
data: {
|
||||||
|
id: 'panel_6',
|
||||||
|
component: 'default',
|
||||||
|
snap: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
activePanel: 'panel_1',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(JSON.parse(JSON.stringify(gridview.toJSON()))).toEqual({
|
||||||
|
grid: {
|
||||||
|
height: 5000,
|
||||||
|
width: 5000,
|
||||||
|
orientation: Orientation.HORIZONTAL,
|
||||||
|
root: {
|
||||||
|
type: 'branch',
|
||||||
|
size: 5000,
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
type: 'leaf',
|
||||||
|
size: 1000,
|
||||||
|
data: {
|
||||||
|
id: 'panel_1',
|
||||||
|
component: 'default',
|
||||||
|
snap: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'branch',
|
||||||
|
size: 2000,
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
type: 'branch',
|
||||||
|
size: 4000,
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
type: 'leaf',
|
||||||
|
size: 1000,
|
||||||
|
data: {
|
||||||
|
id: 'panel_2',
|
||||||
|
component: 'default',
|
||||||
|
snap: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'branch',
|
||||||
|
size: 1000,
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
type: 'leaf',
|
||||||
|
size: 2000,
|
||||||
|
data: {
|
||||||
|
id: 'panel_3',
|
||||||
|
component: 'default',
|
||||||
|
snap: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'leaf',
|
||||||
|
size: 2000,
|
||||||
|
data: {
|
||||||
|
id: 'panel_4',
|
||||||
|
component: 'default',
|
||||||
|
snap: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'leaf',
|
||||||
|
size: 1000,
|
||||||
|
data: {
|
||||||
|
id: 'panel_5',
|
||||||
|
component: 'default',
|
||||||
|
snap: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'leaf',
|
||||||
|
size: 2000,
|
||||||
|
data: {
|
||||||
|
id: 'panel_6',
|
||||||
|
component: 'default',
|
||||||
|
snap: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
activePanel: 'panel_1',
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -408,4 +408,85 @@ describe('componentPaneview', () => {
|
|||||||
expect(panel1Spy).toHaveBeenCalledTimes(1);
|
expect(panel1Spy).toHaveBeenCalledTimes(1);
|
||||||
expect(panel2Spy).toHaveBeenCalledTimes(1);
|
expect(panel2Spy).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('that fromJSON layouts are resized to the current dimensions', async () => {
|
||||||
|
const paneview = new PaneviewComponent({
|
||||||
|
parentElement: container,
|
||||||
|
components: {
|
||||||
|
testPanel: TestPanel,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
paneview.layout(400, 600);
|
||||||
|
|
||||||
|
paneview.fromJSON({
|
||||||
|
size: 6,
|
||||||
|
views: [
|
||||||
|
{
|
||||||
|
size: 1,
|
||||||
|
data: {
|
||||||
|
id: 'panel1',
|
||||||
|
component: 'testPanel',
|
||||||
|
title: 'Panel 1',
|
||||||
|
},
|
||||||
|
expanded: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
size: 2,
|
||||||
|
data: {
|
||||||
|
id: 'panel2',
|
||||||
|
component: 'testPanel',
|
||||||
|
title: 'Panel 2',
|
||||||
|
},
|
||||||
|
expanded: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
size: 3,
|
||||||
|
data: {
|
||||||
|
id: 'panel3',
|
||||||
|
component: 'testPanel',
|
||||||
|
title: 'Panel 3',
|
||||||
|
},
|
||||||
|
expanded: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
// heights slightly differ because header height isn't accounted for
|
||||||
|
expect(JSON.parse(JSON.stringify(paneview.toJSON()))).toEqual({
|
||||||
|
size: 600,
|
||||||
|
views: [
|
||||||
|
{
|
||||||
|
size: 122,
|
||||||
|
data: {
|
||||||
|
id: 'panel1',
|
||||||
|
component: 'testPanel',
|
||||||
|
title: 'Panel 1',
|
||||||
|
},
|
||||||
|
expanded: true,
|
||||||
|
minimumSize: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
size: 122,
|
||||||
|
data: {
|
||||||
|
id: 'panel2',
|
||||||
|
component: 'testPanel',
|
||||||
|
title: 'Panel 2',
|
||||||
|
},
|
||||||
|
expanded: true,
|
||||||
|
minimumSize: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
size: 356,
|
||||||
|
data: {
|
||||||
|
id: 'panel3',
|
||||||
|
component: 'testPanel',
|
||||||
|
title: 'Panel 3',
|
||||||
|
},
|
||||||
|
expanded: true,
|
||||||
|
minimumSize: 100,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -7,7 +7,7 @@ import {
|
|||||||
Sizing,
|
Sizing,
|
||||||
Splitview,
|
Splitview,
|
||||||
} from '../../splitview/splitview';
|
} from '../../splitview/splitview';
|
||||||
|
import { fireEvent } from '@testing-library/dom';
|
||||||
class Testview implements IView {
|
class Testview implements IView {
|
||||||
private _element: HTMLElement = document.createElement('div');
|
private _element: HTMLElement = document.createElement('div');
|
||||||
private _size = 0;
|
private _size = 0;
|
||||||
@ -84,6 +84,8 @@ describe('splitview', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
container = document.createElement('div');
|
container = document.createElement('div');
|
||||||
container.className = 'container';
|
container.className = 'container';
|
||||||
|
|
||||||
|
jest.clearAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('vertical splitview', () => {
|
test('vertical splitview', () => {
|
||||||
@ -596,4 +598,82 @@ describe('splitview', () => {
|
|||||||
expect(anyEvents).toBeFalsy();
|
expect(anyEvents).toBeFalsy();
|
||||||
expect(container.childNodes.length).toBe(0);
|
expect(container.childNodes.length).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('dnd: pointer events to move sash', () => {
|
||||||
|
const splitview = new Splitview(container, {
|
||||||
|
orientation: Orientation.HORIZONTAL,
|
||||||
|
proportionalLayout: false,
|
||||||
|
});
|
||||||
|
splitview.layout(400, 500);
|
||||||
|
|
||||||
|
const view1 = new Testview(0, 1000);
|
||||||
|
const view2 = new Testview(0, 1000);
|
||||||
|
|
||||||
|
splitview.addView(view1);
|
||||||
|
splitview.addView(view2);
|
||||||
|
|
||||||
|
const addEventListenerSpy = jest.spyOn(document, 'addEventListener');
|
||||||
|
const removeEventListenerSpy = jest.spyOn(
|
||||||
|
document,
|
||||||
|
'removeEventListener'
|
||||||
|
);
|
||||||
|
|
||||||
|
const sashElement = container
|
||||||
|
.getElementsByClassName('sash')
|
||||||
|
.item(0) as HTMLElement;
|
||||||
|
|
||||||
|
// validate the expected state before drag
|
||||||
|
expect([view1.size, view2.size]).toEqual([200, 200]);
|
||||||
|
expect(sashElement).toBeTruthy();
|
||||||
|
expect(view1.element.parentElement!.style.pointerEvents).toBe('');
|
||||||
|
expect(view2.element.parentElement!.style.pointerEvents).toBe('');
|
||||||
|
|
||||||
|
// start the drag event
|
||||||
|
fireEvent(
|
||||||
|
sashElement,
|
||||||
|
new MouseEvent('pointerdown', { clientX: 50, clientY: 100 })
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(addEventListenerSpy).toBeCalledTimes(3);
|
||||||
|
|
||||||
|
// during a sash drag the views should have pointer-events disabled
|
||||||
|
expect(view1.element.parentElement!.style.pointerEvents).toBe('none');
|
||||||
|
expect(view2.element.parentElement!.style.pointerEvents).toBe('none');
|
||||||
|
|
||||||
|
// expect a delta move of 70 - 50 = 20
|
||||||
|
fireEvent(
|
||||||
|
document,
|
||||||
|
new MouseEvent('pointermove', { clientX: 70, clientY: 110 })
|
||||||
|
);
|
||||||
|
expect([view1.size, view2.size]).toEqual([220, 180]);
|
||||||
|
|
||||||
|
// expect a delta move of 75 - 70 = 5
|
||||||
|
fireEvent(
|
||||||
|
document,
|
||||||
|
new MouseEvent('pointermove', { clientX: 75, clientY: 110 })
|
||||||
|
);
|
||||||
|
expect([view1.size, view2.size]).toEqual([225, 175]);
|
||||||
|
|
||||||
|
// end the drag event
|
||||||
|
fireEvent(
|
||||||
|
document,
|
||||||
|
new MouseEvent('pointerup', { clientX: 70, clientY: 110 })
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(removeEventListenerSpy).toBeCalledTimes(3);
|
||||||
|
|
||||||
|
// expect pointer-eventes on views to be restored
|
||||||
|
expect(view1.element.parentElement!.style.pointerEvents).toBe('');
|
||||||
|
expect(view2.element.parentElement!.style.pointerEvents).toBe('');
|
||||||
|
|
||||||
|
fireEvent(
|
||||||
|
document,
|
||||||
|
new MouseEvent('pointermove', { clientX: 100, clientY: 100 })
|
||||||
|
);
|
||||||
|
// expect no additional resizes
|
||||||
|
expect([view1.size, view2.size]).toEqual([225, 175]);
|
||||||
|
// expect no additional document listeners
|
||||||
|
expect(addEventListenerSpy).toBeCalledTimes(3);
|
||||||
|
expect(removeEventListenerSpy).toBeCalledTimes(3);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -330,7 +330,7 @@ describe('componentSplitview', () => {
|
|||||||
testPanel: TestPanel,
|
testPanel: TestPanel,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
splitview.layout(600, 400);
|
splitview.layout(400, 6);
|
||||||
|
|
||||||
splitview.fromJSON({
|
splitview.fromJSON({
|
||||||
views: [
|
views: [
|
||||||
@ -535,4 +535,57 @@ describe('componentSplitview', () => {
|
|||||||
expect(panel1Spy).toHaveBeenCalledTimes(1);
|
expect(panel1Spy).toHaveBeenCalledTimes(1);
|
||||||
expect(panel2Spy).toHaveBeenCalledTimes(1);
|
expect(panel2Spy).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('that fromJSON layouts are resized to the current dimensions', async () => {
|
||||||
|
const splitview = new SplitviewComponent({
|
||||||
|
parentElement: container,
|
||||||
|
orientation: Orientation.VERTICAL,
|
||||||
|
components: {
|
||||||
|
testPanel: TestPanel,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
splitview.layout(400, 600);
|
||||||
|
|
||||||
|
splitview.fromJSON({
|
||||||
|
views: [
|
||||||
|
{
|
||||||
|
size: 1,
|
||||||
|
data: { id: 'panel1', component: 'testPanel' },
|
||||||
|
snap: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
size: 2,
|
||||||
|
data: { id: 'panel2', component: 'testPanel' },
|
||||||
|
snap: true,
|
||||||
|
},
|
||||||
|
{ size: 3, data: { id: 'panel3', component: 'testPanel' } },
|
||||||
|
],
|
||||||
|
size: 6,
|
||||||
|
orientation: Orientation.VERTICAL,
|
||||||
|
activeView: 'panel1',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(JSON.parse(JSON.stringify(splitview.toJSON()))).toEqual({
|
||||||
|
views: [
|
||||||
|
{
|
||||||
|
size: 100,
|
||||||
|
data: { id: 'panel1', component: 'testPanel' },
|
||||||
|
snap: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
size: 200,
|
||||||
|
data: { id: 'panel2', component: 'testPanel' },
|
||||||
|
snap: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
size: 300,
|
||||||
|
data: { id: 'panel3', component: 'testPanel' },
|
||||||
|
snap: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
size: 600,
|
||||||
|
orientation: Orientation.VERTICAL,
|
||||||
|
activeView: 'panel1',
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -89,7 +89,7 @@ export class DockviewPanelApiImpl
|
|||||||
}
|
}
|
||||||
|
|
||||||
public setTitle(title: string): void {
|
public setTitle(title: string): void {
|
||||||
this.panel.update({ params: { title } });
|
this.panel.setTitle(title);
|
||||||
}
|
}
|
||||||
|
|
||||||
public close(): void {
|
public close(): void {
|
||||||
|
@ -155,9 +155,7 @@ export class PanelApiImpl extends CompositeDisposable implements PanelApi {
|
|||||||
this.panelUpdatesDisposable.value = this._onUpdateParameters.event(
|
this.panelUpdatesDisposable.value = this._onUpdateParameters.event(
|
||||||
(parameters) => {
|
(parameters) => {
|
||||||
panel.update({
|
panel.update({
|
||||||
params: {
|
|
||||||
params: parameters,
|
params: parameters,
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -7,17 +7,20 @@ import {
|
|||||||
} from '../lifecycle';
|
} from '../lifecycle';
|
||||||
|
|
||||||
export abstract class DragHandler extends CompositeDisposable {
|
export abstract class DragHandler extends CompositeDisposable {
|
||||||
private readonly disposable = new MutableDisposable();
|
private readonly dataDisposable = new MutableDisposable();
|
||||||
|
private readonly pointerEventsDisposable = new MutableDisposable();
|
||||||
|
|
||||||
private readonly _onDragStart = new Emitter<void>();
|
private readonly _onDragStart = new Emitter<void>();
|
||||||
readonly onDragStart = this._onDragStart.event;
|
readonly onDragStart = this._onDragStart.event;
|
||||||
|
|
||||||
private iframes: HTMLElement[] = [];
|
|
||||||
|
|
||||||
constructor(protected readonly el: HTMLElement) {
|
constructor(protected readonly el: HTMLElement) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.addDisposables(this._onDragStart);
|
this.addDisposables(
|
||||||
|
this._onDragStart,
|
||||||
|
this.dataDisposable,
|
||||||
|
this.pointerEventsDisposable
|
||||||
|
);
|
||||||
|
|
||||||
this.configure();
|
this.configure();
|
||||||
}
|
}
|
||||||
@ -37,20 +40,28 @@ export abstract class DragHandler extends CompositeDisposable {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.disposable.value = this.getData(event.dataTransfer);
|
const iframes = [
|
||||||
|
|
||||||
this.iframes = [
|
|
||||||
...getElementsByTagName('iframe'),
|
...getElementsByTagName('iframe'),
|
||||||
...getElementsByTagName('webview'),
|
...getElementsByTagName('webview'),
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const iframe of this.iframes) {
|
this.pointerEventsDisposable.value = {
|
||||||
|
dispose: () => {
|
||||||
|
for (const iframe of iframes) {
|
||||||
|
iframe.style.pointerEvents = 'auto';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const iframe of iframes) {
|
||||||
iframe.style.pointerEvents = 'none';
|
iframe.style.pointerEvents = 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
this.el.classList.add('dv-dragged');
|
this.el.classList.add('dv-dragged');
|
||||||
setTimeout(() => this.el.classList.remove('dv-dragged'), 0);
|
setTimeout(() => this.el.classList.remove('dv-dragged'), 0);
|
||||||
|
|
||||||
|
this.dataDisposable.value = this.getData(event.dataTransfer);
|
||||||
|
|
||||||
if (event.dataTransfer) {
|
if (event.dataTransfer) {
|
||||||
event.dataTransfer.effectAllowed = 'move';
|
event.dataTransfer.effectAllowed = 'move';
|
||||||
|
|
||||||
@ -70,12 +81,8 @@ export abstract class DragHandler extends CompositeDisposable {
|
|||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
addDisposableListener(this.el, 'dragend', () => {
|
addDisposableListener(this.el, 'dragend', () => {
|
||||||
for (const iframe of this.iframes) {
|
this.pointerEventsDisposable.dispose();
|
||||||
iframe.style.pointerEvents = 'auto';
|
this.dataDisposable.dispose();
|
||||||
}
|
|
||||||
this.iframes = [];
|
|
||||||
|
|
||||||
this.disposable.dispose();
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,8 @@ export interface ITabsContainer extends IDisposable {
|
|||||||
isActive: (tab: ITab) => boolean;
|
isActive: (tab: ITab) => boolean;
|
||||||
closePanel: (panel: IDockviewPanel) => void;
|
closePanel: (panel: IDockviewPanel) => void;
|
||||||
openPanel: (panel: IDockviewPanel, index?: number) => void;
|
openPanel: (panel: IDockviewPanel, index?: number) => void;
|
||||||
setActionElement(element: HTMLElement | undefined): void;
|
setRightActionsElement(element: HTMLElement | undefined): void;
|
||||||
|
setLeftActionsElement(element: HTMLElement | undefined): void;
|
||||||
hidden: boolean;
|
hidden: boolean;
|
||||||
show(): void;
|
show(): void;
|
||||||
hide(): void;
|
hide(): void;
|
||||||
@ -40,12 +41,14 @@ export class TabsContainer
|
|||||||
{
|
{
|
||||||
private readonly _element: HTMLElement;
|
private readonly _element: HTMLElement;
|
||||||
private readonly tabContainer: HTMLElement;
|
private readonly tabContainer: HTMLElement;
|
||||||
private readonly actionContainer: HTMLElement;
|
private readonly rightActionsContainer: HTMLElement;
|
||||||
|
private readonly leftActionsContainer: HTMLElement;
|
||||||
private readonly voidContainer: VoidContainer;
|
private readonly voidContainer: VoidContainer;
|
||||||
|
|
||||||
private tabs: IValueDisposable<ITab>[] = [];
|
private tabs: IValueDisposable<ITab>[] = [];
|
||||||
private selectedIndex = -1;
|
private selectedIndex = -1;
|
||||||
private actions: HTMLElement | undefined;
|
private rightActions: HTMLElement | undefined;
|
||||||
|
private leftActions: HTMLElement | undefined;
|
||||||
|
|
||||||
private _hidden = false;
|
private _hidden = false;
|
||||||
|
|
||||||
@ -79,17 +82,31 @@ export class TabsContainer
|
|||||||
this._element.style.display = 'none';
|
this._element.style.display = 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
setActionElement(element: HTMLElement | undefined): void {
|
setRightActionsElement(element: HTMLElement | undefined): void {
|
||||||
if (this.actions === element) {
|
if (this.rightActions === element) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.actions) {
|
if (this.rightActions) {
|
||||||
this.actions.remove();
|
this.rightActions.remove();
|
||||||
this.actions = undefined;
|
this.rightActions = undefined;
|
||||||
}
|
}
|
||||||
if (element) {
|
if (element) {
|
||||||
this.actionContainer.appendChild(element);
|
this.rightActionsContainer.appendChild(element);
|
||||||
this.actions = element;
|
this.rightActions = element;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setLeftActionsElement(element: HTMLElement | undefined): void {
|
||||||
|
if (this.leftActions === element) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.leftActions) {
|
||||||
|
this.leftActions.remove();
|
||||||
|
this.leftActions = undefined;
|
||||||
|
}
|
||||||
|
if (element) {
|
||||||
|
this.leftActionsContainer.appendChild(element);
|
||||||
|
this.leftActions = element;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,8 +163,11 @@ export class TabsContainer
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
this.actionContainer = document.createElement('div');
|
this.rightActionsContainer = document.createElement('div');
|
||||||
this.actionContainer.className = 'action-container';
|
this.rightActionsContainer.className = 'right-actions-container';
|
||||||
|
|
||||||
|
this.leftActionsContainer = document.createElement('div');
|
||||||
|
this.leftActionsContainer.className = 'left-actions-container';
|
||||||
|
|
||||||
this.tabContainer = document.createElement('div');
|
this.tabContainer = document.createElement('div');
|
||||||
this.tabContainer.className = 'tabs-container';
|
this.tabContainer.className = 'tabs-container';
|
||||||
@ -155,8 +175,9 @@ export class TabsContainer
|
|||||||
this.voidContainer = new VoidContainer(this.accessor, this.group);
|
this.voidContainer = new VoidContainer(this.accessor, this.group);
|
||||||
|
|
||||||
this._element.appendChild(this.tabContainer);
|
this._element.appendChild(this.tabContainer);
|
||||||
|
this._element.appendChild(this.leftActionsContainer);
|
||||||
this._element.appendChild(this.voidContainer.element);
|
this._element.appendChild(this.voidContainer.element);
|
||||||
this._element.appendChild(this.actionContainer);
|
this._element.appendChild(this.rightActionsContainer);
|
||||||
|
|
||||||
this.addDisposables(
|
this.addDisposables(
|
||||||
this.voidContainer,
|
this.voidContainer,
|
||||||
|
@ -73,7 +73,8 @@ export type DockviewComponentUpdateOptions = Pick<
|
|||||||
| 'showDndOverlay'
|
| 'showDndOverlay'
|
||||||
| 'watermarkFrameworkComponent'
|
| 'watermarkFrameworkComponent'
|
||||||
| 'defaultTabComponent'
|
| 'defaultTabComponent'
|
||||||
| 'createGroupControlElement'
|
| 'createLeftHeaderActionsElement'
|
||||||
|
| 'createRightHeaderActionsElement'
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export interface DockviewDropEvent extends GroupviewDropEvent {
|
export interface DockviewDropEvent extends GroupviewDropEvent {
|
||||||
@ -500,6 +501,10 @@ export class DockviewComponent
|
|||||||
throw new Error('root must be of type branch');
|
throw new Error('root must be of type branch');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// take note of the existing dimensions
|
||||||
|
const width = this.width;
|
||||||
|
const height = this.height;
|
||||||
|
|
||||||
this.gridview.deserialize(grid, {
|
this.gridview.deserialize(grid, {
|
||||||
fromJSON: (node: ISerializedLeafNode<GroupPanelViewState>) => {
|
fromJSON: (node: ISerializedLeafNode<GroupPanelViewState>) => {
|
||||||
const { id, locked, hideHeader, views, activeView } = node.data;
|
const { id, locked, hideHeader, views, activeView } = node.data;
|
||||||
@ -541,6 +546,8 @@ export class DockviewComponent
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.layout(width, height);
|
||||||
|
|
||||||
if (typeof activeGroup === 'string') {
|
if (typeof activeGroup === 'string') {
|
||||||
const panel = this.getPanel(activeGroup);
|
const panel = this.getPanel(activeGroup);
|
||||||
if (panel) {
|
if (panel) {
|
||||||
@ -548,8 +555,6 @@ export class DockviewComponent
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.gridview.layout(this.width, this.height);
|
|
||||||
|
|
||||||
this._onDidLayoutFromJSON.fire();
|
this._onDidLayoutFromJSON.fire();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ import {
|
|||||||
import { DockviewDropTargets, IWatermarkRenderer } from './types';
|
import { DockviewDropTargets, IWatermarkRenderer } from './types';
|
||||||
import { DockviewGroupPanel } from './dockviewGroupPanel';
|
import { DockviewGroupPanel } from './dockviewGroupPanel';
|
||||||
import { IDockviewPanel } from './dockviewPanel';
|
import { IDockviewPanel } from './dockviewPanel';
|
||||||
import { IGroupControlRenderer } from './options';
|
import { IHeaderActionsRenderer } from './options';
|
||||||
|
|
||||||
export interface DndService {
|
export interface DndService {
|
||||||
canDisplayOverlay(
|
canDisplayOverlay(
|
||||||
@ -137,8 +137,9 @@ export class DockviewGroupPanelModel
|
|||||||
private watermark?: IWatermarkRenderer;
|
private watermark?: IWatermarkRenderer;
|
||||||
private _isGroupActive = false;
|
private _isGroupActive = false;
|
||||||
private _locked = false;
|
private _locked = false;
|
||||||
private _control: IGroupControlRenderer | undefined;
|
|
||||||
private _isFloating = false;
|
private _isFloating = false;
|
||||||
|
private _rightHeaderActions: IHeaderActionsRenderer | undefined;
|
||||||
|
private _leftHeaderActions: IHeaderActionsRenderer | undefined;
|
||||||
|
|
||||||
private mostRecentlyUsed: IDockviewPanel[] = [];
|
private mostRecentlyUsed: IDockviewPanel[] = [];
|
||||||
|
|
||||||
@ -334,16 +335,34 @@ export class DockviewGroupPanelModel
|
|||||||
this.setActive(this.isActive, true, true);
|
this.setActive(this.isActive, true, true);
|
||||||
this.updateContainer();
|
this.updateContainer();
|
||||||
|
|
||||||
if (this.accessor.options.createGroupControlElement) {
|
if (this.accessor.options.createRightHeaderActionsElement) {
|
||||||
this._control = this.accessor.options.createGroupControlElement(
|
this._rightHeaderActions =
|
||||||
|
this.accessor.options.createRightHeaderActionsElement(
|
||||||
this.groupPanel
|
this.groupPanel
|
||||||
);
|
);
|
||||||
this.addDisposables(this._control);
|
this.addDisposables(this._rightHeaderActions);
|
||||||
this._control.init({
|
this._rightHeaderActions.init({
|
||||||
containerApi: new DockviewApi(this.accessor),
|
containerApi: new DockviewApi(this.accessor),
|
||||||
api: this.groupPanel.api,
|
api: this.groupPanel.api,
|
||||||
});
|
});
|
||||||
this.tabsContainer.setActionElement(this._control.element);
|
this.tabsContainer.setRightActionsElement(
|
||||||
|
this._rightHeaderActions.element
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.accessor.options.createLeftHeaderActionsElement) {
|
||||||
|
this._leftHeaderActions =
|
||||||
|
this.accessor.options.createLeftHeaderActionsElement(
|
||||||
|
this.groupPanel
|
||||||
|
);
|
||||||
|
this.addDisposables(this._leftHeaderActions);
|
||||||
|
this._leftHeaderActions.init({
|
||||||
|
containerApi: new DockviewApi(this.accessor),
|
||||||
|
api: this.groupPanel.api,
|
||||||
|
});
|
||||||
|
this.tabsContainer.setLeftActionsElement(
|
||||||
|
this._leftHeaderActions.element
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -526,7 +545,7 @@ export class DockviewGroupPanelModel
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateActions(element: HTMLElement | undefined): void {
|
updateActions(element: HTMLElement | undefined): void {
|
||||||
this.tabsContainer.setActionElement(element);
|
this.tabsContainer.setRightActionsElement(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
public setActive(
|
public setActive(
|
||||||
|
@ -3,14 +3,10 @@ import {
|
|||||||
DockviewPanelApi,
|
DockviewPanelApi,
|
||||||
DockviewPanelApiImpl,
|
DockviewPanelApiImpl,
|
||||||
} from '../api/dockviewPanelApi';
|
} from '../api/dockviewPanelApi';
|
||||||
import {
|
import { GroupviewPanelState, IGroupPanelInitParameters } from './types';
|
||||||
GroupPanelUpdateEvent,
|
|
||||||
GroupviewPanelState,
|
|
||||||
IGroupPanelInitParameters,
|
|
||||||
} from './types';
|
|
||||||
import { DockviewGroupPanel } from './dockviewGroupPanel';
|
import { DockviewGroupPanel } from './dockviewGroupPanel';
|
||||||
import { CompositeDisposable, IDisposable } from '../lifecycle';
|
import { CompositeDisposable, IDisposable } from '../lifecycle';
|
||||||
import { IPanel, Parameters } from '../panel/types';
|
import { IPanel, PanelUpdateEvent, Parameters } from '../panel/types';
|
||||||
import { IDockviewPanelModel } from './dockviewPanelModel';
|
import { IDockviewPanelModel } from './dockviewPanelModel';
|
||||||
import { IDockviewComponent } from './dockviewComponent';
|
import { IDockviewComponent } from './dockviewComponent';
|
||||||
|
|
||||||
@ -23,7 +19,8 @@ export interface IDockviewPanel extends IDisposable, IPanel {
|
|||||||
updateParentGroup(group: DockviewGroupPanel, isGroupActive: boolean): void;
|
updateParentGroup(group: DockviewGroupPanel, isGroupActive: boolean): void;
|
||||||
init(params: IGroupPanelInitParameters): void;
|
init(params: IGroupPanelInitParameters): void;
|
||||||
toJSON(): GroupviewPanelState;
|
toJSON(): GroupviewPanelState;
|
||||||
update(event: GroupPanelUpdateEvent): void;
|
setTitle(title: string): void;
|
||||||
|
update(event: PanelUpdateEvent): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DockviewPanel
|
export class DockviewPanel
|
||||||
@ -117,19 +114,24 @@ export class DockviewPanel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public update(event: GroupPanelUpdateEvent): void {
|
public update(event: PanelUpdateEvent): void {
|
||||||
const params = event.params as IGroupPanelInitParameters;
|
// merge the new parameters with the existing parameters
|
||||||
|
|
||||||
this._params = {
|
this._params = {
|
||||||
...(this._params || {}),
|
...(this._params || {}),
|
||||||
...event.params.params,
|
...event.params,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (params.title !== this.title) {
|
/**
|
||||||
this._title = params.title;
|
* delete new keys that have a value of undefined,
|
||||||
this.api._onDidTitleChange.fire({ title: params.title });
|
* allow values of null
|
||||||
|
*/
|
||||||
|
for (const key of Object.keys(event.params)) {
|
||||||
|
if (event.params[key] === undefined) {
|
||||||
|
delete this._params[key];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// update the view with the updated props
|
||||||
this.view.update({
|
this.view.update({
|
||||||
params: {
|
params: {
|
||||||
params: this._params,
|
params: this._params,
|
||||||
|
@ -3,19 +3,19 @@ import {
|
|||||||
GroupPanelPartInitParameters,
|
GroupPanelPartInitParameters,
|
||||||
IContentRenderer,
|
IContentRenderer,
|
||||||
ITabRenderer,
|
ITabRenderer,
|
||||||
GroupPanelUpdateEvent,
|
|
||||||
} from './types';
|
} from './types';
|
||||||
import { DockviewGroupPanel } from './dockviewGroupPanel';
|
import { DockviewGroupPanel } from './dockviewGroupPanel';
|
||||||
import { IDisposable } from '../lifecycle';
|
import { IDisposable } from '../lifecycle';
|
||||||
import { createComponent } from '../panel/componentFactory';
|
import { createComponent } from '../panel/componentFactory';
|
||||||
import { IDockviewComponent } from './dockviewComponent';
|
import { IDockviewComponent } from './dockviewComponent';
|
||||||
|
import { PanelUpdateEvent } from '../panel/types';
|
||||||
|
|
||||||
export interface IDockviewPanelModel extends IDisposable {
|
export interface IDockviewPanelModel extends IDisposable {
|
||||||
readonly contentComponent: string;
|
readonly contentComponent: string;
|
||||||
readonly tabComponent?: string;
|
readonly tabComponent?: string;
|
||||||
readonly content: IContentRenderer;
|
readonly content: IContentRenderer;
|
||||||
readonly tab?: ITabRenderer;
|
readonly tab?: ITabRenderer;
|
||||||
update(event: GroupPanelUpdateEvent): void;
|
update(event: PanelUpdateEvent): void;
|
||||||
layout(width: number, height: number): void;
|
layout(width: number, height: number): void;
|
||||||
init(params: GroupPanelPartInitParameters): void;
|
init(params: GroupPanelPartInitParameters): void;
|
||||||
updateParentGroup(group: DockviewGroupPanel, isPanelVisible: boolean): void;
|
updateParentGroup(group: DockviewGroupPanel, isPanelVisible: boolean): void;
|
||||||
@ -80,7 +80,7 @@ export class DockviewPanelModel implements IDockviewPanelModel {
|
|||||||
this.content.layout?.(width, height);
|
this.content.layout?.(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
update(event: GroupPanelUpdateEvent): void {
|
update(event: PanelUpdateEvent): void {
|
||||||
this.content.update?.(event);
|
this.content.update?.(event);
|
||||||
this.tab.update?.(event);
|
this.tab.update?.(event);
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ import { Position } from '../dnd/droptarget';
|
|||||||
import { IDockviewPanel } from './dockviewPanel';
|
import { IDockviewPanel } from './dockviewPanel';
|
||||||
import { FrameworkFactory } from '../panel/componentFactory';
|
import { FrameworkFactory } from '../panel/componentFactory';
|
||||||
|
|
||||||
export interface IGroupControlRenderer extends IDisposable {
|
export interface IHeaderActionsRenderer extends IDisposable {
|
||||||
readonly element: HTMLElement;
|
readonly element: HTMLElement;
|
||||||
init(params: {
|
init(params: {
|
||||||
containerApi: DockviewApi;
|
containerApi: DockviewApi;
|
||||||
@ -79,9 +79,12 @@ export interface DockviewComponentOptions extends DockviewRenderFunctions {
|
|||||||
styles?: ISplitviewStyles;
|
styles?: ISplitviewStyles;
|
||||||
defaultTabComponent?: string;
|
defaultTabComponent?: string;
|
||||||
showDndOverlay?: (event: DockviewDndOverlayEvent) => boolean;
|
showDndOverlay?: (event: DockviewDndOverlayEvent) => boolean;
|
||||||
createGroupControlElement?: (
|
createRightHeaderActionsElement?: (
|
||||||
group: DockviewGroupPanel
|
group: DockviewGroupPanel
|
||||||
) => IGroupControlRenderer;
|
) => IHeaderActionsRenderer;
|
||||||
|
createLeftHeaderActionsElement?: (
|
||||||
|
group: DockviewGroupPanel
|
||||||
|
) => IHeaderActionsRenderer;
|
||||||
singleTabMode?: 'fullwidth' | 'default';
|
singleTabMode?: 'fullwidth' | 'default';
|
||||||
parentElement?: HTMLElement;
|
parentElement?: HTMLElement;
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,6 @@
|
|||||||
import { IDockviewComponent } from './dockviewComponent';
|
import { IDockviewComponent } from './dockviewComponent';
|
||||||
import { DockviewPanelApi } from '../api/dockviewPanelApi';
|
import { DockviewPanelApi } from '../api/dockviewPanelApi';
|
||||||
import {
|
import { PanelInitParameters, IPanel } from '../panel/types';
|
||||||
PanelInitParameters,
|
|
||||||
IPanel,
|
|
||||||
PanelUpdateEvent,
|
|
||||||
Parameters,
|
|
||||||
} from '../panel/types';
|
|
||||||
import { DockviewApi } from '../api/component.api';
|
import { DockviewApi } from '../api/component.api';
|
||||||
import { Event } from '../events';
|
import { Event } from '../events';
|
||||||
import { Optional } from '../types';
|
import { Optional } from '../types';
|
||||||
@ -91,11 +86,6 @@ export interface IGroupPanelInitParameters
|
|||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
export type GroupPanelUpdateEvent = PanelUpdateEvent<{
|
|
||||||
params?: Parameters;
|
|
||||||
title?: string;
|
|
||||||
}>;
|
|
||||||
|
|
||||||
export interface GroupviewPanelState {
|
export interface GroupviewPanelState {
|
||||||
id: string;
|
id: string;
|
||||||
contentComponent?: string;
|
contentComponent?: string;
|
||||||
|
@ -102,10 +102,10 @@ export class Emitter<T> implements IDisposable {
|
|||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
this._listeners.splice(index, 1);
|
this._listeners.splice(index, 1);
|
||||||
} else if (Emitter.ENABLE_TRACKING) {
|
} else if (Emitter.ENABLE_TRACKING) {
|
||||||
console.warn(
|
// console.warn(
|
||||||
`Listener already disposed`,
|
// `Listener already disposed`,
|
||||||
Stacktrace.create().print()
|
// Stacktrace.create().print()
|
||||||
);
|
// );
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -162,7 +162,7 @@ export function addDisposableWindowListener<K extends keyof WindowEventMap>(
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
dispose: () => {
|
dispose: () => {
|
||||||
element.removeEventListener(type, listener);
|
element.removeEventListener(type, listener, options);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -177,7 +177,7 @@ export function addDisposableListener<K extends keyof HTMLElementEventMap>(
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
dispose: () => {
|
dispose: () => {
|
||||||
element.removeEventListener(type, listener);
|
element.removeEventListener(type, listener, options);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -104,6 +104,7 @@ export abstract class BasePanelView<T extends PanelApiImpl>
|
|||||||
}
|
}
|
||||||
|
|
||||||
update(event: PanelUpdateEvent): void {
|
update(event: PanelUpdateEvent): void {
|
||||||
|
// merge the new parameters with the existing parameters
|
||||||
this._params = {
|
this._params = {
|
||||||
...this._params,
|
...this._params,
|
||||||
params: {
|
params: {
|
||||||
@ -111,6 +112,18 @@ export abstract class BasePanelView<T extends PanelApiImpl>
|
|||||||
...event.params,
|
...event.params,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* delete new keys that have a value of undefined,
|
||||||
|
* allow values of null
|
||||||
|
*/
|
||||||
|
for (const key of Object.keys(event.params)) {
|
||||||
|
if (event.params[key] === undefined) {
|
||||||
|
delete this._params.params[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// update the view with the updated props
|
||||||
this.part?.update({ params: this._params.params });
|
this.part?.update({ params: this._params.params });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -371,8 +371,7 @@ export class Gridview implements IDisposable {
|
|||||||
root,
|
root,
|
||||||
orientation,
|
orientation,
|
||||||
deserializer,
|
deserializer,
|
||||||
orthogonalSize,
|
orthogonalSize
|
||||||
true
|
|
||||||
) as BranchNode;
|
) as BranchNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -380,8 +379,7 @@ export class Gridview implements IDisposable {
|
|||||||
node: ISerializedNode,
|
node: ISerializedNode,
|
||||||
orientation: Orientation,
|
orientation: Orientation,
|
||||||
deserializer: IViewDeserializer,
|
deserializer: IViewDeserializer,
|
||||||
orthogonalSize: number,
|
orthogonalSize: number
|
||||||
isRoot = false
|
|
||||||
): Node {
|
): Node {
|
||||||
let result: Node;
|
let result: Node;
|
||||||
if (node.type === 'branch') {
|
if (node.type === 'branch') {
|
||||||
@ -398,14 +396,12 @@ export class Gridview implements IDisposable {
|
|||||||
} as INodeDescriptor;
|
} as INodeDescriptor;
|
||||||
});
|
});
|
||||||
|
|
||||||
// HORIZONTAL => height=orthogonalsize width=size
|
|
||||||
// VERTICAL => height=size width=orthogonalsize
|
|
||||||
result = new BranchNode(
|
result = new BranchNode(
|
||||||
orientation,
|
orientation,
|
||||||
this.proportionalLayout,
|
this.proportionalLayout,
|
||||||
this.styles,
|
this.styles,
|
||||||
isRoot ? orthogonalSize : node.size,
|
orthogonalSize, // <- size - flips at each depth
|
||||||
isRoot ? node.size : orthogonalSize,
|
node.size, // <- orthogonal size - flips at each depth
|
||||||
children
|
children
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@ -678,67 +674,82 @@ export class Gridview implements IDisposable {
|
|||||||
throw new Error('Invalid location');
|
throw new Error('Invalid location');
|
||||||
}
|
}
|
||||||
|
|
||||||
const node = parent.children[index];
|
const nodeToRemove = parent.children[index];
|
||||||
|
|
||||||
if (!(node instanceof LeafNode)) {
|
if (!(nodeToRemove instanceof LeafNode)) {
|
||||||
throw new Error('Invalid location');
|
throw new Error('Invalid location');
|
||||||
}
|
}
|
||||||
|
|
||||||
const view = node.view;
|
parent.removeChild(index, sizing);
|
||||||
node.dispose(); // dispose of node
|
nodeToRemove.dispose();
|
||||||
|
|
||||||
const child = parent.removeChild(index, sizing);
|
if (parent.children.length !== 1) {
|
||||||
child.dispose();
|
return nodeToRemove.view;
|
||||||
|
|
||||||
if (parent.children.length === 0) {
|
|
||||||
return view;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parent.children.length > 1) {
|
// if the parent has only one child and we know the parent is a BranchNode we can make the tree
|
||||||
return view;
|
// more efficiently spaced by replacing the parent BranchNode with the child.
|
||||||
}
|
// if that child is a LeafNode then we simply replace the BranchNode with the child otherwise if the child
|
||||||
|
// is a BranchNode too we should spread it's children into the grandparent.
|
||||||
|
|
||||||
|
// refer to the remaining child as the sibling
|
||||||
const sibling = parent.children[0];
|
const sibling = parent.children[0];
|
||||||
|
|
||||||
if (pathToParent.length === 0) {
|
if (pathToParent.length === 0) {
|
||||||
// parent is root
|
// if the parent is root
|
||||||
|
|
||||||
if (sibling instanceof LeafNode) {
|
if (sibling instanceof LeafNode) {
|
||||||
return view;
|
// if the sibling is a leaf node no action is required
|
||||||
|
return nodeToRemove.view;
|
||||||
}
|
}
|
||||||
|
|
||||||
// we must promote sibling to be the new root
|
// otherwise the sibling is a branch node. since the parent is the root and the root has only one child
|
||||||
const child = parent.removeChild(0, sizing);
|
// which is a branch node we can just set this branch node to be the new root node
|
||||||
child.dispose();
|
|
||||||
|
// for good housekeeping we'll removing the sibling from it's existing tree
|
||||||
|
parent.removeChild(0, sizing);
|
||||||
|
|
||||||
|
// and set that sibling node to be root
|
||||||
this.root = sibling;
|
this.root = sibling;
|
||||||
return view;
|
|
||||||
|
return nodeToRemove.view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// otherwise the parent is apart of a large sub-tree
|
||||||
|
|
||||||
const [grandParent, ..._] = [...pathToParent].reverse();
|
const [grandParent, ..._] = [...pathToParent].reverse();
|
||||||
const [parentIndex, ...__] = [...rest].reverse();
|
const [parentIndex, ...__] = [...rest].reverse();
|
||||||
|
|
||||||
const isSiblingVisible = parent.isChildVisible(0);
|
const isSiblingVisible = parent.isChildVisible(0);
|
||||||
const childNode = parent.removeChild(0, sizing);
|
|
||||||
childNode.dispose();
|
|
||||||
|
|
||||||
|
// either way we need to remove the sibling from it's existing tree
|
||||||
|
parent.removeChild(0, sizing);
|
||||||
|
|
||||||
|
// note the sizes of all of the grandparents children
|
||||||
const sizes = grandParent.children.map((_size, i) =>
|
const sizes = grandParent.children.map((_size, i) =>
|
||||||
grandParent.getChildSize(i)
|
grandParent.getChildSize(i)
|
||||||
);
|
);
|
||||||
const parentNode = grandParent.removeChild(parentIndex, sizing);
|
|
||||||
parentNode.dispose();
|
// remove the parent from the grandparent since we are moving the sibling to take the parents place
|
||||||
|
// this parent is no longer used and can be disposed of
|
||||||
|
grandParent.removeChild(parentIndex, sizing).dispose();
|
||||||
|
|
||||||
if (sibling instanceof BranchNode) {
|
if (sibling instanceof BranchNode) {
|
||||||
|
// replace the parent with the siblings children
|
||||||
sizes.splice(
|
sizes.splice(
|
||||||
parentIndex,
|
parentIndex,
|
||||||
1,
|
1,
|
||||||
...sibling.children.map((c) => c.size)
|
...sibling.children.map((c) => c.size)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// and add those siblings to the grandparent
|
||||||
for (let i = 0; i < sibling.children.length; i++) {
|
for (let i = 0; i < sibling.children.length; i++) {
|
||||||
const child = sibling.children[i];
|
const child = sibling.children[i];
|
||||||
grandParent.addChild(child, child.size, parentIndex + i);
|
grandParent.addChild(child, child.size, parentIndex + i);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// otherwise create a new leaf node and add that to the grandparent
|
||||||
|
|
||||||
const newSibling = new LeafNode(
|
const newSibling = new LeafNode(
|
||||||
sibling.view,
|
sibling.view,
|
||||||
orthogonal(sibling.orientation),
|
orthogonal(sibling.orientation),
|
||||||
@ -747,14 +758,19 @@ export class Gridview implements IDisposable {
|
|||||||
const siblingSizing = isSiblingVisible
|
const siblingSizing = isSiblingVisible
|
||||||
? sibling.orthogonalSize
|
? sibling.orthogonalSize
|
||||||
: Sizing.Invisible(sibling.orthogonalSize);
|
: Sizing.Invisible(sibling.orthogonalSize);
|
||||||
|
|
||||||
grandParent.addChild(newSibling, siblingSizing, parentIndex);
|
grandParent.addChild(newSibling, siblingSizing, parentIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// the containing node of the sibling is no longer required and can be disposed of
|
||||||
|
sibling.dispose();
|
||||||
|
|
||||||
|
// resize everything
|
||||||
for (let i = 0; i < sizes.length; i++) {
|
for (let i = 0; i < sizes.length; i++) {
|
||||||
grandParent.resizeChild(i, sizes[i]);
|
grandParent.resizeChild(i, sizes[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return view;
|
return nodeToRemove.view;
|
||||||
}
|
}
|
||||||
|
|
||||||
public layout(width: number, height: number): void {
|
public layout(width: number, height: number): void {
|
||||||
|
@ -176,6 +176,10 @@ export class GridviewComponent
|
|||||||
|
|
||||||
const queue: Function[] = [];
|
const queue: Function[] = [];
|
||||||
|
|
||||||
|
// take note of the existing dimensions
|
||||||
|
const width = this.width;
|
||||||
|
const height = this.height;
|
||||||
|
|
||||||
this.gridview.deserialize(grid, {
|
this.gridview.deserialize(grid, {
|
||||||
fromJSON: (node) => {
|
fromJSON: (node) => {
|
||||||
const { data } = node;
|
const { data } = node;
|
||||||
@ -215,7 +219,7 @@ export class GridviewComponent
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
this.layout(this.width, this.height, true);
|
this.layout(width, height);
|
||||||
|
|
||||||
queue.forEach((f) => f());
|
queue.forEach((f) => f());
|
||||||
|
|
||||||
|
@ -360,6 +360,10 @@ export class PaneviewComponent extends Resizable implements IPaneviewComponent {
|
|||||||
|
|
||||||
const queue: Function[] = [];
|
const queue: Function[] = [];
|
||||||
|
|
||||||
|
// take note of the existing dimensions
|
||||||
|
const width = this.width;
|
||||||
|
const height = this.height;
|
||||||
|
|
||||||
this.paneview = new Paneview(this.element, {
|
this.paneview = new Paneview(this.element, {
|
||||||
orientation: Orientation.VERTICAL,
|
orientation: Orientation.VERTICAL,
|
||||||
descriptor: {
|
descriptor: {
|
||||||
@ -437,7 +441,7 @@ export class PaneviewComponent extends Resizable implements IPaneviewComponent {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
this.layout(this.width, this.height);
|
this.layout(width, height);
|
||||||
|
|
||||||
queue.forEach((f) => f());
|
queue.forEach((f) => f());
|
||||||
|
|
||||||
|
@ -106,6 +106,7 @@
|
|||||||
-webkit-user-select: none; // Safari
|
-webkit-user-select: none; // Safari
|
||||||
-moz-user-select: none; // Firefox
|
-moz-user-select: none; // Firefox
|
||||||
-ms-user-select: none; // IE 10 and IE 11
|
-ms-user-select: none; // IE 10 and IE 11
|
||||||
|
touch-action: none;
|
||||||
|
|
||||||
&:active {
|
&:active {
|
||||||
transition: background-color 0.1s ease-in-out;
|
transition: background-color 0.1s ease-in-out;
|
||||||
|
@ -393,7 +393,7 @@ export class Splitview {
|
|||||||
const sash = document.createElement('div');
|
const sash = document.createElement('div');
|
||||||
sash.className = 'sash';
|
sash.className = 'sash';
|
||||||
|
|
||||||
const onStart = (event: MouseEvent) => {
|
const onPointerStart = (event: PointerEvent) => {
|
||||||
for (const item of this.viewItems) {
|
for (const item of this.viewItems) {
|
||||||
item.enabled = false;
|
item.enabled = false;
|
||||||
}
|
}
|
||||||
@ -486,13 +486,12 @@ export class Splitview {
|
|||||||
size: snappedViewItem.size,
|
size: snappedViewItem.size,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
//
|
|
||||||
|
|
||||||
const mousemove = (mousemoveEvent: MouseEvent) => {
|
const onPointerMove = (event: PointerEvent) => {
|
||||||
const current =
|
const current =
|
||||||
this._orientation === Orientation.HORIZONTAL
|
this._orientation === Orientation.HORIZONTAL
|
||||||
? mousemoveEvent.clientX
|
? event.clientX
|
||||||
: mousemoveEvent.clientY;
|
: event.clientY;
|
||||||
const delta = current - start;
|
const delta = current - start;
|
||||||
|
|
||||||
this.resize(
|
this.resize(
|
||||||
@ -521,24 +520,24 @@ export class Splitview {
|
|||||||
|
|
||||||
this.saveProportions();
|
this.saveProportions();
|
||||||
|
|
||||||
document.removeEventListener('mousemove', mousemove);
|
document.removeEventListener('pointermove', onPointerMove);
|
||||||
document.removeEventListener('mouseup', end);
|
document.removeEventListener('pointerup', end);
|
||||||
document.removeEventListener('mouseend', end);
|
document.removeEventListener('pointercancel', end);
|
||||||
|
|
||||||
this._onDidSashEnd.fire(undefined);
|
this._onDidSashEnd.fire(undefined);
|
||||||
};
|
};
|
||||||
|
|
||||||
document.addEventListener('mousemove', mousemove);
|
document.addEventListener('pointermove', onPointerMove);
|
||||||
document.addEventListener('mouseup', end);
|
document.addEventListener('pointerup', end);
|
||||||
document.addEventListener('mouseend', end);
|
document.addEventListener('pointercancel', end);
|
||||||
};
|
};
|
||||||
|
|
||||||
sash.addEventListener('mousedown', onStart);
|
sash.addEventListener('pointerdown', onPointerStart);
|
||||||
|
|
||||||
const sashItem: ISashItem = {
|
const sashItem: ISashItem = {
|
||||||
container: sash,
|
container: sash,
|
||||||
disposable: () => {
|
disposable: () => {
|
||||||
sash.removeEventListener('mousedown', onStart);
|
sash.removeEventListener('pointerdown', onPointerStart);
|
||||||
this.sashContainer.removeChild(sash);
|
this.sashContainer.removeChild(sash);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -337,6 +337,10 @@ export class SplitviewComponent
|
|||||||
|
|
||||||
const queue: Function[] = [];
|
const queue: Function[] = [];
|
||||||
|
|
||||||
|
// take note of the existing dimensions
|
||||||
|
const width = this.width;
|
||||||
|
const height = this.height;
|
||||||
|
|
||||||
this.splitview = new Splitview(this.element, {
|
this.splitview = new Splitview(this.element, {
|
||||||
orientation,
|
orientation,
|
||||||
proportionalLayout: this.options.proportionalLayout,
|
proportionalLayout: this.options.proportionalLayout,
|
||||||
@ -387,7 +391,7 @@ export class SplitviewComponent
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
this.layout(this.width, this.height);
|
this.layout(width, height);
|
||||||
|
|
||||||
queue.forEach((f) => f());
|
queue.forEach((f) => f());
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ const config: JestConfigWithTsJest = {
|
|||||||
setupFiles: [
|
setupFiles: [
|
||||||
'<rootDir>/packages/dockview/src/__tests__/__mocks__/resizeObserver.js',
|
'<rootDir>/packages/dockview/src/__tests__/__mocks__/resizeObserver.js',
|
||||||
],
|
],
|
||||||
|
setupFilesAfterEnv: ['@testing-library/jest-dom/extend-expect'],
|
||||||
coveragePathIgnorePatterns: ['/node_modules/'],
|
coveragePathIgnorePatterns: ['/node_modules/'],
|
||||||
modulePathIgnorePatterns: [
|
modulePathIgnorePatterns: [
|
||||||
'<rootDir>/packages/dockview/src/__tests__/__mocks__',
|
'<rootDir>/packages/dockview/src/__tests__/__mocks__',
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "dockview",
|
"name": "dockview",
|
||||||
"version": "1.7.3",
|
"version": "1.7.6",
|
||||||
"description": "Zero dependency layout manager supporting tabs, grids and splitviews with ReactJS support",
|
"description": "Zero dependency layout manager supporting tabs, grids and splitviews with ReactJS support",
|
||||||
"main": "./dist/cjs/index.js",
|
"main": "./dist/cjs/index.js",
|
||||||
"types": "./dist/cjs/index.d.ts",
|
"types": "./dist/cjs/index.d.ts",
|
||||||
@ -56,7 +56,7 @@
|
|||||||
"author": "https://github.com/mathuo",
|
"author": "https://github.com/mathuo",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"dockview-core": "^1.7.3"
|
"dockview-core": "^1.7.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@rollup/plugin-node-resolve": "^15.0.1",
|
"@rollup/plugin-node-resolve": "^15.0.1",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { render } from '@testing-library/react';
|
import { act, render, waitFor } from '@testing-library/react';
|
||||||
import { DockviewApi } from 'dockview-core';
|
import { DockviewApi, IDockviewPanel } from 'dockview-core';
|
||||||
import {
|
import {
|
||||||
IDockviewPanelProps,
|
IDockviewPanelProps,
|
||||||
DockviewReact,
|
DockviewReact,
|
||||||
@ -15,7 +15,17 @@ describe('gridview react', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
components = {
|
components = {
|
||||||
default: (props: IDockviewPanelProps) => {
|
default: (props: IDockviewPanelProps) => {
|
||||||
return <div>hello world</div>;
|
return (
|
||||||
|
<div>
|
||||||
|
{Object.keys(props.params).map((key) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={key}
|
||||||
|
>{`key=${key},value=${props.params[key]}`}</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@ -51,4 +61,84 @@ describe('gridview react', () => {
|
|||||||
expect(api!.width).toBe(650);
|
expect(api!.width).toBe(650);
|
||||||
expect(api!.height).toBe(450);
|
expect(api!.height).toBe(450);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('that the component can update parameters', async () => {
|
||||||
|
let api: DockviewApi;
|
||||||
|
|
||||||
|
const onReady = (event: DockviewReadyEvent) => {
|
||||||
|
api = event.api;
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = render(
|
||||||
|
<DockviewReact components={components} onReady={onReady} />
|
||||||
|
);
|
||||||
|
|
||||||
|
let panel: IDockviewPanel;
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
panel = api!.addPanel({
|
||||||
|
id: 'panel_1',
|
||||||
|
component: 'default',
|
||||||
|
params: {
|
||||||
|
keyA: 'valueA',
|
||||||
|
keyB: 'valueB',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(
|
||||||
|
wrapper.queryByText(/key=keyA,value=valueA/i)
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
wrapper.queryByText(/key=keyB,value=valueB/i)
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
panel.api.updateParameters({ keyA: 'valueAA', keyC: 'valueC' });
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(
|
||||||
|
wrapper.queryByText(/key=keyA,value=valueAA/i)
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
wrapper.queryByText(/key=keyB,value=valueB/i)
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
wrapper.queryByText(/key=keyC,value=valueC/i)
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
panel.api.updateParameters({ keyC: null });
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(
|
||||||
|
wrapper.queryByText(/key=keyA,value=valueAA/i)
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
wrapper.queryByText(/key=keyB,value=valueB/i)
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
wrapper.queryByText(/key=keyC,value=null/i)
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
panel.api.updateParameters({ keyA: undefined });
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(wrapper.queryByText(/key=keyA/i)).not.toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
wrapper.queryByText(/key=keyB,value=valueB/i)
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
wrapper.queryByText(/key=keyC,value=null/i)
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -3,9 +3,9 @@ import {
|
|||||||
DockviewGroupPanelApi,
|
DockviewGroupPanelApi,
|
||||||
DockviewGroupPanelModel,
|
DockviewGroupPanelModel,
|
||||||
} from 'dockview-core';
|
} from 'dockview-core';
|
||||||
import { ReactGroupControlsRendererPart } from '../../dockview/groupControlsRenderer';
|
import { ReactHeaderActionsRendererPart } from '../../dockview/headerActionsRenderer';
|
||||||
|
|
||||||
describe('groupControlsRenderer', () => {
|
describe('headerActionsRenderer', () => {
|
||||||
test('#1', () => {
|
test('#1', () => {
|
||||||
const groupviewMock = jest.fn<Partial<DockviewGroupPanelModel>, []>(
|
const groupviewMock = jest.fn<Partial<DockviewGroupPanelModel>, []>(
|
||||||
() => {
|
() => {
|
||||||
@ -28,7 +28,7 @@ describe('groupControlsRenderer', () => {
|
|||||||
|
|
||||||
const groupPanel = new groupPanelMock() as DockviewGroupPanel;
|
const groupPanel = new groupPanelMock() as DockviewGroupPanel;
|
||||||
|
|
||||||
const cut = new ReactGroupControlsRendererPart(
|
const cut = new ReactHeaderActionsRendererPart(
|
||||||
jest.fn(),
|
jest.fn(),
|
||||||
{
|
{
|
||||||
addPortal: jest.fn(),
|
addPortal: jest.fn(),
|
@ -1,6 +1,6 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { render } from '@testing-library/react';
|
import { act, render, waitFor } from '@testing-library/react';
|
||||||
import { GridviewApi, Orientation } from 'dockview-core';
|
import { GridviewApi, IGridviewPanel, Orientation } from 'dockview-core';
|
||||||
import {
|
import {
|
||||||
IGridviewPanelProps,
|
IGridviewPanelProps,
|
||||||
GridviewReact,
|
GridviewReact,
|
||||||
@ -15,7 +15,17 @@ describe('gridview react', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
components = {
|
components = {
|
||||||
default: (props: IGridviewPanelProps) => {
|
default: (props: IGridviewPanelProps) => {
|
||||||
return <div>hello world</div>;
|
return (
|
||||||
|
<div>
|
||||||
|
{Object.keys(props.params).map((key) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={key}
|
||||||
|
>{`key=${key},value=${props.params[key]}`}</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@ -62,4 +72,88 @@ describe('gridview react', () => {
|
|||||||
expect(api!.width).toBe(650);
|
expect(api!.width).toBe(650);
|
||||||
expect(api!.height).toBe(450);
|
expect(api!.height).toBe(450);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('that the component can update parameters', async () => {
|
||||||
|
let api: GridviewApi;
|
||||||
|
|
||||||
|
const onReady = (event: GridviewReadyEvent) => {
|
||||||
|
api = event.api;
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = render(
|
||||||
|
<GridviewReact
|
||||||
|
orientation={Orientation.VERTICAL}
|
||||||
|
components={components}
|
||||||
|
onReady={onReady}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
let panel: IGridviewPanel;
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
panel = api!.addPanel({
|
||||||
|
id: 'panel_1',
|
||||||
|
component: 'default',
|
||||||
|
params: {
|
||||||
|
keyA: 'valueA',
|
||||||
|
keyB: 'valueB',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(
|
||||||
|
wrapper.queryByText(/key=keyA,value=valueA/i)
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
wrapper.queryByText(/key=keyB,value=valueB/i)
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
panel.api.updateParameters({ keyA: 'valueAA', keyC: 'valueC' });
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(
|
||||||
|
wrapper.queryByText(/key=keyA,value=valueAA/i)
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
wrapper.queryByText(/key=keyB,value=valueB/i)
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
wrapper.queryByText(/key=keyC,value=valueC/i)
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
panel.api.updateParameters({ keyC: null });
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(
|
||||||
|
wrapper.queryByText(/key=keyA,value=valueAA/i)
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
wrapper.queryByText(/key=keyB,value=valueB/i)
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
wrapper.queryByText(/key=keyC,value=null/i)
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
panel.api.updateParameters({ keyA: undefined });
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(wrapper.queryByText(/key=keyA/i)).not.toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
wrapper.queryByText(/key=keyB,value=valueB/i)
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
wrapper.queryByText(/key=keyC,value=null/i)
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { render } from '@testing-library/react';
|
import { act, render, waitFor } from '@testing-library/react';
|
||||||
import { PaneviewApi } from 'dockview-core';
|
import { IPaneviewPanel, PaneviewApi } from 'dockview-core';
|
||||||
import {
|
import {
|
||||||
IPaneviewPanelProps,
|
IPaneviewPanelProps,
|
||||||
PaneviewReact,
|
PaneviewReact,
|
||||||
@ -15,7 +15,17 @@ describe('gridview react', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
components = {
|
components = {
|
||||||
default: (props: IPaneviewPanelProps) => {
|
default: (props: IPaneviewPanelProps) => {
|
||||||
return <div>hello world</div>;
|
return (
|
||||||
|
<div>
|
||||||
|
{Object.keys(props.params).map((key) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={key}
|
||||||
|
>{`key=${key},value=${props.params[key]}`}</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@ -49,4 +59,85 @@ describe('gridview react', () => {
|
|||||||
expect(api!.width).toBe(650);
|
expect(api!.width).toBe(650);
|
||||||
expect(api!.height).toBe(450);
|
expect(api!.height).toBe(450);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('that the component can update parameters', async () => {
|
||||||
|
let api: PaneviewApi;
|
||||||
|
|
||||||
|
const onReady = (event: PaneviewReadyEvent) => {
|
||||||
|
api = event.api;
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = render(
|
||||||
|
<PaneviewReact components={components} onReady={onReady} />
|
||||||
|
);
|
||||||
|
|
||||||
|
let panel: IPaneviewPanel;
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
panel = api!.addPanel({
|
||||||
|
id: 'panel_1',
|
||||||
|
component: 'default',
|
||||||
|
title: 'Panel 1',
|
||||||
|
params: {
|
||||||
|
keyA: 'valueA',
|
||||||
|
keyB: 'valueB',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(
|
||||||
|
wrapper.queryByText(/key=keyA,value=valueA/i)
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
wrapper.queryByText(/key=keyB,value=valueB/i)
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
panel.api.updateParameters({ keyA: 'valueAA', keyC: 'valueC' });
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(
|
||||||
|
wrapper.queryByText(/key=keyA,value=valueAA/i)
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
wrapper.queryByText(/key=keyB,value=valueB/i)
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
wrapper.queryByText(/key=keyC,value=valueC/i)
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
panel.api.updateParameters({ keyC: null });
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(
|
||||||
|
wrapper.queryByText(/key=keyA,value=valueAA/i)
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
wrapper.queryByText(/key=keyB,value=valueB/i)
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
wrapper.queryByText(/key=keyC,value=null/i)
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
panel.api.updateParameters({ keyA: undefined });
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(wrapper.queryByText(/key=keyA/i)).not.toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
wrapper.queryByText(/key=keyB,value=valueB/i)
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
wrapper.queryByText(/key=keyC,value=null/i)
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,53 +0,0 @@
|
|||||||
import * as React from 'react';
|
|
||||||
import { render } from '@testing-library/react';
|
|
||||||
import { DockviewApi } from 'dockview-core';
|
|
||||||
import {
|
|
||||||
IDockviewPanelProps,
|
|
||||||
DockviewReact,
|
|
||||||
DockviewReadyEvent,
|
|
||||||
} from '../../../dockview/dockview';
|
|
||||||
import { PanelCollection } from '../../../types';
|
|
||||||
import { setMockRefElement } from '../../__test_utils__/utils';
|
|
||||||
|
|
||||||
describe('dockview', () => {
|
|
||||||
let components: PanelCollection<IDockviewPanelProps>;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
components = {
|
|
||||||
default: (props: IDockviewPanelProps) => {
|
|
||||||
return <div>hello world</div>;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
test('default', () => {
|
|
||||||
let api: DockviewApi | undefined;
|
|
||||||
|
|
||||||
const onReady = (event: DockviewReadyEvent) => {
|
|
||||||
api = event.api;
|
|
||||||
};
|
|
||||||
|
|
||||||
render(<DockviewReact components={components} onReady={onReady} />);
|
|
||||||
|
|
||||||
expect(api).toBeTruthy();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('is sized to container', () => {
|
|
||||||
const el = document.createElement('div') as any;
|
|
||||||
jest.spyOn(el, 'clientHeight', 'get').mockReturnValue(450);
|
|
||||||
jest.spyOn(el, 'clientWidth', 'get').mockReturnValue(650);
|
|
||||||
|
|
||||||
setMockRefElement(el);
|
|
||||||
|
|
||||||
let api: DockviewApi | undefined;
|
|
||||||
|
|
||||||
const onReady = (event: DockviewReadyEvent) => {
|
|
||||||
api = event.api;
|
|
||||||
};
|
|
||||||
|
|
||||||
render(<DockviewReact components={components} onReady={onReady} />);
|
|
||||||
|
|
||||||
expect(api!.width).toBe(650);
|
|
||||||
expect(api!.height).toBe(450);
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,58 +0,0 @@
|
|||||||
import {
|
|
||||||
DockviewGroupPanel,
|
|
||||||
DockviewGroupPanelApi,
|
|
||||||
DockviewGroupPanelModel,
|
|
||||||
} from 'dockview-core';
|
|
||||||
import { ReactGroupControlsRendererPart } from '../../../dockview/groupControlsRenderer';
|
|
||||||
|
|
||||||
describe('groupControlsRenderer', () => {
|
|
||||||
test('#1', () => {
|
|
||||||
const groupviewMock = jest.fn<Partial<DockviewGroupPanelModel>, []>(
|
|
||||||
() => {
|
|
||||||
return {
|
|
||||||
onDidAddPanel: jest.fn(),
|
|
||||||
onDidRemovePanel: jest.fn(),
|
|
||||||
onDidActivePanelChange: jest.fn(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const groupview = new groupviewMock() as DockviewGroupPanelModel;
|
|
||||||
|
|
||||||
const groupPanelMock = jest.fn<Partial<DockviewGroupPanel>, []>(() => {
|
|
||||||
return {
|
|
||||||
api: {} as DockviewGroupPanelApi as any,
|
|
||||||
model: groupview,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const groupPanel = new groupPanelMock() as DockviewGroupPanel;
|
|
||||||
|
|
||||||
const cut = new ReactGroupControlsRendererPart(
|
|
||||||
jest.fn(),
|
|
||||||
{
|
|
||||||
addPortal: jest.fn(),
|
|
||||||
},
|
|
||||||
groupPanel
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(cut.element.childNodes.length).toBe(0);
|
|
||||||
expect(cut.element.className).toBe('dockview-react-part');
|
|
||||||
expect(cut.part).toBeUndefined();
|
|
||||||
|
|
||||||
cut.init({
|
|
||||||
containerApi: <any>jest.fn(),
|
|
||||||
api: <any>{
|
|
||||||
onDidActiveChange: jest.fn(),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const update = jest.fn();
|
|
||||||
|
|
||||||
jest.spyOn(cut.part!, 'update').mockImplementation(update);
|
|
||||||
|
|
||||||
cut.update({ params: { valueA: 'A' } });
|
|
||||||
|
|
||||||
expect(update).toBeCalledWith({ valueA: 'A' });
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,64 +0,0 @@
|
|||||||
import * as React from 'react';
|
|
||||||
import { render } from '@testing-library/react';
|
|
||||||
import { GridviewApi, Orientation } from 'dockview-core';
|
|
||||||
import {
|
|
||||||
IGridviewPanelProps,
|
|
||||||
GridviewReact,
|
|
||||||
GridviewReadyEvent,
|
|
||||||
} from '../../../gridview/gridview';
|
|
||||||
import { PanelCollection } from '../../../types';
|
|
||||||
import { setMockRefElement } from '../../__test_utils__/utils';
|
|
||||||
|
|
||||||
describe('gridview react', () => {
|
|
||||||
let components: PanelCollection<IGridviewPanelProps>;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
components = {
|
|
||||||
default: (props: IGridviewPanelProps) => {
|
|
||||||
return <div>hello world</div>;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
test('default', () => {
|
|
||||||
let api: GridviewApi | undefined;
|
|
||||||
|
|
||||||
const onReady = (event: GridviewReadyEvent) => {
|
|
||||||
api = event.api;
|
|
||||||
};
|
|
||||||
|
|
||||||
render(
|
|
||||||
<GridviewReact
|
|
||||||
orientation={Orientation.VERTICAL}
|
|
||||||
components={components}
|
|
||||||
onReady={onReady}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(api).toBeTruthy();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('is sized to container', () => {
|
|
||||||
setMockRefElement({
|
|
||||||
clientHeight: 450,
|
|
||||||
clientWidth: 650,
|
|
||||||
appendChild: jest.fn(),
|
|
||||||
});
|
|
||||||
let api: GridviewApi | undefined;
|
|
||||||
|
|
||||||
const onReady = (event: GridviewReadyEvent) => {
|
|
||||||
api = event.api;
|
|
||||||
};
|
|
||||||
|
|
||||||
render(
|
|
||||||
<GridviewReact
|
|
||||||
orientation={Orientation.VERTICAL}
|
|
||||||
components={components}
|
|
||||||
onReady={onReady}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(api!.width).toBe(650);
|
|
||||||
expect(api!.height).toBe(450);
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,52 +0,0 @@
|
|||||||
import * as React from 'react';
|
|
||||||
import { render } from '@testing-library/react';
|
|
||||||
import { PaneviewApi } from 'dockview-core';
|
|
||||||
import {
|
|
||||||
IPaneviewPanelProps,
|
|
||||||
PaneviewReact,
|
|
||||||
PaneviewReadyEvent,
|
|
||||||
} from '../../../paneview/paneview';
|
|
||||||
import { PanelCollection } from '../../../types';
|
|
||||||
import { setMockRefElement } from '../../__test_utils__/utils';
|
|
||||||
|
|
||||||
describe('gridview react', () => {
|
|
||||||
let components: PanelCollection<IPaneviewPanelProps>;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
components = {
|
|
||||||
default: (props: IPaneviewPanelProps) => {
|
|
||||||
return <div>hello world</div>;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
test('default', () => {
|
|
||||||
let api: PaneviewApi | undefined;
|
|
||||||
|
|
||||||
const onReady = (event: PaneviewReadyEvent) => {
|
|
||||||
api = event.api;
|
|
||||||
};
|
|
||||||
|
|
||||||
render(<PaneviewReact components={components} onReady={onReady} />);
|
|
||||||
|
|
||||||
expect(api).toBeTruthy();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('is sized to container', () => {
|
|
||||||
setMockRefElement({
|
|
||||||
clientHeight: 450,
|
|
||||||
clientWidth: 650,
|
|
||||||
appendChild: jest.fn(),
|
|
||||||
});
|
|
||||||
let api: PaneviewApi | undefined;
|
|
||||||
|
|
||||||
const onReady = (event: PaneviewReadyEvent) => {
|
|
||||||
api = event.api;
|
|
||||||
};
|
|
||||||
|
|
||||||
render(<PaneviewReact components={components} onReady={onReady} />);
|
|
||||||
|
|
||||||
expect(api!.width).toBe(650);
|
|
||||||
expect(api!.height).toBe(450);
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,90 +0,0 @@
|
|||||||
import { ReactPart } from '../../react';
|
|
||||||
import * as React from 'react';
|
|
||||||
import { render, screen, act } from '@testing-library/react';
|
|
||||||
|
|
||||||
interface TestInterface {
|
|
||||||
valueA: string;
|
|
||||||
valueB: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('react', () => {
|
|
||||||
describe('ReactPart', () => {
|
|
||||||
test('update underlying component via ReactPart class', () => {
|
|
||||||
let api: ReactPart<TestInterface>;
|
|
||||||
|
|
||||||
const onReady = (_api: ReactPart<TestInterface>) => {
|
|
||||||
api = _api;
|
|
||||||
};
|
|
||||||
|
|
||||||
render(<TestWrapper onReady={onReady} component={Component} />);
|
|
||||||
|
|
||||||
expect(api!).toBeTruthy();
|
|
||||||
|
|
||||||
expect(screen.getByTestId('valueA').textContent).toBe('stringA');
|
|
||||||
expect(screen.getByTestId('valueB').textContent).toBe('42');
|
|
||||||
|
|
||||||
act(() => {
|
|
||||||
api.update({ valueB: '32' });
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(screen.getByTestId('valueA').textContent).toBe('stringA');
|
|
||||||
expect(screen.getByTestId('valueB').textContent).toBe('32');
|
|
||||||
|
|
||||||
act(() => {
|
|
||||||
api.update({ valueA: 'anotherStringA', valueB: '22' });
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(screen.getByTestId('valueA').textContent).toBe(
|
|
||||||
'anotherStringA'
|
|
||||||
);
|
|
||||||
expect(screen.getByTestId('valueB').textContent).toBe('22');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const Component = (props: TestInterface) => {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div data-testid="valueA">{props.valueA}</div>
|
|
||||||
<div data-testid="valueB">{props.valueB}</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const TestWrapper = (props: {
|
|
||||||
component: React.FunctionComponent<TestInterface>;
|
|
||||||
onReady: (api: ReactPart<TestInterface>) => void;
|
|
||||||
}) => {
|
|
||||||
const [portal, setPortal] = React.useState<React.ReactPortal[]>([]);
|
|
||||||
const ref = React.useRef<HTMLDivElement>(null);
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
const cut = new ReactPart<TestInterface>(
|
|
||||||
ref.current!,
|
|
||||||
{
|
|
||||||
addPortal: (portal: React.ReactPortal) => {
|
|
||||||
setPortal((_) => [..._, portal]);
|
|
||||||
|
|
||||||
return {
|
|
||||||
dispose: () => {
|
|
||||||
setPortal((_) => _.filter((_) => _ !== portal));
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
props.component,
|
|
||||||
{
|
|
||||||
valueA: 'stringA',
|
|
||||||
valueB: 42,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
props.onReady(cut);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
cut.dispose();
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return <div ref={ref}>{portal}</div>;
|
|
||||||
};
|
|
@ -1,64 +0,0 @@
|
|||||||
import * as React from 'react';
|
|
||||||
import { render } from '@testing-library/react';
|
|
||||||
import { SplitviewApi, Orientation } from 'dockview-core';
|
|
||||||
import {
|
|
||||||
ISplitviewPanelProps,
|
|
||||||
SplitviewReact,
|
|
||||||
SplitviewReadyEvent,
|
|
||||||
} from '../../../splitview/splitview';
|
|
||||||
import { PanelCollection } from '../../../types';
|
|
||||||
import { setMockRefElement } from '../../__test_utils__/utils';
|
|
||||||
|
|
||||||
describe('splitview react', () => {
|
|
||||||
let components: PanelCollection<ISplitviewPanelProps>;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
components = {
|
|
||||||
default: (props: ISplitviewPanelProps) => {
|
|
||||||
return <div>hello world</div>;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
test('default', () => {
|
|
||||||
let api: SplitviewApi | undefined;
|
|
||||||
|
|
||||||
const onReady = (event: SplitviewReadyEvent) => {
|
|
||||||
api = event.api;
|
|
||||||
};
|
|
||||||
|
|
||||||
render(
|
|
||||||
<SplitviewReact
|
|
||||||
orientation={Orientation.VERTICAL}
|
|
||||||
components={components}
|
|
||||||
onReady={onReady}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(api).toBeTruthy();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('is sized to container', () => {
|
|
||||||
setMockRefElement({
|
|
||||||
clientHeight: 450,
|
|
||||||
clientWidth: 650,
|
|
||||||
appendChild: jest.fn(),
|
|
||||||
});
|
|
||||||
let api: SplitviewApi | undefined;
|
|
||||||
|
|
||||||
const onReady = (event: SplitviewReadyEvent) => {
|
|
||||||
api = event.api;
|
|
||||||
};
|
|
||||||
|
|
||||||
render(
|
|
||||||
<SplitviewReact
|
|
||||||
orientation={Orientation.VERTICAL}
|
|
||||||
components={components}
|
|
||||||
onReady={onReady}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(api!.width).toBe(650);
|
|
||||||
expect(api!.height).toBe(450);
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,6 +1,6 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { render } from '@testing-library/react';
|
import { act, render, waitFor } from '@testing-library/react';
|
||||||
import { SplitviewApi, Orientation } from 'dockview-core';
|
import { SplitviewApi, Orientation, ISplitviewPanel } from 'dockview-core';
|
||||||
import {
|
import {
|
||||||
ISplitviewPanelProps,
|
ISplitviewPanelProps,
|
||||||
SplitviewReact,
|
SplitviewReact,
|
||||||
@ -15,7 +15,17 @@ describe('splitview react', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
components = {
|
components = {
|
||||||
default: (props: ISplitviewPanelProps) => {
|
default: (props: ISplitviewPanelProps) => {
|
||||||
return <div>hello world</div>;
|
return (
|
||||||
|
<div>
|
||||||
|
{Object.keys(props.params).map((key) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={key}
|
||||||
|
>{`key=${key},value=${props.params[key]}`}</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@ -61,4 +71,88 @@ describe('splitview react', () => {
|
|||||||
expect(api!.width).toBe(650);
|
expect(api!.width).toBe(650);
|
||||||
expect(api!.height).toBe(450);
|
expect(api!.height).toBe(450);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('that the component can update parameters', async () => {
|
||||||
|
let api: SplitviewApi;
|
||||||
|
|
||||||
|
const onReady = (event: SplitviewReadyEvent) => {
|
||||||
|
api = event.api;
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = render(
|
||||||
|
<SplitviewReact
|
||||||
|
orientation={Orientation.VERTICAL}
|
||||||
|
components={components}
|
||||||
|
onReady={onReady}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
let panel: ISplitviewPanel;
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
panel = api!.addPanel({
|
||||||
|
id: 'panel_1',
|
||||||
|
component: 'default',
|
||||||
|
params: {
|
||||||
|
keyA: 'valueA',
|
||||||
|
keyB: 'valueB',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(
|
||||||
|
wrapper.queryByText(/key=keyA,value=valueA/i)
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
wrapper.queryByText(/key=keyB,value=valueB/i)
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
panel.api.updateParameters({ keyA: 'valueAA', keyC: 'valueC' });
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(
|
||||||
|
wrapper.queryByText(/key=keyA,value=valueAA/i)
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
wrapper.queryByText(/key=keyB,value=valueB/i)
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
wrapper.queryByText(/key=keyC,value=valueC/i)
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
panel.api.updateParameters({ keyC: null });
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(
|
||||||
|
wrapper.queryByText(/key=keyA,value=valueAA/i)
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
wrapper.queryByText(/key=keyB,value=valueB/i)
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
wrapper.queryByText(/key=keyC,value=null/i)
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
panel.api.updateParameters({ keyA: undefined });
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(wrapper.queryByText(/key=keyA/i)).not.toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
wrapper.queryByText(/key=keyB,value=valueB/i)
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
wrapper.queryByText(/key=keyC,value=null/i)
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -4,12 +4,12 @@ import {
|
|||||||
DockviewDropEvent,
|
DockviewDropEvent,
|
||||||
DockviewDndOverlayEvent,
|
DockviewDndOverlayEvent,
|
||||||
GroupPanelFrameworkComponentFactory,
|
GroupPanelFrameworkComponentFactory,
|
||||||
IGroupControlRenderer,
|
|
||||||
DockviewPanelApi,
|
DockviewPanelApi,
|
||||||
DockviewApi,
|
DockviewApi,
|
||||||
IContentRenderer,
|
IContentRenderer,
|
||||||
ITabRenderer,
|
ITabRenderer,
|
||||||
DockviewGroupPanel,
|
DockviewGroupPanel,
|
||||||
|
IHeaderActionsRenderer,
|
||||||
} from 'dockview-core';
|
} from 'dockview-core';
|
||||||
import { ReactPanelContentPart } from './reactContentPart';
|
import { ReactPanelContentPart } from './reactContentPart';
|
||||||
import { ReactPanelHeaderPart } from './reactHeaderPart';
|
import { ReactPanelHeaderPart } from './reactHeaderPart';
|
||||||
@ -18,17 +18,17 @@ import { ReactPortalStore, usePortalsLifecycle } from '../react';
|
|||||||
import { IWatermarkPanelProps, ReactWatermarkPart } from './reactWatermarkPart';
|
import { IWatermarkPanelProps, ReactWatermarkPart } from './reactWatermarkPart';
|
||||||
import { PanelCollection, PanelParameters } from '../types';
|
import { PanelCollection, PanelParameters } from '../types';
|
||||||
import {
|
import {
|
||||||
IDockviewGroupControlProps,
|
IDockviewHeaderActionsProps,
|
||||||
ReactGroupControlsRendererPart,
|
ReactHeaderActionsRendererPart,
|
||||||
} from './groupControlsRenderer';
|
} from './headerActionsRenderer';
|
||||||
|
|
||||||
function createGroupControlElement(
|
function createGroupControlElement(
|
||||||
component: React.FunctionComponent<IDockviewGroupControlProps> | undefined,
|
component: React.FunctionComponent<IDockviewHeaderActionsProps> | undefined,
|
||||||
store: ReactPortalStore
|
store: ReactPortalStore
|
||||||
): ((groupPanel: DockviewGroupPanel) => IGroupControlRenderer) | undefined {
|
): ((groupPanel: DockviewGroupPanel) => IHeaderActionsRenderer) | undefined {
|
||||||
return component
|
return component
|
||||||
? (groupPanel: DockviewGroupPanel) => {
|
? (groupPanel: DockviewGroupPanel) => {
|
||||||
return new ReactGroupControlsRendererPart(
|
return new ReactHeaderActionsRendererPart(
|
||||||
component,
|
component,
|
||||||
store,
|
store,
|
||||||
groupPanel
|
groupPanel
|
||||||
@ -65,7 +65,8 @@ export interface IDockviewReactProps {
|
|||||||
className?: string;
|
className?: string;
|
||||||
disableAutoResizing?: boolean;
|
disableAutoResizing?: boolean;
|
||||||
defaultTabComponent?: React.FunctionComponent<IDockviewPanelHeaderProps>;
|
defaultTabComponent?: React.FunctionComponent<IDockviewPanelHeaderProps>;
|
||||||
groupControlComponent?: React.FunctionComponent<IDockviewGroupControlProps>;
|
rightHeaderActionsComponent?: React.FunctionComponent<IDockviewHeaderActionsProps>;
|
||||||
|
leftHeaderActionsComponent?: React.FunctionComponent<IDockviewHeaderActionsProps>;
|
||||||
singleTabMode?: 'fullwidth' | 'default';
|
singleTabMode?: 'fullwidth' | 'default';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,10 +151,15 @@ export const DockviewReact = React.forwardRef(
|
|||||||
? { separatorBorder: 'transparent' }
|
? { separatorBorder: 'transparent' }
|
||||||
: undefined,
|
: undefined,
|
||||||
showDndOverlay: props.showDndOverlay,
|
showDndOverlay: props.showDndOverlay,
|
||||||
createGroupControlElement: createGroupControlElement(
|
createLeftHeaderActionsElement: createGroupControlElement(
|
||||||
props.groupControlComponent,
|
props.leftHeaderActionsComponent,
|
||||||
{ addPortal }
|
{ addPortal }
|
||||||
),
|
),
|
||||||
|
createRightHeaderActionsElement: createGroupControlElement(
|
||||||
|
props.rightHeaderActionsComponent,
|
||||||
|
{ addPortal }
|
||||||
|
),
|
||||||
|
|
||||||
singleTabMode: props.singleTabMode,
|
singleTabMode: props.singleTabMode,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -250,12 +256,24 @@ export const DockviewReact = React.forwardRef(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dockviewRef.current.updateOptions({
|
dockviewRef.current.updateOptions({
|
||||||
createGroupControlElement: createGroupControlElement(
|
createRightHeaderActionsElement: createGroupControlElement(
|
||||||
props.groupControlComponent,
|
props.rightHeaderActionsComponent,
|
||||||
{ addPortal }
|
{ addPortal }
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
}, [props.groupControlComponent]);
|
}, [props.rightHeaderActionsComponent]);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (!dockviewRef.current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dockviewRef.current.updateOptions({
|
||||||
|
createLeftHeaderActionsElement: createGroupControlElement(
|
||||||
|
props.leftHeaderActionsComponent,
|
||||||
|
{ addPortal }
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}, [props.leftHeaderActionsComponent]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
@ -10,24 +10,25 @@ import {
|
|||||||
PanelUpdateEvent,
|
PanelUpdateEvent,
|
||||||
} from 'dockview-core';
|
} from 'dockview-core';
|
||||||
|
|
||||||
export interface IDockviewGroupControlProps {
|
export interface IDockviewHeaderActionsProps {
|
||||||
api: DockviewGroupPanelApi;
|
api: DockviewGroupPanelApi;
|
||||||
containerApi: DockviewApi;
|
containerApi: DockviewApi;
|
||||||
panels: IDockviewPanel[];
|
panels: IDockviewPanel[];
|
||||||
activePanel: IDockviewPanel | undefined;
|
activePanel: IDockviewPanel | undefined;
|
||||||
isGroupActive: boolean;
|
isGroupActive: boolean;
|
||||||
|
group: DockviewGroupPanel;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ReactGroupControlsRendererPart {
|
export class ReactHeaderActionsRendererPart {
|
||||||
private mutableDisposable = new DockviewMutableDisposable();
|
private mutableDisposable = new DockviewMutableDisposable();
|
||||||
private _element: HTMLElement;
|
private _element: HTMLElement;
|
||||||
private _part?: ReactPart<IDockviewGroupControlProps>;
|
private _part?: ReactPart<IDockviewHeaderActionsProps>;
|
||||||
|
|
||||||
get element(): HTMLElement {
|
get element(): HTMLElement {
|
||||||
return this._element;
|
return this._element;
|
||||||
}
|
}
|
||||||
|
|
||||||
get part(): ReactPart<IDockviewGroupControlProps> | undefined {
|
get part(): ReactPart<IDockviewHeaderActionsProps> | undefined {
|
||||||
return this._part;
|
return this._part;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,7 +37,7 @@ export class ReactGroupControlsRendererPart {
|
|||||||
}
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly component: React.FunctionComponent<IDockviewGroupControlProps>,
|
private readonly component: React.FunctionComponent<IDockviewHeaderActionsProps>,
|
||||||
private readonly reactPortalStore: ReactPortalStore,
|
private readonly reactPortalStore: ReactPortalStore,
|
||||||
private readonly _group: DockviewGroupPanel
|
private readonly _group: DockviewGroupPanel
|
||||||
) {
|
) {
|
||||||
@ -77,6 +78,7 @@ export class ReactGroupControlsRendererPart {
|
|||||||
panels: this._group.model.panels,
|
panels: this._group.model.panels,
|
||||||
activePanel: this._group.model.activePanel,
|
activePanel: this._group.model.activePanel,
|
||||||
isGroupActive: this._group.api.isActive,
|
isGroupActive: this._group.api.isActive,
|
||||||
|
group: this._group,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
@ -4,7 +4,7 @@ export * from './dockview/dockview';
|
|||||||
export * from './dockview/defaultTab';
|
export * from './dockview/defaultTab';
|
||||||
export * from './splitview/splitview';
|
export * from './splitview/splitview';
|
||||||
export * from './gridview/gridview';
|
export * from './gridview/gridview';
|
||||||
export { IDockviewGroupControlProps } from './dockview/groupControlsRenderer';
|
export { IDockviewHeaderActionsProps } from './dockview/headerActionsRenderer';
|
||||||
export { IWatermarkPanelProps } from './dockview/reactWatermarkPart';
|
export { IWatermarkPanelProps } from './dockview/reactWatermarkPart';
|
||||||
export * from './paneview/paneview';
|
export * from './paneview/paneview';
|
||||||
export * from './types';
|
export * from './types';
|
||||||
|
@ -20,7 +20,7 @@ import Link from '@docusaurus/Link';
|
|||||||
- Provide a default React tab implementation to allow for simple changes to tab renderer without rewritting the entire tab
|
- Provide a default React tab implementation to allow for simple changes to tab renderer without rewritting the entire tab
|
||||||
- Override the default tab in `ReactDockview` with the `defaultTabComponent` prop
|
- Override the default tab in `ReactDockview` with the `defaultTabComponent` prop
|
||||||
- Group controls renderer [#138](https://github.com/mathuo/dockview/pull/138)
|
- Group controls renderer [#138](https://github.com/mathuo/dockview/pull/138)
|
||||||
- Provide the `groupControlComponent` prop in `ReactDockview` to create custom control components for groups. <Link to="../../docs/components/dockview/#group-controls-panel">Go</Link>
|
- Provide the `groupControlComponent` prop in `ReactDockview` to create custom control components for groups.
|
||||||
|
|
||||||
## 🛠 Miscs
|
## 🛠 Miscs
|
||||||
|
|
||||||
|
20
packages/docs/blog/2023-06-10-dockview-1.7.4.md
Normal file
20
packages/docs/blog/2023-06-10-dockview-1.7.4.md
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
slug: dockview-1.7.4-release
|
||||||
|
title: Dockview 1.7.4
|
||||||
|
tags: [release]
|
||||||
|
---
|
||||||
|
|
||||||
|
# Release Notes
|
||||||
|
|
||||||
|
Please reference to docs @ [dockview.dev](https://dockview.dev).
|
||||||
|
|
||||||
|
## 🚀 Features
|
||||||
|
|
||||||
|
- Improvements and tests added to the panel `api.updateParameters(...)` method [#265](https://github.com/mathuo/dockview/pull/265)
|
||||||
|
|
||||||
|
## 🛠 Miscs
|
||||||
|
|
||||||
|
- Fix bug associated with overidding panel titles when using `api.updateParameters(...)` [#265](https://github.com/mathuo/dockview/pull/265)
|
||||||
|
- Cleanup listeners and disposables after use [#257](https://github.com/mathuo/dockview/pull/257)
|
||||||
|
|
||||||
|
## 🔥 Breaking changes
|
17
packages/docs/blog/2023-06-11-dockview-1.7.5.md
Normal file
17
packages/docs/blog/2023-06-11-dockview-1.7.5.md
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
slug: dockview-1.7.5-release
|
||||||
|
title: Dockview 1.7.5
|
||||||
|
tags: [release]
|
||||||
|
---
|
||||||
|
|
||||||
|
# Release Notes
|
||||||
|
|
||||||
|
Please reference to docs @ [dockview.dev](https://dockview.dev).
|
||||||
|
|
||||||
|
## 🚀 Features
|
||||||
|
|
||||||
|
## 🛠 Miscs
|
||||||
|
|
||||||
|
- Fix [#255](https://github.com/mathuo/dockview/issues/255)
|
||||||
|
|
||||||
|
## 🔥 Breaking changes
|
20
packages/docs/blog/2023-06-18-dockview-1.7.6.md
Normal file
20
packages/docs/blog/2023-06-18-dockview-1.7.6.md
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
slug: dockview-1.7.6-release
|
||||||
|
title: Dockview 1.7.6
|
||||||
|
tags: [release]
|
||||||
|
---
|
||||||
|
|
||||||
|
# Release Notes
|
||||||
|
|
||||||
|
Please reference to docs @ [dockview.dev](https://dockview.dev).
|
||||||
|
|
||||||
|
## 🚀 Features
|
||||||
|
|
||||||
|
- Touch support for resize handles [#278](https://github.com/mathuo/dockview/pull/278)
|
||||||
|
|
||||||
|
## 🛠 Miscs
|
||||||
|
|
||||||
|
- Internal cleanup [#275](https://github.com/mathuo/dockview/pull/275)
|
||||||
|
- iframe docs [#273](https://github.com/mathuo/dockview/pull/273)
|
||||||
|
|
||||||
|
## 🔥 Breaking changes
|
@ -18,7 +18,7 @@ import DockviewConstraints from '@site/sandboxes/constraints-dockview/src/app';
|
|||||||
import DndDockview from '@site/sandboxes/dnd-dockview/src/app';
|
import DndDockview from '@site/sandboxes/dnd-dockview/src/app';
|
||||||
import NestedDockview from '@site/sandboxes/nested-dockview/src/app';
|
import NestedDockview from '@site/sandboxes/nested-dockview/src/app';
|
||||||
import EventsDockview from '@site/sandboxes/events-dockview/src/app';
|
import EventsDockview from '@site/sandboxes/events-dockview/src/app';
|
||||||
import DockviewGroupControl from '@site/sandboxes/groupcontrol-dockview/src/app';
|
import DockviewGroupControl from '@site/sandboxes/headeractions-dockview/src/app';
|
||||||
import CustomHeadersDockview from '@site/sandboxes/customheader-dockview/src/app';
|
import CustomHeadersDockview from '@site/sandboxes/customheader-dockview/src/app';
|
||||||
import DockviewNative from '@site/sandboxes/fullwidthtab-dockview/src/app';
|
import DockviewNative from '@site/sandboxes/fullwidthtab-dockview/src/app';
|
||||||
import DockviewNative2 from '@site/sandboxes/nativeapp-dockview/src/app';
|
import DockviewNative2 from '@site/sandboxes/nativeapp-dockview/src/app';
|
||||||
@ -27,6 +27,7 @@ import RenderingDockview from '@site/sandboxes/rendering-dockview/src/app';
|
|||||||
import DockviewExternalDnd from '@site/sandboxes/externaldnd-dockview/src/app';
|
import DockviewExternalDnd from '@site/sandboxes/externaldnd-dockview/src/app';
|
||||||
import DockviewResizeContainer from '@site/sandboxes/resizecontainer-dockview/src/app';
|
import DockviewResizeContainer from '@site/sandboxes/resizecontainer-dockview/src/app';
|
||||||
import DockviewTabheight from '@site/sandboxes/tabheight-dockview/src/app';
|
import DockviewTabheight from '@site/sandboxes/tabheight-dockview/src/app';
|
||||||
|
import DockviewWithIFrames from '@site/sandboxes/iframe-dockview/src/app';
|
||||||
|
|
||||||
import { attach as attachDockviewVanilla } from '@site/sandboxes/javascript/vanilla-dockview/src/app';
|
import { attach as attachDockviewVanilla } from '@site/sandboxes/javascript/vanilla-dockview/src/app';
|
||||||
import { attach as attachSimpleDockview } from '@site/sandboxes/javascript/simple-dockview/src/app';
|
import { attach as attachSimpleDockview } from '@site/sandboxes/javascript/simple-dockview/src/app';
|
||||||
@ -59,7 +60,7 @@ import { DockviewReact } from 'dockview';
|
|||||||
```
|
```
|
||||||
|
|
||||||
| Property | Type | Optional | Default | Description |
|
| Property | Type | Optional | Default | Description |
|
||||||
| --------------------- | ------------------------------------ | -------- | --------- | ------------------------------------------------------------ |
|
| --------------------------- | ------------------------------------ | -------- | --------- | ------------------------------------------------------------ |
|
||||||
| onReady | (event: SplitviewReadyEvent) => void | No | | |
|
| onReady | (event: SplitviewReadyEvent) => void | No | | |
|
||||||
| components | object | No | | |
|
| components | object | No | | |
|
||||||
| tabComponents | object | Yes | | |
|
| tabComponents | object | Yes | | |
|
||||||
@ -70,7 +71,8 @@ import { DockviewReact } from 'dockview';
|
|||||||
| onDidDrop | Event | Yes | false | |
|
| onDidDrop | Event | Yes | false | |
|
||||||
| showDndOverlay | Event | Yes | false | |
|
| showDndOverlay | Event | Yes | false | |
|
||||||
| defaultTabComponent | object | Yes | | |
|
| defaultTabComponent | object | Yes | | |
|
||||||
| groupControlComponent | object | Yes | | |
|
| leftHeaderActionsComponent | object | Yes | | |
|
||||||
|
| rightHeaderActionsComponent | object | Yes | | |
|
||||||
| singleTabMode | 'fullwidth' \| 'default' | Yes | 'default' | |
|
| singleTabMode | 'fullwidth' \| 'default' | Yes | 'default' | |
|
||||||
|
|
||||||
## Dockview API
|
## Dockview API
|
||||||
@ -435,6 +437,40 @@ const panel2 = api.addPanel({
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Update Panel
|
||||||
|
|
||||||
|
You can programatically update the `params` passed through to the panel through the panal api using `api.updateParameters`.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const panel = api.addPanel({
|
||||||
|
id: 'panel_1',
|
||||||
|
component: 'default',
|
||||||
|
params: {
|
||||||
|
keyA: 'valueA',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// ...
|
||||||
|
|
||||||
|
panel.api.updateParameters({
|
||||||
|
keyB: 'valueB',
|
||||||
|
});
|
||||||
|
|
||||||
|
// ...
|
||||||
|
|
||||||
|
panel.api.updateParameters({
|
||||||
|
keyA: 'anotherValueA',
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
To delete a parameter you should pass a value of `undefined` for the key.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
panel.api.updateParameters({
|
||||||
|
keyA: undefined, // this will delete 'keyA'.
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
### Panel Rendering
|
### Panel Rendering
|
||||||
|
|
||||||
By default `DockviewReact` only adds to the DOM those panels that are visible,
|
By default `DockviewReact` only adds to the DOM those panels that are visible,
|
||||||
@ -648,22 +684,22 @@ panel.group.locked = true;
|
|||||||
|
|
||||||
### Group Controls Panel
|
### Group Controls Panel
|
||||||
|
|
||||||
`DockviewReact` accepts a prop `groupControlComponent` which expects a React component whos props are `IDockviewGroupControlProps`.
|
`DockviewReact` accepts `leftHeaderActionsComponent` and `rightHeaderActionsComponent` which expect a React component with props `IDockviewHeaderActionsProps`.
|
||||||
This control will be rendered inside the header bar on the right hand side for each group of tabs.
|
These controls are rendered of the left and right side of the space to the right of the tabs in the header bar.
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
const Component: React.FunctionComponent<IDockviewGroupControlProps> = () => {
|
const Component: React.FunctionComponent<IDockviewHeaderActionsProps> = () => {
|
||||||
return <div>{'...'}</div>;
|
return <div>{'...'}</div>;
|
||||||
};
|
};
|
||||||
|
|
||||||
return <DockviewReact {...props} groupControlComponent={Component} />;
|
return <DockviewReact {...props} leftHeaderActionsComponent={Component} rightHeaderActionsComponent={...} />;
|
||||||
```
|
```
|
||||||
|
|
||||||
As a simple example the below uses the `groupControlComponent` to render a small control that indicates whether the group
|
As a simple example the below uses the `groupControlComponent` to render a small control that indicates whether the group
|
||||||
is active and which panel is active in that group.
|
is active and which panel is active in that group.
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
const GroupControlComponent = (props: IDockviewGroupControlProps) => {
|
const RightHeaderActionsComponent = (props: IDockviewHeaderActionsProps) => {
|
||||||
const isGroupActive = props.isGroupActive;
|
const isGroupActive = props.isGroupActive;
|
||||||
const activePanel = props.activePanel;
|
const activePanel = props.activePanel;
|
||||||
|
|
||||||
@ -705,6 +741,29 @@ api.group.api.setConstraints(...)
|
|||||||
<DockviewConstraints />
|
<DockviewConstraints />
|
||||||
</Container>
|
</Container>
|
||||||
|
|
||||||
|
## iFrames
|
||||||
|
|
||||||
|
iFrames required special attention because of a particular behaviour in how iFrames render:
|
||||||
|
|
||||||
|
> Re-parenting an iFrame will reload the contents of the iFrame or the rephrase this, moving an iFrame within the DOM will cause a reload of its contents.
|
||||||
|
|
||||||
|
You can find many examples of discussions on this. Two reputable forums for example are linked [here](https://bugzilla.mozilla.org/show_bug.cgi?id=254144) and [here](https://github.com/whatwg/html/issues/5484).
|
||||||
|
|
||||||
|
The problem with iFrames and `dockview` is that when you hide or move a panel that panels DOM element may be moved within the DOM or removed from the DOM completely.
|
||||||
|
If your panel contains an iFrame then that iFrame will reload after being re-positioned within the DOM tree and all state in that iFrame will most likely be lost.
|
||||||
|
|
||||||
|
`dockview` does not provide a built-in solution to this because it's too specific of a problem to include in the library.
|
||||||
|
However the below example does show an implementation of a higher-order component `HoistedDockviewPanel`that you could use to work around this problems and make iFrames behave in `dockview`.
|
||||||
|
|
||||||
|
What the higher-order component is doing is to hoist the panels contents into a DOM element that is always present and then `position: absolute` that element to match the dimensions of it's linked panel.
|
||||||
|
The visibility of these hoisted elements is then controlled through some exposed api methods to hide elements that shouldn't be currently shown.
|
||||||
|
|
||||||
|
You should open this example in CodeSandbox using the provided link to understand the code and make use of this implemention if required.
|
||||||
|
|
||||||
|
<Container sandboxId="iframe-dockview" height={600}>
|
||||||
|
<DockviewWithIFrames />
|
||||||
|
</Container>
|
||||||
|
|
||||||
## Events
|
## Events
|
||||||
|
|
||||||
A simple example showing events fired by `dockviewz that can be interacted with.
|
A simple example showing events fired by `dockviewz that can be interacted with.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "dockview-docs",
|
"name": "dockview-docs",
|
||||||
"version": "1.7.3",
|
"version": "1.7.6",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"docusaurus": "docusaurus",
|
"docusaurus": "docusaurus",
|
||||||
@ -22,7 +22,7 @@
|
|||||||
"@minoru/react-dnd-treeview": "^3.4.3",
|
"@minoru/react-dnd-treeview": "^3.4.3",
|
||||||
"axios": "^1.3.3",
|
"axios": "^1.3.3",
|
||||||
"clsx": "^1.2.1",
|
"clsx": "^1.2.1",
|
||||||
"dockview": "^1.7.3",
|
"dockview": "^1.7.6",
|
||||||
"prism-react-renderer": "^1.3.5",
|
"prism-react-renderer": "^1.3.5",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dnd": "^16.0.1",
|
"react-dnd": "^16.0.1",
|
||||||
|
@ -4,7 +4,7 @@ import {
|
|||||||
DockviewReadyEvent,
|
DockviewReadyEvent,
|
||||||
IDockviewPanelHeaderProps,
|
IDockviewPanelHeaderProps,
|
||||||
IDockviewPanelProps,
|
IDockviewPanelProps,
|
||||||
IDockviewGroupControlProps,
|
IDockviewHeaderActionsProps,
|
||||||
} from 'dockview';
|
} from 'dockview';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import * as ReactDOM from 'react-dom';
|
import * as ReactDOM from 'react-dom';
|
||||||
@ -156,7 +156,7 @@ const groupControlsComponents = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const GroupControls = (props: IDockviewGroupControlProps) => {
|
const RightControls = (props: IDockviewHeaderActionsProps) => {
|
||||||
const Component = React.useMemo(() => {
|
const Component = React.useMemo(() => {
|
||||||
if (!props.isGroupActive || !props.activePanel) {
|
if (!props.isGroupActive || !props.activePanel) {
|
||||||
return null;
|
return null;
|
||||||
@ -183,6 +183,36 @@ const GroupControls = (props: IDockviewGroupControlProps) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let counter = 0;
|
||||||
|
|
||||||
|
const LeftControls = (props: IDockviewHeaderActionsProps) => {
|
||||||
|
const onClick = () => {
|
||||||
|
props.containerApi.addPanel({
|
||||||
|
id: `id_${Date.now().toString()}`,
|
||||||
|
component: 'default',
|
||||||
|
title: `Tab ${counter++}`,
|
||||||
|
position: {
|
||||||
|
referenceGroup: props.group,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="group-control"
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
padding: '0px 8px',
|
||||||
|
height: '100%',
|
||||||
|
color: 'var(--dv-activegroup-visiblepanel-tab-color)',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Icon onClick={onClick} icon="add" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const DockviewDemo = () => {
|
const DockviewDemo = () => {
|
||||||
const onReady = (event: DockviewReadyEvent) => {
|
const onReady = (event: DockviewReadyEvent) => {
|
||||||
event.api.addPanel({
|
event.api.addPanel({
|
||||||
@ -218,8 +248,6 @@ const DockviewDemo = () => {
|
|||||||
title: 'Panel 6',
|
title: 'Panel 6',
|
||||||
position: { referencePanel: 'panel_4', direction: 'below' },
|
position: { referencePanel: 'panel_4', direction: 'below' },
|
||||||
});
|
});
|
||||||
// panel6.group.locked = true;
|
|
||||||
// panel6.group.header.hidden = true;
|
|
||||||
event.api.addPanel({
|
event.api.addPanel({
|
||||||
id: 'panel_7',
|
id: 'panel_7',
|
||||||
component: 'default',
|
component: 'default',
|
||||||
@ -233,8 +261,6 @@ const DockviewDemo = () => {
|
|||||||
position: { referencePanel: 'panel_7', direction: 'within' },
|
position: { referencePanel: 'panel_7', direction: 'within' },
|
||||||
});
|
});
|
||||||
|
|
||||||
// event.api.addGroup();
|
|
||||||
|
|
||||||
event.api.getPanel('panel_1')!.api.setActive();
|
event.api.getPanel('panel_1')!.api.setActive();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -247,7 +273,8 @@ const DockviewDemo = () => {
|
|||||||
<DockviewReact
|
<DockviewReact
|
||||||
components={components}
|
components={components}
|
||||||
defaultTabComponent={headerComponents.default}
|
defaultTabComponent={headerComponents.default}
|
||||||
groupControlComponent={GroupControls}
|
rightHeaderActionsComponent={RightControls}
|
||||||
|
leftHeaderActionsComponent={LeftControls}
|
||||||
onReady={onReady}
|
onReady={onReady}
|
||||||
className={theme}
|
className={theme}
|
||||||
/>
|
/>
|
||||||
|
32
packages/docs/sandboxes/headeractions-dockview/package.json
Normal file
32
packages/docs/sandboxes/headeractions-dockview/package.json
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"name": "headeractions-dockview",
|
||||||
|
"description": "",
|
||||||
|
"keywords": [
|
||||||
|
"dockview"
|
||||||
|
],
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "src/index.tsx",
|
||||||
|
"dependencies": {
|
||||||
|
"dockview": "*",
|
||||||
|
"react": "^18.2.0",
|
||||||
|
"react-dom": "^18.2.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/react": "^18.0.28",
|
||||||
|
"@types/react-dom": "^18.0.11",
|
||||||
|
"typescript": "^4.9.5",
|
||||||
|
"react-scripts": "*"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"start": "react-scripts start",
|
||||||
|
"build": "react-scripts build",
|
||||||
|
"test": "react-scripts test --env=jsdom",
|
||||||
|
"eject": "react-scripts eject"
|
||||||
|
},
|
||||||
|
"browserslist": [
|
||||||
|
">0.2%",
|
||||||
|
"not dead",
|
||||||
|
"not ie <= 11",
|
||||||
|
"not op_mini all"
|
||||||
|
]
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
DockviewReact,
|
DockviewReact,
|
||||||
DockviewReadyEvent,
|
DockviewReadyEvent,
|
||||||
IDockviewGroupControlProps,
|
IDockviewHeaderActionsProps,
|
||||||
IDockviewPanelProps,
|
IDockviewPanelProps,
|
||||||
} from 'dockview';
|
} from 'dockview';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
@ -26,9 +26,8 @@ const components = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const GroupControlComponent = (props: IDockviewGroupControlProps) => {
|
const RightHeaderActions = (props: IDockviewHeaderActionsProps) => {
|
||||||
const isGroupActive = props.isGroupActive;
|
const isGroupActive = props.isGroupActive;
|
||||||
const activePanel = props.activePanel;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="dockview-groupcontrol-demo">
|
<div className="dockview-groupcontrol-demo">
|
||||||
@ -40,6 +39,15 @@ const GroupControlComponent = (props: IDockviewGroupControlProps) => {
|
|||||||
>
|
>
|
||||||
{isGroupActive ? 'Group Active' : 'Group Inactive'}
|
{isGroupActive ? 'Group Active' : 'Group Inactive'}
|
||||||
</span>
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const LeftHeaderActions = (props: IDockviewHeaderActionsProps) => {
|
||||||
|
const activePanel = props.activePanel;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="dockview-groupcontrol-demo">
|
||||||
<span className="dockview-groupcontrol-demo-active-panel">{`activePanel: ${
|
<span className="dockview-groupcontrol-demo-active-panel">{`activePanel: ${
|
||||||
activePanel?.id || 'null'
|
activePanel?.id || 'null'
|
||||||
}`}</span>
|
}`}</span>
|
||||||
@ -87,7 +95,8 @@ const DockviewGroupControl = () => {
|
|||||||
<DockviewReact
|
<DockviewReact
|
||||||
onReady={onReady}
|
onReady={onReady}
|
||||||
components={components}
|
components={components}
|
||||||
groupControlComponent={GroupControlComponent}
|
leftHeaderActionsComponent={LeftHeaderActions}
|
||||||
|
rightHeaderActionsComponent={RightHeaderActions}
|
||||||
className="dockview-theme-abyss"
|
className="dockview-theme-abyss"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "groupcontrol-dockview",
|
"name": "iframe-dockview",
|
||||||
"description": "",
|
"description": "",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"dockview"
|
"dockview"
|
44
packages/docs/sandboxes/iframe-dockview/public/index.html
Normal file
44
packages/docs/sandboxes/iframe-dockview/public/index.html
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||||
|
<meta name="theme-color" content="#000000">
|
||||||
|
<!--
|
||||||
|
manifest.json provides metadata used when your web app is added to the
|
||||||
|
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
|
||||||
|
-->
|
||||||
|
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
|
||||||
|
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
|
||||||
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" />
|
||||||
|
<!--
|
||||||
|
Notice the use of %PUBLIC_URL% in the tags above.
|
||||||
|
It will be replaced with the URL of the `public` folder during the build.
|
||||||
|
Only files inside the `public` folder can be referenced from the HTML.
|
||||||
|
|
||||||
|
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||||
|
work correctly both with client-side routing and a non-root public URL.
|
||||||
|
Learn how to configure a non-root public URL by running `npm run build`.
|
||||||
|
-->
|
||||||
|
<title>React App</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<noscript>
|
||||||
|
You need to enable JavaScript to run this app.
|
||||||
|
</noscript>
|
||||||
|
<div id="root"></div>
|
||||||
|
<!--
|
||||||
|
This HTML file is a template.
|
||||||
|
If you open it directly in the browser, you will see an empty page.
|
||||||
|
|
||||||
|
You can add webfonts, meta tags, or analytics to this file.
|
||||||
|
The build step will place the bundled scripts into the <body> tag.
|
||||||
|
|
||||||
|
To begin the development, run `npm start` or `yarn start`.
|
||||||
|
To create a production bundle, use `npm run build` or `yarn build`.
|
||||||
|
-->
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
61
packages/docs/sandboxes/iframe-dockview/src/app.tsx
Normal file
61
packages/docs/sandboxes/iframe-dockview/src/app.tsx
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import {
|
||||||
|
DockviewReact,
|
||||||
|
DockviewReadyEvent,
|
||||||
|
IDockviewPanelProps,
|
||||||
|
} from 'dockview';
|
||||||
|
import * as React from 'react';
|
||||||
|
import { HoistedDockviewPanel } from './hoistedDockviewPanel';
|
||||||
|
|
||||||
|
const components = {
|
||||||
|
iframeComponent: HoistedDockviewPanel(
|
||||||
|
(props: IDockviewPanelProps<{ color: string }>) => {
|
||||||
|
return (
|
||||||
|
<iframe
|
||||||
|
style={{
|
||||||
|
pointerEvents: 'none',
|
||||||
|
border: 'none',
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
}}
|
||||||
|
src="https://dockview.dev"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
basicComponent: () => {
|
||||||
|
return (
|
||||||
|
<div style={{ padding: '20px', color: 'white' }}>
|
||||||
|
{'This panel is just a usual component '}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const App: React.FC = () => {
|
||||||
|
const onReady = (event: DockviewReadyEvent) => {
|
||||||
|
event.api.addPanel({
|
||||||
|
id: 'panel_1',
|
||||||
|
component: 'iframeComponent',
|
||||||
|
});
|
||||||
|
|
||||||
|
event.api.addPanel({
|
||||||
|
id: 'panel_2',
|
||||||
|
component: 'iframeComponent',
|
||||||
|
});
|
||||||
|
|
||||||
|
event.api.addPanel({
|
||||||
|
id: 'panel_3',
|
||||||
|
component: 'basicComponent',
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DockviewReact
|
||||||
|
components={components}
|
||||||
|
onReady={onReady}
|
||||||
|
className="dockview-theme-abyss"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default App;
|
@ -0,0 +1,91 @@
|
|||||||
|
import { IDockviewPanelProps } from 'dockview';
|
||||||
|
import * as React from 'react';
|
||||||
|
import * as ReactDOM from 'react-dom';
|
||||||
|
|
||||||
|
// get absolute position of element allowing for scroll position
|
||||||
|
function getDomNodePagePosition(domNode: HTMLElement): {
|
||||||
|
left: number;
|
||||||
|
top: number;
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
} {
|
||||||
|
const { left, top, width, height } = domNode.getBoundingClientRect();
|
||||||
|
return {
|
||||||
|
left: left + window.scrollX,
|
||||||
|
top: top + window.scrollY,
|
||||||
|
width: width,
|
||||||
|
height: height,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleVisibility(element: HTMLElement, isVisible: boolean) {
|
||||||
|
element.style.visibility = isVisible ? 'visible' : 'hidden';
|
||||||
|
}
|
||||||
|
|
||||||
|
export const HoistedDockviewPanel = <T extends object>(
|
||||||
|
DockviewPanelComponent: React.FC<IDockviewPanelProps<T>>
|
||||||
|
) => {
|
||||||
|
return (props: IDockviewPanelProps<T>) => {
|
||||||
|
const ref = React.useRef<HTMLDivElement>(null);
|
||||||
|
const innerRef = React.useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
const positionHoistedPanel = () => {
|
||||||
|
if (!ref.current || !innerRef.current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { left, top, height, width } = getDomNodePagePosition(
|
||||||
|
ref.current.parentElement! // use the parent element to determine our size
|
||||||
|
);
|
||||||
|
|
||||||
|
innerRef.current.style.left = `${left}px`;
|
||||||
|
innerRef.current.style.top = `${top}px`;
|
||||||
|
innerRef.current.style.height = `${height}px`;
|
||||||
|
innerRef.current.style.width = `${width}px`;
|
||||||
|
};
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (!innerRef.current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const disposable1 = props.api.onDidVisibilityChange((event) => {
|
||||||
|
if (!innerRef.current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleVisibility(innerRef.current, event.isVisible); // subsequent checks of visibility
|
||||||
|
});
|
||||||
|
|
||||||
|
const disposable2 = props.api.onDidDimensionsChange(() => {
|
||||||
|
positionHoistedPanel();
|
||||||
|
});
|
||||||
|
|
||||||
|
positionHoistedPanel();
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
disposable1.dispose(); // cleanup
|
||||||
|
disposable2.dispose();
|
||||||
|
};
|
||||||
|
}, [props.api]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div ref={ref}>
|
||||||
|
{ReactDOM.createPortal(
|
||||||
|
<div
|
||||||
|
/** you may want to mark these elements with some kind of attribute id */
|
||||||
|
ref={innerRef}
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
overflow: 'hidden',
|
||||||
|
pointerEvents: 'none', // prevent this wrapper contain stealing events
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DockviewPanelComponent {...props} />
|
||||||
|
</div>,
|
||||||
|
document.body // <-- you may choose to mount these 'global' elements to anywhere you see suitable
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
};
|
20
packages/docs/sandboxes/iframe-dockview/src/index.tsx
Normal file
20
packages/docs/sandboxes/iframe-dockview/src/index.tsx
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { StrictMode } from 'react';
|
||||||
|
import * as ReactDOMClient from 'react-dom/client';
|
||||||
|
import './styles.css';
|
||||||
|
import 'dockview/dist/styles/dockview.css';
|
||||||
|
|
||||||
|
import App from './app';
|
||||||
|
|
||||||
|
const rootElement = document.getElementById('root');
|
||||||
|
|
||||||
|
if (rootElement) {
|
||||||
|
const root = ReactDOMClient.createRoot(rootElement);
|
||||||
|
|
||||||
|
root.render(
|
||||||
|
<StrictMode>
|
||||||
|
<div className="app">
|
||||||
|
<App />
|
||||||
|
</div>
|
||||||
|
</StrictMode>
|
||||||
|
);
|
||||||
|
}
|
15
packages/docs/sandboxes/iframe-dockview/src/styles.css
Normal file
15
packages/docs/sandboxes/iframe-dockview/src/styles.css
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
body {
|
||||||
|
margin: 0px;
|
||||||
|
color: white;
|
||||||
|
font-family: sans-serif;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#root {
|
||||||
|
height: 100vh;
|
||||||
|
width: 100vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app {
|
||||||
|
height: 100%;
|
||||||
|
}
|
18
packages/docs/sandboxes/iframe-dockview/tsconfig.json
Normal file
18
packages/docs/sandboxes/iframe-dockview/tsconfig.json
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "build/dist",
|
||||||
|
"module": "esnext",
|
||||||
|
"target": "es5",
|
||||||
|
"lib": ["es6", "dom"],
|
||||||
|
"sourceMap": true,
|
||||||
|
"allowJs": true,
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"rootDir": "src",
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"noImplicitThis": true,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"strictNullChecks": true
|
||||||
|
}
|
||||||
|
}
|
@ -18,7 +18,7 @@ import DockviewConstraints from '@site/sandboxes/constraints-dockview/src/app';
|
|||||||
import DndDockview from '@site/sandboxes/dnd-dockview/src/app';
|
import DndDockview from '@site/sandboxes/dnd-dockview/src/app';
|
||||||
import NestedDockview from '@site/sandboxes/nested-dockview/src/app';
|
import NestedDockview from '@site/sandboxes/nested-dockview/src/app';
|
||||||
import EventsDockview from '@site/sandboxes/events-dockview/src/app';
|
import EventsDockview from '@site/sandboxes/events-dockview/src/app';
|
||||||
import DockviewGroupControl from '@site/sandboxes/groupcontrol-dockview/src/app';
|
import DockviewGroupControl from '@site/sandboxes/headeractions-dockview/src/app';
|
||||||
import CustomHeadersDockview from '@site/sandboxes/customheader-dockview/src/app';
|
import CustomHeadersDockview from '@site/sandboxes/customheader-dockview/src/app';
|
||||||
import DockviewNative from '@site/sandboxes/fullwidthtab-dockview/src/app';
|
import DockviewNative from '@site/sandboxes/fullwidthtab-dockview/src/app';
|
||||||
import DockviewNative2 from '@site/sandboxes/nativeapp-dockview/src/app';
|
import DockviewNative2 from '@site/sandboxes/nativeapp-dockview/src/app';
|
||||||
@ -27,6 +27,7 @@ import RenderingDockview from '@site/sandboxes/rendering-dockview/src/app';
|
|||||||
import DockviewExternalDnd from '@site/sandboxes/externaldnd-dockview/src/app';
|
import DockviewExternalDnd from '@site/sandboxes/externaldnd-dockview/src/app';
|
||||||
import DockviewResizeContainer from '@site/sandboxes/resizecontainer-dockview/src/app';
|
import DockviewResizeContainer from '@site/sandboxes/resizecontainer-dockview/src/app';
|
||||||
import DockviewTabheight from '@site/sandboxes/tabheight-dockview/src/app';
|
import DockviewTabheight from '@site/sandboxes/tabheight-dockview/src/app';
|
||||||
|
import DockviewWithIFrames from '@site/sandboxes/iframe-dockview/src/app';
|
||||||
|
|
||||||
import { attach as attachDockviewVanilla } from '@site/sandboxes/javascript/vanilla-dockview/src/app';
|
import { attach as attachDockviewVanilla } from '@site/sandboxes/javascript/vanilla-dockview/src/app';
|
||||||
import { attach as attachSimpleDockview } from '@site/sandboxes/javascript/simple-dockview/src/app';
|
import { attach as attachSimpleDockview } from '@site/sandboxes/javascript/simple-dockview/src/app';
|
||||||
@ -435,6 +436,40 @@ const panel2 = api.addPanel({
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Update Panel
|
||||||
|
|
||||||
|
You can programatically update the `params` passed through to the panel through the panal api using `api.updateParameters`.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const panel = api.addPanel({
|
||||||
|
id: 'panel_1',
|
||||||
|
component: 'default',
|
||||||
|
params: {
|
||||||
|
keyA: 'valueA',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// ...
|
||||||
|
|
||||||
|
panel.api.updateParameters({
|
||||||
|
keyB: 'valueB',
|
||||||
|
});
|
||||||
|
|
||||||
|
// ...
|
||||||
|
|
||||||
|
panel.api.updateParameters({
|
||||||
|
keyA: 'anotherValueA',
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
To delete a parameter you should pass a value of `undefined` for the key.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
panel.api.updateParameters({
|
||||||
|
keyA: undefined, // this will delete 'keyA'.
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
### Panel Rendering
|
### Panel Rendering
|
||||||
|
|
||||||
By default `DockviewReact` only adds to the DOM those panels that are visible,
|
By default `DockviewReact` only adds to the DOM those panels that are visible,
|
||||||
@ -705,6 +740,29 @@ api.group.api.setConstraints(...)
|
|||||||
<DockviewConstraints />
|
<DockviewConstraints />
|
||||||
</Container>
|
</Container>
|
||||||
|
|
||||||
|
## iFrames
|
||||||
|
|
||||||
|
iFrames required special attention because of a particular behaviour in how iFrames render:
|
||||||
|
|
||||||
|
> Re-parenting an iFrame will reload the contents of the iFrame or the rephrase this, moving an iFrame within the DOM will cause a reload of its contents.
|
||||||
|
|
||||||
|
You can find many examples of discussions on this. Two reputable forums for example are linked [here](https://bugzilla.mozilla.org/show_bug.cgi?id=254144) and [here](https://github.com/whatwg/html/issues/5484).
|
||||||
|
|
||||||
|
The problem with iFrames and `dockview` is that when you hide or move a panel that panels DOM element may be moved within the DOM or removed from the DOM completely.
|
||||||
|
If your panel contains an iFrame then that iFrame will reload after being re-positioned within the DOM tree and all state in that iFrame will most likely be lost.
|
||||||
|
|
||||||
|
`dockview` does not provide a built-in solution to this because it's too specific of a problem to include in the library.
|
||||||
|
However the below example does show an implementation of a higher-order component `HoistedDockviewPanel`that you could use to work around this problems and make iFrames behave in `dockview`.
|
||||||
|
|
||||||
|
What the higher-order component is doing is to hoist the panels contents into a DOM element that is always present and then `position: absolute` that element to match the dimensions of it's linked panel.
|
||||||
|
The visibility of these hoisted elements is then controlled through some exposed api methods to hide elements that shouldn't be currently shown.
|
||||||
|
|
||||||
|
You should open this example in CodeSandbox using the provided link to understand the code and make use of this implemention if required.
|
||||||
|
|
||||||
|
<Container sandboxId="iframe-dockview" height={600}>
|
||||||
|
<DockviewWithIFrames />
|
||||||
|
</Container>
|
||||||
|
|
||||||
## Events
|
## Events
|
||||||
|
|
||||||
A simple example showing events fired by `dockviewz that can be interacted with.
|
A simple example showing events fired by `dockviewz that can be interacted with.
|
@ -1,3 +1,3 @@
|
|||||||
[
|
[
|
||||||
"1.7.3"
|
"1.7.6"
|
||||||
]
|
]
|
69
yarn.lock
69
yarn.lock
@ -2,6 +2,11 @@
|
|||||||
# yarn lockfile v1
|
# yarn lockfile v1
|
||||||
|
|
||||||
|
|
||||||
|
"@adobe/css-tools@^4.0.1":
|
||||||
|
version "4.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@adobe/css-tools/-/css-tools-4.2.0.tgz#e1a84fca468f4b337816fcb7f0964beb620ba855"
|
||||||
|
integrity sha512-E09FiIft46CmH5Qnjb0wsW54/YQd69LsxeKUOWawmws1XWvyFGURnAChH0mlr7YPFR1ofwvUQfcL0J3lMxXqPA==
|
||||||
|
|
||||||
"@algolia/autocomplete-core@1.7.4":
|
"@algolia/autocomplete-core@1.7.4":
|
||||||
version "1.7.4"
|
version "1.7.4"
|
||||||
resolved "https://registry.yarnpkg.com/@algolia/autocomplete-core/-/autocomplete-core-1.7.4.tgz#85ff36b2673654a393c8c505345eaedd6eaa4f70"
|
resolved "https://registry.yarnpkg.com/@algolia/autocomplete-core/-/autocomplete-core-1.7.4.tgz#85ff36b2673654a393c8c505345eaedd6eaa4f70"
|
||||||
@ -2888,6 +2893,21 @@
|
|||||||
lz-string "^1.4.4"
|
lz-string "^1.4.4"
|
||||||
pretty-format "^27.0.2"
|
pretty-format "^27.0.2"
|
||||||
|
|
||||||
|
"@testing-library/jest-dom@^5.16.5":
|
||||||
|
version "5.16.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-5.16.5.tgz#3912846af19a29b2dbf32a6ae9c31ef52580074e"
|
||||||
|
integrity sha512-N5ixQ2qKpi5OLYfwQmUb/5mSV9LneAcaUfp32pn4yCnpb8r/Yz0pXFPck21dIicKmi+ta5WRAknkZCfA8refMA==
|
||||||
|
dependencies:
|
||||||
|
"@adobe/css-tools" "^4.0.1"
|
||||||
|
"@babel/runtime" "^7.9.2"
|
||||||
|
"@types/testing-library__jest-dom" "^5.9.1"
|
||||||
|
aria-query "^5.0.0"
|
||||||
|
chalk "^3.0.0"
|
||||||
|
css.escape "^1.5.1"
|
||||||
|
dom-accessibility-api "^0.5.6"
|
||||||
|
lodash "^4.17.15"
|
||||||
|
redent "^3.0.0"
|
||||||
|
|
||||||
"@testing-library/react@^13.4.0":
|
"@testing-library/react@^13.4.0":
|
||||||
version "13.4.0"
|
version "13.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-13.4.0.tgz#6a31e3bf5951615593ad984e96b9e5e2d9380966"
|
resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-13.4.0.tgz#6a31e3bf5951615593ad984e96b9e5e2d9380966"
|
||||||
@ -3107,6 +3127,14 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@types/istanbul-lib-report" "*"
|
"@types/istanbul-lib-report" "*"
|
||||||
|
|
||||||
|
"@types/jest@*":
|
||||||
|
version "29.5.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.2.tgz#86b4afc86e3a8f3005b297ed8a72494f89e6395b"
|
||||||
|
integrity sha512-mSoZVJF5YzGVCk+FsDxzDuH7s+SCkzrgKZzf0Z0T2WudhBUPoF6ktoTPC4R0ZoCPCV5xUvuU6ias5NvxcBcMMg==
|
||||||
|
dependencies:
|
||||||
|
expect "^29.0.0"
|
||||||
|
pretty-format "^29.0.0"
|
||||||
|
|
||||||
"@types/jest@^29.4.0":
|
"@types/jest@^29.4.0":
|
||||||
version "29.5.0"
|
version "29.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.0.tgz#337b90bbcfe42158f39c2fb5619ad044bbb518ac"
|
resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.0.tgz#337b90bbcfe42158f39c2fb5619ad044bbb518ac"
|
||||||
@ -3292,6 +3320,13 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c"
|
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c"
|
||||||
integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==
|
integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==
|
||||||
|
|
||||||
|
"@types/testing-library__jest-dom@^5.9.1":
|
||||||
|
version "5.14.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.6.tgz#4887f6e1af11215428ab02777873bcede98a53b0"
|
||||||
|
integrity sha512-FkHXCb+ikSoUP4Y4rOslzTdX5sqYwMxfefKh1GmZ8ce1GOkEHntSp6b5cGadmNfp5e4BMEWOMx+WSKd5/MqlDA==
|
||||||
|
dependencies:
|
||||||
|
"@types/jest" "*"
|
||||||
|
|
||||||
"@types/tough-cookie@*":
|
"@types/tough-cookie@*":
|
||||||
version "4.0.2"
|
version "4.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.2.tgz#6286b4c7228d58ab7866d19716f3696e03a09397"
|
resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.2.tgz#6286b4c7228d58ab7866d19716f3696e03a09397"
|
||||||
@ -4659,6 +4694,14 @@ chalk@^2.0.0, chalk@^2.3.0:
|
|||||||
escape-string-regexp "^1.0.5"
|
escape-string-regexp "^1.0.5"
|
||||||
supports-color "^5.3.0"
|
supports-color "^5.3.0"
|
||||||
|
|
||||||
|
chalk@^3.0.0:
|
||||||
|
version "3.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4"
|
||||||
|
integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==
|
||||||
|
dependencies:
|
||||||
|
ansi-styles "^4.1.0"
|
||||||
|
supports-color "^7.1.0"
|
||||||
|
|
||||||
chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2:
|
chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2:
|
||||||
version "4.1.2"
|
version "4.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
|
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
|
||||||
@ -5488,6 +5531,11 @@ css-what@^6.0.1, css-what@^6.1.0:
|
|||||||
resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4"
|
resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4"
|
||||||
integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==
|
integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==
|
||||||
|
|
||||||
|
css.escape@^1.5.1:
|
||||||
|
version "1.5.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/css.escape/-/css.escape-1.5.1.tgz#42e27d4fa04ae32f931a4b4d4191fa9cddee97cb"
|
||||||
|
integrity sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==
|
||||||
|
|
||||||
cssesc@^3.0.0:
|
cssesc@^3.0.0:
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
|
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
|
||||||
@ -5928,7 +5976,7 @@ docusaurus-plugin-sass@^0.2.3:
|
|||||||
dependencies:
|
dependencies:
|
||||||
sass-loader "^10.1.1"
|
sass-loader "^10.1.1"
|
||||||
|
|
||||||
dom-accessibility-api@^0.5.9:
|
dom-accessibility-api@^0.5.6, dom-accessibility-api@^0.5.9:
|
||||||
version "0.5.16"
|
version "0.5.16"
|
||||||
resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz#5a7429e6066eb3664d911e33fb0e45de8eb08453"
|
resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz#5a7429e6066eb3664d911e33fb0e45de8eb08453"
|
||||||
integrity sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==
|
integrity sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==
|
||||||
@ -9918,7 +9966,7 @@ markdown-escapes@^1.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/markdown-escapes/-/markdown-escapes-1.0.4.tgz#c95415ef451499d7602b91095f3c8e8975f78535"
|
resolved "https://registry.yarnpkg.com/markdown-escapes/-/markdown-escapes-1.0.4.tgz#c95415ef451499d7602b91095f3c8e8975f78535"
|
||||||
integrity sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==
|
integrity sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==
|
||||||
|
|
||||||
marked@^4.3.0:
|
marked@^4.2.12, marked@^4.3.0:
|
||||||
version "4.3.0"
|
version "4.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/marked/-/marked-4.3.0.tgz#796362821b019f734054582038b116481b456cf3"
|
resolved "https://registry.yarnpkg.com/marked/-/marked-4.3.0.tgz#796362821b019f734054582038b116481b456cf3"
|
||||||
integrity sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==
|
integrity sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==
|
||||||
@ -10136,6 +10184,13 @@ minimatch@^6.1.6:
|
|||||||
dependencies:
|
dependencies:
|
||||||
brace-expansion "^2.0.1"
|
brace-expansion "^2.0.1"
|
||||||
|
|
||||||
|
minimatch@^7.1.3:
|
||||||
|
version "7.4.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-7.4.6.tgz#845d6f254d8f4a5e4fd6baf44d5f10c8448365fb"
|
||||||
|
integrity sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==
|
||||||
|
dependencies:
|
||||||
|
brace-expansion "^2.0.1"
|
||||||
|
|
||||||
minimatch@^7.4.1, minimatch@^7.4.2:
|
minimatch@^7.4.1, minimatch@^7.4.2:
|
||||||
version "7.4.3"
|
version "7.4.3"
|
||||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-7.4.3.tgz#012cbf110a65134bb354ae9773b55256cdb045a2"
|
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-7.4.3.tgz#012cbf110a65134bb354ae9773b55256cdb045a2"
|
||||||
@ -14256,6 +14311,16 @@ typedarray@^0.0.6:
|
|||||||
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
|
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
|
||||||
integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==
|
integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==
|
||||||
|
|
||||||
|
typedoc@^0.23.25:
|
||||||
|
version "0.23.28"
|
||||||
|
resolved "https://registry.yarnpkg.com/typedoc/-/typedoc-0.23.28.tgz#3ce9c36ef1c273fa849d2dea18651855100d3ccd"
|
||||||
|
integrity sha512-9x1+hZWTHEQcGoP7qFmlo4unUoVJLB0H/8vfO/7wqTnZxg4kPuji9y3uRzEu0ZKez63OJAUmiGhUrtukC6Uj3w==
|
||||||
|
dependencies:
|
||||||
|
lunr "^2.3.9"
|
||||||
|
marked "^4.2.12"
|
||||||
|
minimatch "^7.1.3"
|
||||||
|
shiki "^0.14.1"
|
||||||
|
|
||||||
typedoc@^0.24.7:
|
typedoc@^0.24.7:
|
||||||
version "0.24.7"
|
version "0.24.7"
|
||||||
resolved "https://registry.yarnpkg.com/typedoc/-/typedoc-0.24.7.tgz#7eeb272a1894b3789acc1a94b3f2ae8e7330ee39"
|
resolved "https://registry.yarnpkg.com/typedoc/-/typedoc-0.24.7.tgz#7eeb272a1894b3789acc1a94b3f2ae8e7330ee39"
|
||||||
|
Loading…
Reference in New Issue
Block a user