mirror of
https://github.com/mathuo/dockview
synced 2025-05-10 21:48:27 +00:00
Merge branch 'master' of https://github.com/mathuo/dockview into 582-expose-event-for-moving-tab-within-same-panel
This commit is contained in:
commit
cd59248f34
22
README.md
22
README.md
@ -1,7 +1,7 @@
|
|||||||
<div align="center">
|
<div align="center">
|
||||||
<h1>dockview</h1>
|
<h1>dockview</h1>
|
||||||
|
|
||||||
<p>Zero dependency layout manager supporting tabs, groups, grids and splitviews with ReactJS support written in TypeScript</p>
|
<p>Zero dependency layout manager supporting tabs, groups, grids and splitviews. Supports React, Vue and Vanilla TypeScript</p>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -36,23 +36,3 @@ Please see the website: https://dockview.dev
|
|||||||
- Security at mind - verifed publishing and builds through GitHub Actions
|
- Security at mind - verifed publishing and builds through GitHub Actions
|
||||||
|
|
||||||
Want to verify our builds? Go [here](https://www.npmjs.com/package/dockview#Provenance).
|
Want to verify our builds? Go [here](https://www.npmjs.com/package/dockview#Provenance).
|
||||||
|
|
||||||
## Quick start
|
|
||||||
|
|
||||||
Dockview has a peer dependency on `react >= 16.8.0` and `react-dom >= 16.8.0`. You can install dockview from [npm](https://www.npmjs.com/package/dockview).
|
|
||||||
|
|
||||||
```
|
|
||||||
npm install --save dockview
|
|
||||||
```
|
|
||||||
|
|
||||||
Within your project you must import or reference the stylesheet at `dockview/dist/styles/dockview.css` and attach a theme.
|
|
||||||
|
|
||||||
```css
|
|
||||||
@import '~dockview/dist/styles/dockview.css';
|
|
||||||
```
|
|
||||||
|
|
||||||
You should also attach a dockview theme to an element containing your components. For example:
|
|
||||||
|
|
||||||
```html
|
|
||||||
<body classname="dockview-theme-dark"></body>
|
|
||||||
```
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
"packages": [
|
"packages": [
|
||||||
"packages/*"
|
"packages/*"
|
||||||
],
|
],
|
||||||
"version": "1.14.0",
|
"version": "1.14.2",
|
||||||
"npmClient": "yarn",
|
"npmClient": "yarn",
|
||||||
"command": {
|
"command": {
|
||||||
"publish": {
|
"publish": {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "dockview-angular",
|
"name": "dockview-angular",
|
||||||
"version": "1.14.0",
|
"version": "1.14.2",
|
||||||
"description": "Zero dependency layout manager supporting tabs, grids and splitviews",
|
"description": "Zero dependency layout manager supporting tabs, grids and splitviews",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"splitview",
|
"splitview",
|
||||||
@ -54,6 +54,6 @@
|
|||||||
"test:cov": "cross-env ../../node_modules/.bin/jest --selectProjects dockview --coverage"
|
"test:cov": "cross-env ../../node_modules/.bin/jest --selectProjects dockview --coverage"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"dockview-core": "^1.14.0"
|
"dockview-core": "^1.14.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<div align="center">
|
<div align="center">
|
||||||
<h1>dockview</h1>
|
<h1>dockview</h1>
|
||||||
|
|
||||||
<p>Zero dependency layout manager supporting tabs, groups, grids and splitviews written in TypeScript</p>
|
<p>Zero dependency layout manager supporting tabs, groups, grids and splitviews. Supports React, Vue and Vanilla TypeScript</p>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -36,23 +36,3 @@ Please see the website: https://dockview.dev
|
|||||||
- Security at mind - verifed publishing and builds through GitHub Actions
|
- Security at mind - verifed publishing and builds through GitHub Actions
|
||||||
|
|
||||||
Want to verify our builds? Go [here](https://www.npmjs.com/package/dockview#Provenance).
|
Want to verify our builds? Go [here](https://www.npmjs.com/package/dockview#Provenance).
|
||||||
|
|
||||||
## Quick start
|
|
||||||
|
|
||||||
Dockview has a peer dependency on `react >= 16.8.0` and `react-dom >= 16.8.0`. You can install dockview from [npm](https://www.npmjs.com/package/dockview-core).
|
|
||||||
|
|
||||||
```
|
|
||||||
npm install --save dockview-core
|
|
||||||
```
|
|
||||||
|
|
||||||
Within your project you must import or reference the stylesheet at `dockview-core/dist/styles/dockview.css` and attach a theme.
|
|
||||||
|
|
||||||
```css
|
|
||||||
@import '~dockview-core/dist/styles/dockview.css';
|
|
||||||
```
|
|
||||||
|
|
||||||
You should also attach a dockview theme to an element containing your components. For example:
|
|
||||||
|
|
||||||
```html
|
|
||||||
<body classname="dockview-theme-dark"></body>
|
|
||||||
```
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "dockview-core",
|
"name": "dockview-core",
|
||||||
"version": "1.14.0",
|
"version": "1.14.2",
|
||||||
"description": "Zero dependency layout manager supporting tabs, grids and splitviews",
|
"description": "Zero dependency layout manager supporting tabs, grids and splitviews",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"splitview",
|
"splitview",
|
||||||
|
@ -1,7 +1,34 @@
|
|||||||
import { Overlay } from '../../dnd/overlay';
|
import { Overlay } from '../../dnd/overlay';
|
||||||
|
|
||||||
|
const mockGetBoundingClientRect = ({
|
||||||
|
left,
|
||||||
|
top,
|
||||||
|
height,
|
||||||
|
width,
|
||||||
|
}: {
|
||||||
|
left: number;
|
||||||
|
top: number;
|
||||||
|
height: number;
|
||||||
|
width: number;
|
||||||
|
}) => {
|
||||||
|
const result = {
|
||||||
|
left,
|
||||||
|
top,
|
||||||
|
height,
|
||||||
|
width,
|
||||||
|
right: left + width,
|
||||||
|
bottom: top + height,
|
||||||
|
x: left,
|
||||||
|
y: top,
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
...result,
|
||||||
|
toJSON: () => result,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
describe('overlay', () => {
|
describe('overlay', () => {
|
||||||
test('toJSON', () => {
|
test('toJSON, top left', () => {
|
||||||
const container = document.createElement('div');
|
const container = document.createElement('div');
|
||||||
const content = document.createElement('div');
|
const content = document.createElement('div');
|
||||||
|
|
||||||
@ -23,14 +50,26 @@ describe('overlay', () => {
|
|||||||
container.childNodes.item(0) as HTMLElement,
|
container.childNodes.item(0) as HTMLElement,
|
||||||
'getBoundingClientRect'
|
'getBoundingClientRect'
|
||||||
).mockImplementation(() => {
|
).mockImplementation(() => {
|
||||||
return { left: 80, top: 100, width: 40, height: 50 } as any;
|
return mockGetBoundingClientRect({
|
||||||
|
left: 80,
|
||||||
|
top: 100,
|
||||||
|
width: 40,
|
||||||
|
height: 50,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
jest.spyOn(container, 'getBoundingClientRect').mockImplementation(
|
jest.spyOn(container, 'getBoundingClientRect').mockImplementation(
|
||||||
() => {
|
() => {
|
||||||
return { left: 20, top: 30, width: 100, height: 100 } as any;
|
return mockGetBoundingClientRect({
|
||||||
|
left: 20,
|
||||||
|
top: 30,
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
cut.setBounds();
|
||||||
|
|
||||||
expect(cut.toJSON()).toEqual({
|
expect(cut.toJSON()).toEqual({
|
||||||
top: 70,
|
top: 70,
|
||||||
left: 60,
|
left: 60,
|
||||||
@ -39,7 +78,57 @@ describe('overlay', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('that out-of-bounds dimensions are fixed', () => {
|
test('toJSON, bottom right', () => {
|
||||||
|
const container = document.createElement('div');
|
||||||
|
const content = document.createElement('div');
|
||||||
|
|
||||||
|
document.body.appendChild(container);
|
||||||
|
container.appendChild(content);
|
||||||
|
|
||||||
|
const cut = new Overlay({
|
||||||
|
height: 200,
|
||||||
|
width: 100,
|
||||||
|
right: 10,
|
||||||
|
bottom: 20,
|
||||||
|
minimumInViewportWidth: 0,
|
||||||
|
minimumInViewportHeight: 0,
|
||||||
|
container,
|
||||||
|
content,
|
||||||
|
});
|
||||||
|
|
||||||
|
jest.spyOn(
|
||||||
|
container.childNodes.item(0) as HTMLElement,
|
||||||
|
'getBoundingClientRect'
|
||||||
|
).mockImplementation(() => {
|
||||||
|
return mockGetBoundingClientRect({
|
||||||
|
left: 80,
|
||||||
|
top: 100,
|
||||||
|
width: 40,
|
||||||
|
height: 50,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
jest.spyOn(container, 'getBoundingClientRect').mockImplementation(
|
||||||
|
() => {
|
||||||
|
return mockGetBoundingClientRect({
|
||||||
|
left: 20,
|
||||||
|
top: 30,
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
cut.setBounds();
|
||||||
|
|
||||||
|
expect(cut.toJSON()).toEqual({
|
||||||
|
bottom: -20,
|
||||||
|
right: 0,
|
||||||
|
width: 40,
|
||||||
|
height: 50,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('that out-of-bounds dimensions are fixed, top left', () => {
|
||||||
const container = document.createElement('div');
|
const container = document.createElement('div');
|
||||||
const content = document.createElement('div');
|
const content = document.createElement('div');
|
||||||
|
|
||||||
@ -61,14 +150,26 @@ describe('overlay', () => {
|
|||||||
container.childNodes.item(0) as HTMLElement,
|
container.childNodes.item(0) as HTMLElement,
|
||||||
'getBoundingClientRect'
|
'getBoundingClientRect'
|
||||||
).mockImplementation(() => {
|
).mockImplementation(() => {
|
||||||
return { left: 80, top: 100, width: 40, height: 50 } as any;
|
return mockGetBoundingClientRect({
|
||||||
|
left: 80,
|
||||||
|
top: 100,
|
||||||
|
width: 40,
|
||||||
|
height: 50,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
jest.spyOn(container, 'getBoundingClientRect').mockImplementation(
|
jest.spyOn(container, 'getBoundingClientRect').mockImplementation(
|
||||||
() => {
|
() => {
|
||||||
return { left: 20, top: 30, width: 100, height: 100 } as any;
|
return mockGetBoundingClientRect({
|
||||||
|
left: 20,
|
||||||
|
top: 30,
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
cut.setBounds();
|
||||||
|
|
||||||
expect(cut.toJSON()).toEqual({
|
expect(cut.toJSON()).toEqual({
|
||||||
top: 70,
|
top: 70,
|
||||||
left: 60,
|
left: 60,
|
||||||
@ -77,7 +178,57 @@ describe('overlay', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('setBounds', () => {
|
test('that out-of-bounds dimensions are fixed, bottom right', () => {
|
||||||
|
const container = document.createElement('div');
|
||||||
|
const content = document.createElement('div');
|
||||||
|
|
||||||
|
document.body.appendChild(container);
|
||||||
|
container.appendChild(content);
|
||||||
|
|
||||||
|
const cut = new Overlay({
|
||||||
|
height: 200,
|
||||||
|
width: 100,
|
||||||
|
bottom: -1000,
|
||||||
|
right: -1000,
|
||||||
|
minimumInViewportWidth: 0,
|
||||||
|
minimumInViewportHeight: 0,
|
||||||
|
container,
|
||||||
|
content,
|
||||||
|
});
|
||||||
|
|
||||||
|
jest.spyOn(
|
||||||
|
container.childNodes.item(0) as HTMLElement,
|
||||||
|
'getBoundingClientRect'
|
||||||
|
).mockImplementation(() => {
|
||||||
|
return mockGetBoundingClientRect({
|
||||||
|
left: 80,
|
||||||
|
top: 100,
|
||||||
|
width: 40,
|
||||||
|
height: 50,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
jest.spyOn(container, 'getBoundingClientRect').mockImplementation(
|
||||||
|
() => {
|
||||||
|
return mockGetBoundingClientRect({
|
||||||
|
left: 20,
|
||||||
|
top: 30,
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
cut.setBounds();
|
||||||
|
|
||||||
|
expect(cut.toJSON()).toEqual({
|
||||||
|
bottom: -20,
|
||||||
|
right: 0,
|
||||||
|
width: 40,
|
||||||
|
height: 50,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('setBounds, top left', () => {
|
||||||
const container = document.createElement('div');
|
const container = document.createElement('div');
|
||||||
const content = document.createElement('div');
|
const content = document.createElement('div');
|
||||||
|
|
||||||
@ -101,11 +252,21 @@ describe('overlay', () => {
|
|||||||
expect(element).toBeTruthy();
|
expect(element).toBeTruthy();
|
||||||
|
|
||||||
jest.spyOn(element, 'getBoundingClientRect').mockImplementation(() => {
|
jest.spyOn(element, 'getBoundingClientRect').mockImplementation(() => {
|
||||||
return { left: 300, top: 400, width: 1000, height: 1000 } as any;
|
return mockGetBoundingClientRect({
|
||||||
|
left: 300,
|
||||||
|
top: 400,
|
||||||
|
width: 200,
|
||||||
|
height: 100,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
jest.spyOn(container, 'getBoundingClientRect').mockImplementation(
|
jest.spyOn(container, 'getBoundingClientRect').mockImplementation(
|
||||||
() => {
|
() => {
|
||||||
return { left: 0, top: 0, width: 1000, height: 1000 } as any;
|
return mockGetBoundingClientRect({
|
||||||
|
left: 0,
|
||||||
|
top: 0,
|
||||||
|
width: 1000,
|
||||||
|
height: 1000,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -117,6 +278,56 @@ describe('overlay', () => {
|
|||||||
expect(element.style.top).toBe('400px');
|
expect(element.style.top).toBe('400px');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('setBounds, bottom right', () => {
|
||||||
|
const container = document.createElement('div');
|
||||||
|
const content = document.createElement('div');
|
||||||
|
|
||||||
|
document.body.appendChild(container);
|
||||||
|
container.appendChild(content);
|
||||||
|
|
||||||
|
const cut = new Overlay({
|
||||||
|
height: 1000,
|
||||||
|
width: 1000,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
minimumInViewportWidth: 0,
|
||||||
|
minimumInViewportHeight: 0,
|
||||||
|
container,
|
||||||
|
content,
|
||||||
|
});
|
||||||
|
|
||||||
|
const element: HTMLElement = container.querySelector(
|
||||||
|
'.dv-resize-container'
|
||||||
|
)!;
|
||||||
|
expect(element).toBeTruthy();
|
||||||
|
|
||||||
|
jest.spyOn(element, 'getBoundingClientRect').mockImplementation(() => {
|
||||||
|
return mockGetBoundingClientRect({
|
||||||
|
left: 500,
|
||||||
|
top: 500,
|
||||||
|
width: 200,
|
||||||
|
height: 100,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
jest.spyOn(container, 'getBoundingClientRect').mockImplementation(
|
||||||
|
() => {
|
||||||
|
return mockGetBoundingClientRect({
|
||||||
|
left: 0,
|
||||||
|
top: 0,
|
||||||
|
width: 1000,
|
||||||
|
height: 1000,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
cut.setBounds({ height: 100, width: 200, right: 300, bottom: 400 });
|
||||||
|
|
||||||
|
expect(element.style.height).toBe('100px');
|
||||||
|
expect(element.style.width).toBe('200px');
|
||||||
|
expect(element.style.right).toBe('300px');
|
||||||
|
expect(element.style.bottom).toBe('400px');
|
||||||
|
});
|
||||||
|
|
||||||
test('that the resize handles are added', () => {
|
test('that the resize handles are added', () => {
|
||||||
const container = document.createElement('div');
|
const container = document.createElement('div');
|
||||||
const content = document.createElement('div');
|
const content = document.createElement('div');
|
||||||
|
@ -0,0 +1,63 @@
|
|||||||
|
import { DockviewApi } from '../../../../api/component.api';
|
||||||
|
import { DockviewPanelApi, TitleEvent } from '../../../../api/dockviewPanelApi';
|
||||||
|
import { DefaultTab } from '../../../../dockview/components/tab/defaultTab';
|
||||||
|
import { fromPartial } from '@total-typescript/shoehorn';
|
||||||
|
import { Emitter } from '../../../../events';
|
||||||
|
import { fireEvent } from '@testing-library/dom';
|
||||||
|
|
||||||
|
describe('defaultTab', () => {
|
||||||
|
test('that title updates', () => {
|
||||||
|
const cut = new DefaultTab();
|
||||||
|
|
||||||
|
let el = cut.element.querySelector('.dv-default-tab-content');
|
||||||
|
expect(el).toBeTruthy();
|
||||||
|
expect(el!.textContent).toBe('');
|
||||||
|
|
||||||
|
const onDidTitleChange = new Emitter<TitleEvent>();
|
||||||
|
|
||||||
|
const api = fromPartial<DockviewPanelApi>({
|
||||||
|
onDidTitleChange: onDidTitleChange.event,
|
||||||
|
});
|
||||||
|
const containerApi = fromPartial<DockviewApi>({});
|
||||||
|
|
||||||
|
cut.init({
|
||||||
|
api,
|
||||||
|
containerApi,
|
||||||
|
params: {},
|
||||||
|
title: 'title_abc',
|
||||||
|
});
|
||||||
|
|
||||||
|
el = cut.element.querySelector('.dv-default-tab-content');
|
||||||
|
expect(el).toBeTruthy();
|
||||||
|
expect(el!.textContent).toBe('title_abc');
|
||||||
|
|
||||||
|
onDidTitleChange.fire({ title: 'title_def' });
|
||||||
|
|
||||||
|
expect(el!.textContent).toBe('title_def');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('that click closes tab', () => {
|
||||||
|
const cut = new DefaultTab();
|
||||||
|
|
||||||
|
const api = fromPartial<DockviewPanelApi>({
|
||||||
|
onDidTitleChange: jest.fn(),
|
||||||
|
close: jest.fn(),
|
||||||
|
});
|
||||||
|
const containerApi = fromPartial<DockviewApi>({});
|
||||||
|
|
||||||
|
cut.init({
|
||||||
|
api,
|
||||||
|
containerApi,
|
||||||
|
params: {},
|
||||||
|
title: 'title_abc',
|
||||||
|
});
|
||||||
|
|
||||||
|
let el = cut.element.querySelector('.dv-default-tab-action');
|
||||||
|
|
||||||
|
fireEvent.mouseDown(el!);
|
||||||
|
expect(api.close).toHaveBeenCalledTimes(0);
|
||||||
|
|
||||||
|
fireEvent.click(el!);
|
||||||
|
expect(api.close).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
});
|
@ -490,14 +490,11 @@ describe('tabsContainer', () => {
|
|||||||
const eventPreventDefaultSpy = jest.spyOn(event, 'preventDefault');
|
const eventPreventDefaultSpy = jest.spyOn(event, 'preventDefault');
|
||||||
fireEvent(container, event);
|
fireEvent(container, event);
|
||||||
|
|
||||||
expect(accessor.addFloatingGroup).toHaveBeenCalledWith(
|
expect(accessor.addFloatingGroup).toHaveBeenCalledWith(groupPanel, {
|
||||||
groupPanel,
|
x: 100,
|
||||||
{
|
y: 60,
|
||||||
x: 100,
|
inDragMode: true,
|
||||||
y: 60,
|
});
|
||||||
},
|
|
||||||
{ inDragMode: true }
|
|
||||||
);
|
|
||||||
expect(accessor.addFloatingGroup).toHaveBeenCalledTimes(1);
|
expect(accessor.addFloatingGroup).toHaveBeenCalledTimes(1);
|
||||||
expect(eventPreventDefaultSpy).toHaveBeenCalledTimes(1);
|
expect(eventPreventDefaultSpy).toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ import { CompositeDisposable } from '../../lifecycle';
|
|||||||
import { Emitter } from '../../events';
|
import { Emitter } from '../../events';
|
||||||
import { DockviewPanel, IDockviewPanel } from '../../dockview/dockviewPanel';
|
import { DockviewPanel, IDockviewPanel } from '../../dockview/dockviewPanel';
|
||||||
import { DockviewGroupPanel } from '../../dockview/dockviewGroupPanel';
|
import { DockviewGroupPanel } from '../../dockview/dockviewGroupPanel';
|
||||||
import { fireEvent } from '@testing-library/dom';
|
import { fireEvent, getByTestId, queryByTestId } from '@testing-library/dom';
|
||||||
import { getPanelData } from '../../dnd/dataTransfer';
|
import { getPanelData } from '../../dnd/dataTransfer';
|
||||||
import {
|
import {
|
||||||
GroupDragEvent,
|
GroupDragEvent,
|
||||||
@ -5165,6 +5165,60 @@ describe('dockviewComponent', () => {
|
|||||||
expect(panel4.api.isVisible).toBeTruthy();
|
expect(panel4.api.isVisible).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('setVisible #1', () => {
|
||||||
|
const container = document.createElement('div');
|
||||||
|
|
||||||
|
const dockview = new DockviewComponent({
|
||||||
|
parentElement: container,
|
||||||
|
createComponent(options) {
|
||||||
|
switch (options.name) {
|
||||||
|
case 'default':
|
||||||
|
return new PanelContentPartTest(
|
||||||
|
options.id,
|
||||||
|
options.name
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
throw new Error(`unsupported`);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const api = new DockviewApi(dockview);
|
||||||
|
|
||||||
|
dockview.layout(1000, 1000);
|
||||||
|
|
||||||
|
const panel1 = api.addPanel({
|
||||||
|
id: 'panel1',
|
||||||
|
component: 'default',
|
||||||
|
});
|
||||||
|
const panel2 = api.addPanel({
|
||||||
|
id: 'panel2',
|
||||||
|
component: 'default',
|
||||||
|
position: { referencePanel: panel1, direction: 'below' },
|
||||||
|
});
|
||||||
|
|
||||||
|
const panel3 = api.addPanel({
|
||||||
|
id: 'panel3',
|
||||||
|
component: 'default',
|
||||||
|
position: { referencePanel: panel1, direction: 'below' },
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(api.groups.length).toBe(3);
|
||||||
|
|
||||||
|
panel1.group.api.setVisible(false);
|
||||||
|
panel2.group.api.setVisible(false);
|
||||||
|
panel3.group.api.setVisible(false);
|
||||||
|
|
||||||
|
expect(panel1.group.api.isVisible).toBeFalsy();
|
||||||
|
expect(panel2.group.api.isVisible).toBeFalsy();
|
||||||
|
expect(panel3.group.api.isVisible).toBeFalsy();
|
||||||
|
|
||||||
|
panel1.group.api.setVisible(true);
|
||||||
|
|
||||||
|
expect(panel1.group.api.isVisible).toBeTruthy();
|
||||||
|
expect(panel2.group.api.isVisible).toBeFalsy();
|
||||||
|
expect(panel3.group.api.isVisible).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
describe('addPanel', () => {
|
describe('addPanel', () => {
|
||||||
test('that can add panel', () => {
|
test('that can add panel', () => {
|
||||||
const container = document.createElement('div');
|
const container = document.createElement('div');
|
||||||
@ -5497,4 +5551,57 @@ describe('dockviewComponent', () => {
|
|||||||
expect(api.panels.length).toBe(3);
|
expect(api.panels.length).toBe(3);
|
||||||
expect(api.groups.length).toBe(3);
|
expect(api.groups.length).toBe(3);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('that watermark appears when all views are not visible', () => {
|
||||||
|
jest.useFakeTimers();
|
||||||
|
const container = document.createElement('div');
|
||||||
|
|
||||||
|
const dockview = new DockviewComponent({
|
||||||
|
parentElement: container,
|
||||||
|
createComponent(options) {
|
||||||
|
switch (options.name) {
|
||||||
|
case 'default':
|
||||||
|
return new PanelContentPartTest(
|
||||||
|
options.id,
|
||||||
|
options.name
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
throw new Error(`unsupported`);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const api = new DockviewApi(dockview);
|
||||||
|
|
||||||
|
dockview.layout(1000, 1000);
|
||||||
|
|
||||||
|
const panel1 = api.addPanel({
|
||||||
|
id: 'panel_1',
|
||||||
|
component: 'default',
|
||||||
|
});
|
||||||
|
const panel2 = api.addPanel({
|
||||||
|
id: 'panel_2',
|
||||||
|
component: 'default',
|
||||||
|
position: {
|
||||||
|
direction: 'right',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
let query = queryByTestId(container, 'watermark-component');
|
||||||
|
expect(query).toBeFalsy();
|
||||||
|
|
||||||
|
panel1.group.api.setVisible(false);
|
||||||
|
jest.runAllTicks(); // visibility events check fires on microtask-queue
|
||||||
|
query = queryByTestId(container, 'watermark-component');
|
||||||
|
expect(query).toBeFalsy();
|
||||||
|
|
||||||
|
panel2.group.api.setVisible(false);
|
||||||
|
jest.runAllTicks(); // visibility events check fires on microtask-queue
|
||||||
|
query = queryByTestId(container, 'watermark-component');
|
||||||
|
expect(query).toBeTruthy();
|
||||||
|
|
||||||
|
panel1.group.api.setVisible(true);
|
||||||
|
jest.runAllTicks(); // visibility events check fires on microtask-queue
|
||||||
|
query = queryByTestId(container, 'watermark-component');
|
||||||
|
expect(query).toBeFalsy();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -17,13 +17,9 @@ class TestPanel implements IGridPanelView {
|
|||||||
_onDidChange = new Emitter<IViewSize | undefined>();
|
_onDidChange = new Emitter<IViewSize | undefined>();
|
||||||
readonly onDidChange = this._onDidChange.event;
|
readonly onDidChange = this._onDidChange.event;
|
||||||
|
|
||||||
get isActive(): boolean {
|
isVisible: boolean = true;
|
||||||
return true;
|
isActive: boolean = true;
|
||||||
}
|
params: Parameters = {};
|
||||||
|
|
||||||
get params(): Parameters {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public readonly id: string,
|
public readonly id: string,
|
||||||
|
@ -5,6 +5,7 @@ import {
|
|||||||
IGridView,
|
IGridView,
|
||||||
IViewSize,
|
IViewSize,
|
||||||
SerializedGridview,
|
SerializedGridview,
|
||||||
|
getGridLocation,
|
||||||
orthogonal,
|
orthogonal,
|
||||||
} from '../../gridview/gridview';
|
} from '../../gridview/gridview';
|
||||||
import { Orientation, Sizing } from '../../splitview/splitview';
|
import { Orientation, Sizing } from '../../splitview/splitview';
|
||||||
@ -18,7 +19,7 @@ class MockGridview implements IGridView {
|
|||||||
IViewSize | undefined
|
IViewSize | undefined
|
||||||
>().event;
|
>().event;
|
||||||
element: HTMLElement = document.createElement('div');
|
element: HTMLElement = document.createElement('div');
|
||||||
|
isVisible: boolean = true;
|
||||||
width: number = 0;
|
width: number = 0;
|
||||||
height: number = 0;
|
height: number = 0;
|
||||||
|
|
||||||
@ -1105,4 +1106,102 @@ describe('gridview', () => {
|
|||||||
|
|
||||||
expect(gridview.hasMaximizedView()).toBeFalsy();
|
expect(gridview.hasMaximizedView()).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('visibility check', () => {
|
||||||
|
const gridview = new Gridview(
|
||||||
|
true,
|
||||||
|
{ separatorBorder: '' },
|
||||||
|
Orientation.HORIZONTAL
|
||||||
|
);
|
||||||
|
gridview.layout(1000, 1000);
|
||||||
|
|
||||||
|
const view1 = new MockGridview('1');
|
||||||
|
const view2 = new MockGridview('2');
|
||||||
|
const view3 = new MockGridview('3');
|
||||||
|
const view4 = new MockGridview('4');
|
||||||
|
const view5 = new MockGridview('5');
|
||||||
|
const view6 = new MockGridview('6');
|
||||||
|
|
||||||
|
gridview.addView(view1, Sizing.Distribute, [0]);
|
||||||
|
gridview.addView(view2, Sizing.Distribute, [1]);
|
||||||
|
gridview.addView(view3, Sizing.Distribute, [1, 1]);
|
||||||
|
gridview.addView(view4, Sizing.Distribute, [1, 1, 0]);
|
||||||
|
gridview.addView(view5, Sizing.Distribute, [1, 1, 0, 0]);
|
||||||
|
gridview.addView(view6, Sizing.Distribute, [1, 1, 0, 0, 0]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* _____________________________________________
|
||||||
|
* | | |
|
||||||
|
* | | 2 |
|
||||||
|
* | | |
|
||||||
|
* | 1 |_______________________|
|
||||||
|
* | | | 4 |
|
||||||
|
* | | 3 |_____________|
|
||||||
|
* | | | 5 | 6 |
|
||||||
|
* |_____________________|_________|______|______|
|
||||||
|
*/
|
||||||
|
|
||||||
|
function assertVisibility(visibility: boolean[]) {
|
||||||
|
expect(gridview.isViewVisible(getGridLocation(view1.element))).toBe(
|
||||||
|
visibility[0]
|
||||||
|
);
|
||||||
|
expect(gridview.isViewVisible(getGridLocation(view2.element))).toBe(
|
||||||
|
visibility[1]
|
||||||
|
);
|
||||||
|
expect(gridview.isViewVisible(getGridLocation(view3.element))).toBe(
|
||||||
|
visibility[2]
|
||||||
|
);
|
||||||
|
expect(gridview.isViewVisible(getGridLocation(view4.element))).toBe(
|
||||||
|
visibility[3]
|
||||||
|
);
|
||||||
|
expect(gridview.isViewVisible(getGridLocation(view5.element))).toBe(
|
||||||
|
visibility[4]
|
||||||
|
);
|
||||||
|
expect(gridview.isViewVisible(getGridLocation(view6.element))).toBe(
|
||||||
|
visibility[5]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// hide each view one by one
|
||||||
|
|
||||||
|
assertVisibility([true, true, true, true, true, true]);
|
||||||
|
|
||||||
|
gridview.setViewVisible(getGridLocation(view5.element), false);
|
||||||
|
assertVisibility([true, true, true, true, false, true]);
|
||||||
|
|
||||||
|
gridview.setViewVisible(getGridLocation(view4.element), false);
|
||||||
|
assertVisibility([true, true, true, false, false, true]);
|
||||||
|
|
||||||
|
gridview.setViewVisible(getGridLocation(view1.element), false);
|
||||||
|
assertVisibility([false, true, true, false, false, true]);
|
||||||
|
|
||||||
|
gridview.setViewVisible(getGridLocation(view2.element), false);
|
||||||
|
assertVisibility([false, false, true, false, false, true]);
|
||||||
|
|
||||||
|
gridview.setViewVisible(getGridLocation(view3.element), false);
|
||||||
|
assertVisibility([false, false, false, false, false, true]);
|
||||||
|
|
||||||
|
gridview.setViewVisible(getGridLocation(view6.element), false);
|
||||||
|
assertVisibility([false, false, false, false, false, false]);
|
||||||
|
|
||||||
|
// un-hide each view one by one
|
||||||
|
|
||||||
|
gridview.setViewVisible(getGridLocation(view1.element), true);
|
||||||
|
assertVisibility([true, false, false, false, false, false]);
|
||||||
|
|
||||||
|
gridview.setViewVisible(getGridLocation(view5.element), true);
|
||||||
|
assertVisibility([true, false, false, false, true, false]);
|
||||||
|
|
||||||
|
gridview.setViewVisible(getGridLocation(view6.element), true);
|
||||||
|
assertVisibility([true, false, false, false, true, true]);
|
||||||
|
|
||||||
|
gridview.setViewVisible(getGridLocation(view2.element), true);
|
||||||
|
assertVisibility([true, true, false, false, true, true]);
|
||||||
|
|
||||||
|
gridview.setViewVisible(getGridLocation(view3.element), true);
|
||||||
|
assertVisibility([true, true, true, false, true, true]);
|
||||||
|
|
||||||
|
gridview.setViewVisible(getGridLocation(view4.element), true);
|
||||||
|
assertVisibility([true, true, true, true, true, true]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -8,10 +8,8 @@ describe('math', () => {
|
|||||||
expect(clamp(55, 40, 50)).toBe(50);
|
expect(clamp(55, 40, 50)).toBe(50);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw an error if min > max', () => {
|
it('if min > max return min', () => {
|
||||||
expect(() => clamp(55, 50, 40)).toThrow(
|
expect(clamp(55, 50, 40)).toBe(50);
|
||||||
'50 > 40 is an invalid condition'
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
|
FloatingGroupOptions,
|
||||||
IDockviewComponent,
|
IDockviewComponent,
|
||||||
MovePanelEvent,
|
MovePanelEvent,
|
||||||
SerializedDockview,
|
SerializedDockview,
|
||||||
@ -43,7 +44,7 @@ import {
|
|||||||
GroupDragEvent,
|
GroupDragEvent,
|
||||||
TabDragEvent,
|
TabDragEvent,
|
||||||
} from '../dockview/components/titlebar/tabsContainer';
|
} from '../dockview/components/titlebar/tabsContainer';
|
||||||
import { Box } from '../types';
|
import { AnchoredBox, Box } from '../types';
|
||||||
import {
|
import {
|
||||||
DockviewDidDropEvent,
|
DockviewDidDropEvent,
|
||||||
DockviewWillDropEvent,
|
DockviewWillDropEvent,
|
||||||
@ -805,9 +806,9 @@ export class DockviewApi implements CommonApi<SerializedDockview> {
|
|||||||
*/
|
*/
|
||||||
addFloatingGroup(
|
addFloatingGroup(
|
||||||
item: IDockviewPanel | DockviewGroupPanel,
|
item: IDockviewPanel | DockviewGroupPanel,
|
||||||
coord?: { x: number; y: number }
|
options?: FloatingGroupOptions
|
||||||
): void {
|
): void {
|
||||||
return this.component.addFloatingGroup(item, coord);
|
return this.component.addFloatingGroup(item, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
export const DEFAULT_FLOATING_GROUP_OVERFLOW_SIZE = 100;
|
export const DEFAULT_FLOATING_GROUP_OVERFLOW_SIZE = 100;
|
||||||
|
|
||||||
export const DEFAULT_FLOATING_GROUP_POSITION = { left: 100, top: 100 };
|
export const DEFAULT_FLOATING_GROUP_POSITION = { left: 100, top: 100, width: 300, height: 300 };
|
||||||
|
@ -11,7 +11,7 @@ import {
|
|||||||
} from '../events';
|
} from '../events';
|
||||||
import { CompositeDisposable, MutableDisposable } from '../lifecycle';
|
import { CompositeDisposable, MutableDisposable } from '../lifecycle';
|
||||||
import { clamp } from '../math';
|
import { clamp } from '../math';
|
||||||
import { Box } from '../types';
|
import { AnchoredBox } from '../types';
|
||||||
|
|
||||||
const bringElementToFront = (() => {
|
const bringElementToFront = (() => {
|
||||||
let previous: HTMLElement | null = null;
|
let previous: HTMLElement | null = null;
|
||||||
@ -40,6 +40,9 @@ export class Overlay extends CompositeDisposable {
|
|||||||
private static MINIMUM_HEIGHT = 20;
|
private static MINIMUM_HEIGHT = 20;
|
||||||
private static MINIMUM_WIDTH = 20;
|
private static MINIMUM_WIDTH = 20;
|
||||||
|
|
||||||
|
private verticalAlignment: 'top' | 'bottom' | undefined;
|
||||||
|
private horiziontalAlignment: 'left' | 'right' | undefined;
|
||||||
|
|
||||||
set minimumInViewportWidth(value: number | undefined) {
|
set minimumInViewportWidth(value: number | undefined) {
|
||||||
this.options.minimumInViewportWidth = value;
|
this.options.minimumInViewportWidth = value;
|
||||||
}
|
}
|
||||||
@ -49,7 +52,7 @@ export class Overlay extends CompositeDisposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly options: Box & {
|
private readonly options: AnchoredBox & {
|
||||||
container: HTMLElement;
|
container: HTMLElement;
|
||||||
content: HTMLElement;
|
content: HTMLElement;
|
||||||
minimumInViewportWidth?: number;
|
minimumInViewportWidth?: number;
|
||||||
@ -78,23 +81,39 @@ export class Overlay extends CompositeDisposable {
|
|||||||
this.setBounds({
|
this.setBounds({
|
||||||
height: this.options.height,
|
height: this.options.height,
|
||||||
width: this.options.width,
|
width: this.options.width,
|
||||||
top: this.options.top,
|
...('top' in this.options && { top: this.options.top }),
|
||||||
left: this.options.left,
|
...('bottom' in this.options && { bottom: this.options.bottom }),
|
||||||
|
...('left' in this.options && { left: this.options.left }),
|
||||||
|
...('right' in this.options && { right: this.options.right }),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setBounds(bounds: Partial<Box> = {}): void {
|
setBounds(bounds: Partial<AnchoredBox> = {}): void {
|
||||||
if (typeof bounds.height === 'number') {
|
if (typeof bounds.height === 'number') {
|
||||||
this._element.style.height = `${bounds.height}px`;
|
this._element.style.height = `${bounds.height}px`;
|
||||||
}
|
}
|
||||||
if (typeof bounds.width === 'number') {
|
if (typeof bounds.width === 'number') {
|
||||||
this._element.style.width = `${bounds.width}px`;
|
this._element.style.width = `${bounds.width}px`;
|
||||||
}
|
}
|
||||||
if (typeof bounds.top === 'number') {
|
if ('top' in bounds && typeof bounds.top === 'number') {
|
||||||
this._element.style.top = `${bounds.top}px`;
|
this._element.style.top = `${bounds.top}px`;
|
||||||
|
this._element.style.bottom = 'auto';
|
||||||
|
this.verticalAlignment = 'top';
|
||||||
}
|
}
|
||||||
if (typeof bounds.left === 'number') {
|
if ('bottom' in bounds && typeof bounds.bottom === 'number') {
|
||||||
|
this._element.style.bottom = `${bounds.bottom}px`;
|
||||||
|
this._element.style.top = 'auto';
|
||||||
|
this.verticalAlignment = 'bottom';
|
||||||
|
}
|
||||||
|
if ('left' in bounds && typeof bounds.left === 'number') {
|
||||||
this._element.style.left = `${bounds.left}px`;
|
this._element.style.left = `${bounds.left}px`;
|
||||||
|
this._element.style.right = 'auto';
|
||||||
|
this.horiziontalAlignment = 'left';
|
||||||
|
}
|
||||||
|
if ('right' in bounds && typeof bounds.right === 'number') {
|
||||||
|
this._element.style.right = `${bounds.right}px`;
|
||||||
|
this._element.style.left = 'auto';
|
||||||
|
this.horiziontalAlignment = 'right';
|
||||||
}
|
}
|
||||||
|
|
||||||
const containerRect = this.options.container.getBoundingClientRect();
|
const containerRect = this.options.container.getBoundingClientRect();
|
||||||
@ -106,39 +125,77 @@ export class Overlay extends CompositeDisposable {
|
|||||||
const xOffset = Math.max(0, this.getMinimumWidth(overlayRect.width));
|
const xOffset = Math.max(0, this.getMinimumWidth(overlayRect.width));
|
||||||
|
|
||||||
// a minimum height of minimumViewportHeight must be inside the viewport
|
// a minimum height of minimumViewportHeight must be inside the viewport
|
||||||
const yOffset =
|
const yOffset = Math.max(0, this.getMinimumHeight(overlayRect.height));
|
||||||
typeof this.options.minimumInViewportHeight === 'number'
|
|
||||||
? Math.max(0, this.getMinimumHeight(overlayRect.height))
|
|
||||||
: 0;
|
|
||||||
|
|
||||||
const left = clamp(
|
if (this.verticalAlignment === 'top') {
|
||||||
overlayRect.left - containerRect.left,
|
const top = clamp(
|
||||||
-xOffset,
|
overlayRect.top - containerRect.top,
|
||||||
Math.max(0, containerRect.width - overlayRect.width + xOffset)
|
-yOffset,
|
||||||
);
|
Math.max(0, containerRect.height - overlayRect.height + yOffset)
|
||||||
|
);
|
||||||
|
this._element.style.top = `${top}px`;
|
||||||
|
this._element.style.bottom = 'auto';
|
||||||
|
}
|
||||||
|
|
||||||
const top = clamp(
|
if (this.verticalAlignment === 'bottom') {
|
||||||
overlayRect.top - containerRect.top,
|
const bottom = clamp(
|
||||||
-yOffset,
|
containerRect.bottom - overlayRect.bottom,
|
||||||
Math.max(0, containerRect.height - overlayRect.height + yOffset)
|
-yOffset,
|
||||||
);
|
Math.max(0, containerRect.height - overlayRect.height + yOffset)
|
||||||
|
);
|
||||||
|
this._element.style.bottom = `${bottom}px`;
|
||||||
|
this._element.style.top = 'auto';
|
||||||
|
}
|
||||||
|
|
||||||
this._element.style.left = `${left}px`;
|
if (this.horiziontalAlignment === 'left') {
|
||||||
this._element.style.top = `${top}px`;
|
const left = clamp(
|
||||||
|
overlayRect.left - containerRect.left,
|
||||||
|
-xOffset,
|
||||||
|
Math.max(0, containerRect.width - overlayRect.width + xOffset)
|
||||||
|
);
|
||||||
|
this._element.style.left = `${left}px`;
|
||||||
|
this._element.style.right = 'auto';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.horiziontalAlignment === 'right') {
|
||||||
|
const right = clamp(
|
||||||
|
containerRect.right - overlayRect.right,
|
||||||
|
-xOffset,
|
||||||
|
Math.max(0, containerRect.width - overlayRect.width + xOffset)
|
||||||
|
);
|
||||||
|
this._element.style.right = `${right}px`;
|
||||||
|
this._element.style.left = 'auto';
|
||||||
|
}
|
||||||
|
|
||||||
this._onDidChange.fire();
|
this._onDidChange.fire();
|
||||||
}
|
}
|
||||||
|
|
||||||
toJSON(): Box {
|
toJSON(): AnchoredBox {
|
||||||
const container = this.options.container.getBoundingClientRect();
|
const container = this.options.container.getBoundingClientRect();
|
||||||
const element = this._element.getBoundingClientRect();
|
const element = this._element.getBoundingClientRect();
|
||||||
|
|
||||||
return {
|
const result: any = {};
|
||||||
top: element.top - container.top,
|
|
||||||
left: element.left - container.left,
|
if (this.verticalAlignment === 'top') {
|
||||||
width: element.width,
|
result.top = parseFloat(this._element.style.top);
|
||||||
height: element.height,
|
} else if (this.verticalAlignment === 'bottom') {
|
||||||
};
|
result.bottom = parseFloat(this._element.style.bottom);
|
||||||
|
} else {
|
||||||
|
result.top = element.top - container.top;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.horiziontalAlignment === 'left') {
|
||||||
|
result.left = parseFloat(this._element.style.left);
|
||||||
|
} else if (this.horiziontalAlignment === 'right') {
|
||||||
|
result.right = parseFloat(this._element.style.right);
|
||||||
|
} else {
|
||||||
|
result.left = element.left - container.left;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.width = element.width;
|
||||||
|
result.height = element.height;
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
setupDrag(
|
setupDrag(
|
||||||
@ -193,18 +250,7 @@ export class Overlay extends CompositeDisposable {
|
|||||||
);
|
);
|
||||||
const yOffset = Math.max(
|
const yOffset = Math.max(
|
||||||
0,
|
0,
|
||||||
this.options.minimumInViewportHeight
|
this.getMinimumHeight(overlayRect.height)
|
||||||
? this.getMinimumHeight(overlayRect.height)
|
|
||||||
: 0
|
|
||||||
);
|
|
||||||
|
|
||||||
const left = clamp(
|
|
||||||
x - offset.x,
|
|
||||||
-xOffset,
|
|
||||||
Math.max(
|
|
||||||
0,
|
|
||||||
containerRect.width - overlayRect.width + xOffset
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const top = clamp(
|
const top = clamp(
|
||||||
@ -216,7 +262,53 @@ export class Overlay extends CompositeDisposable {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
this.setBounds({ top, left });
|
const bottom = clamp(
|
||||||
|
offset.y -
|
||||||
|
y +
|
||||||
|
containerRect.height -
|
||||||
|
overlayRect.height,
|
||||||
|
-yOffset,
|
||||||
|
Math.max(
|
||||||
|
0,
|
||||||
|
containerRect.height - overlayRect.height + yOffset
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
const left = clamp(
|
||||||
|
x - offset.x,
|
||||||
|
-xOffset,
|
||||||
|
Math.max(
|
||||||
|
0,
|
||||||
|
containerRect.width - overlayRect.width + xOffset
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
const right = clamp(
|
||||||
|
offset.x - x + containerRect.width - overlayRect.width,
|
||||||
|
-xOffset,
|
||||||
|
Math.max(
|
||||||
|
0,
|
||||||
|
containerRect.width - overlayRect.width + xOffset
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
const bounds: any = {};
|
||||||
|
|
||||||
|
// Anchor to top or to bottom depending on which one is closer
|
||||||
|
if (top <= bottom) {
|
||||||
|
bounds.top = top;
|
||||||
|
} else {
|
||||||
|
bounds.bottom = bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Anchor to left or to right depending on which one is closer
|
||||||
|
if (left <= right) {
|
||||||
|
bounds.left = left;
|
||||||
|
} else {
|
||||||
|
bounds.right = right;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setBounds(bounds);
|
||||||
}),
|
}),
|
||||||
addDisposableWindowListener(window, 'mouseup', () => {
|
addDisposableWindowListener(window, 'mouseup', () => {
|
||||||
toggleClass(
|
toggleClass(
|
||||||
@ -342,8 +434,10 @@ export class Overlay extends CompositeDisposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let top: number | undefined = undefined;
|
let top: number | undefined = undefined;
|
||||||
|
let bottom: number | undefined = undefined;
|
||||||
let height: number | undefined = undefined;
|
let height: number | undefined = undefined;
|
||||||
let left: number | undefined = undefined;
|
let left: number | undefined = undefined;
|
||||||
|
let right: number | undefined = undefined;
|
||||||
let width: number | undefined = undefined;
|
let width: number | undefined = undefined;
|
||||||
|
|
||||||
const moveTop = () => {
|
const moveTop = () => {
|
||||||
@ -363,10 +457,13 @@ export class Overlay extends CompositeDisposable {
|
|||||||
Overlay.MINIMUM_HEIGHT
|
Overlay.MINIMUM_HEIGHT
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
height =
|
height =
|
||||||
startPosition!.originalY +
|
startPosition!.originalY +
|
||||||
startPosition!.originalHeight -
|
startPosition!.originalHeight -
|
||||||
top;
|
top;
|
||||||
|
|
||||||
|
bottom = containerRect.height - top - height;
|
||||||
};
|
};
|
||||||
|
|
||||||
const moveBottom = () => {
|
const moveBottom = () => {
|
||||||
@ -384,6 +481,8 @@ export class Overlay extends CompositeDisposable {
|
|||||||
: Overlay.MINIMUM_HEIGHT,
|
: Overlay.MINIMUM_HEIGHT,
|
||||||
Number.MAX_VALUE
|
Number.MAX_VALUE
|
||||||
);
|
);
|
||||||
|
|
||||||
|
bottom = containerRect.height - top - height;
|
||||||
};
|
};
|
||||||
|
|
||||||
const moveLeft = () => {
|
const moveLeft = () => {
|
||||||
@ -406,6 +505,8 @@ export class Overlay extends CompositeDisposable {
|
|||||||
startPosition!.originalX +
|
startPosition!.originalX +
|
||||||
startPosition!.originalWidth -
|
startPosition!.originalWidth -
|
||||||
left;
|
left;
|
||||||
|
|
||||||
|
right = containerRect.width - left - width;
|
||||||
};
|
};
|
||||||
|
|
||||||
const moveRight = () => {
|
const moveRight = () => {
|
||||||
@ -423,6 +524,8 @@ export class Overlay extends CompositeDisposable {
|
|||||||
: Overlay.MINIMUM_WIDTH,
|
: Overlay.MINIMUM_WIDTH,
|
||||||
Number.MAX_VALUE
|
Number.MAX_VALUE
|
||||||
);
|
);
|
||||||
|
|
||||||
|
right = containerRect.width - left - width;
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (direction) {
|
switch (direction) {
|
||||||
@ -456,7 +559,26 @@ export class Overlay extends CompositeDisposable {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setBounds({ height, width, top, left });
|
const bounds: any = {};
|
||||||
|
|
||||||
|
// Anchor to top or to bottom depending on which one is closer
|
||||||
|
if (top! <= bottom!) {
|
||||||
|
bounds.top = top;
|
||||||
|
} else {
|
||||||
|
bounds.bottom = bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Anchor to left or to right depending on which one is closer
|
||||||
|
if (left! <= right!) {
|
||||||
|
bounds.left = left;
|
||||||
|
} else {
|
||||||
|
bounds.right = right;
|
||||||
|
}
|
||||||
|
|
||||||
|
bounds.height = height;
|
||||||
|
bounds.width = width;
|
||||||
|
|
||||||
|
this.setBounds(bounds);
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
dispose: () => {
|
dispose: () => {
|
||||||
@ -485,7 +607,7 @@ export class Overlay extends CompositeDisposable {
|
|||||||
if (typeof this.options.minimumInViewportHeight === 'number') {
|
if (typeof this.options.minimumInViewportHeight === 'number') {
|
||||||
return height - this.options.minimumInViewportHeight;
|
return height - this.options.minimumInViewportHeight;
|
||||||
}
|
}
|
||||||
return height;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
override dispose(): void {
|
override dispose(): void {
|
||||||
|
@ -1,16 +1,13 @@
|
|||||||
import { CompositeDisposable } from '../../../lifecycle';
|
import { CompositeDisposable } from '../../../lifecycle';
|
||||||
import { ITabRenderer, GroupPanelPartInitParameters } from '../../types';
|
import { ITabRenderer, GroupPanelPartInitParameters } from '../../types';
|
||||||
import { addDisposableListener } from '../../../events';
|
import { addDisposableListener } from '../../../events';
|
||||||
import { PanelUpdateEvent } from '../../../panel/types';
|
|
||||||
import { DockviewGroupPanel } from '../../dockviewGroupPanel';
|
|
||||||
import { createCloseButton } from '../../../svg';
|
import { createCloseButton } from '../../../svg';
|
||||||
|
|
||||||
export class DefaultTab extends CompositeDisposable implements ITabRenderer {
|
export class DefaultTab extends CompositeDisposable implements ITabRenderer {
|
||||||
private _element: HTMLElement;
|
private _element: HTMLElement;
|
||||||
private _content: HTMLElement;
|
private _content: HTMLElement;
|
||||||
private action: HTMLElement;
|
private action: HTMLElement;
|
||||||
//
|
private _title: string | undefined;
|
||||||
private params: GroupPanelPartInitParameters = {} as any;
|
|
||||||
|
|
||||||
get element(): HTMLElement {
|
get element(): HTMLElement {
|
||||||
return this._element;
|
return this._element;
|
||||||
@ -21,7 +18,7 @@ export class DefaultTab extends CompositeDisposable implements ITabRenderer {
|
|||||||
|
|
||||||
this._element = document.createElement('div');
|
this._element = document.createElement('div');
|
||||||
this._element.className = 'dv-default-tab';
|
this._element.className = 'dv-default-tab';
|
||||||
//
|
|
||||||
this._content = document.createElement('div');
|
this._content = document.createElement('div');
|
||||||
this._content.className = 'dv-default-tab-content';
|
this._content.className = 'dv-default-tab-content';
|
||||||
|
|
||||||
@ -29,10 +26,9 @@ export class DefaultTab extends CompositeDisposable implements ITabRenderer {
|
|||||||
this.action.className = 'dv-default-tab-action';
|
this.action.className = 'dv-default-tab-action';
|
||||||
this.action.appendChild(createCloseButton());
|
this.action.appendChild(createCloseButton());
|
||||||
|
|
||||||
//
|
|
||||||
this._element.appendChild(this._content);
|
this._element.appendChild(this._content);
|
||||||
this._element.appendChild(this.action);
|
this._element.appendChild(this.action);
|
||||||
//
|
|
||||||
this.addDisposables(
|
this.addDisposables(
|
||||||
addDisposableListener(this.action, 'mousedown', (ev) => {
|
addDisposableListener(this.action, 'mousedown', (ev) => {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
@ -42,40 +38,33 @@ export class DefaultTab extends CompositeDisposable implements ITabRenderer {
|
|||||||
this.render();
|
this.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
public update(event: PanelUpdateEvent): void {
|
init(params: GroupPanelPartInitParameters): void {
|
||||||
this.params = { ...this.params, ...event.params };
|
this._title = params.title;
|
||||||
|
|
||||||
|
this.addDisposables(
|
||||||
|
params.api.onDidTitleChange((event) => {
|
||||||
|
this._title = event.title;
|
||||||
|
this.render();
|
||||||
|
}),
|
||||||
|
addDisposableListener(this.action, 'mousedown', (ev) => {
|
||||||
|
ev.preventDefault();
|
||||||
|
}),
|
||||||
|
addDisposableListener(this.action, 'click', (ev) => {
|
||||||
|
if (ev.defaultPrevented) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ev.preventDefault();
|
||||||
|
params.api.close();
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
this.render();
|
this.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
focus(): void {
|
|
||||||
//noop
|
|
||||||
}
|
|
||||||
|
|
||||||
public init(params: GroupPanelPartInitParameters): void {
|
|
||||||
this.params = params;
|
|
||||||
this._content.textContent = params.title;
|
|
||||||
|
|
||||||
addDisposableListener(this.action, 'click', (ev) => {
|
|
||||||
ev.preventDefault(); //
|
|
||||||
this.params.api.close();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onGroupChange(_group: DockviewGroupPanel): void {
|
|
||||||
this.render();
|
|
||||||
}
|
|
||||||
|
|
||||||
onPanelVisibleChange(_isPanelVisible: boolean): void {
|
|
||||||
this.render();
|
|
||||||
}
|
|
||||||
|
|
||||||
public layout(_width: number, _height: number): void {
|
|
||||||
// noop
|
|
||||||
}
|
|
||||||
|
|
||||||
private render(): void {
|
private render(): void {
|
||||||
if (this._content.textContent !== this.params.title) {
|
if (this._content.textContent !== this._title) {
|
||||||
this._content.textContent = this.params.title;
|
this._content.textContent = this._title ?? '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -270,14 +270,11 @@ export class TabsContainer
|
|||||||
const { top: rootTop, left: rootLeft } =
|
const { top: rootTop, left: rootLeft } =
|
||||||
this.accessor.element.getBoundingClientRect();
|
this.accessor.element.getBoundingClientRect();
|
||||||
|
|
||||||
this.accessor.addFloatingGroup(
|
this.accessor.addFloatingGroup(this.group, {
|
||||||
this.group,
|
x: left - rootLeft + 20,
|
||||||
{
|
y: top - rootTop + 20,
|
||||||
x: left - rootLeft + 20,
|
inDragMode: true,
|
||||||
y: top - rootTop + 20,
|
});
|
||||||
},
|
|
||||||
{ inDragMode: true }
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
@ -380,14 +377,11 @@ export class TabsContainer
|
|||||||
const { top: rootTop, left: rootLeft } =
|
const { top: rootTop, left: rootLeft } =
|
||||||
this.accessor.element.getBoundingClientRect();
|
this.accessor.element.getBoundingClientRect();
|
||||||
|
|
||||||
this.accessor.addFloatingGroup(
|
this.accessor.addFloatingGroup(panel as DockviewPanel, {
|
||||||
panel as DockviewPanel,
|
x: left - rootLeft,
|
||||||
{
|
y: top - rootTop,
|
||||||
x: left - rootLeft,
|
inDragMode: true,
|
||||||
y: top - rootTop,
|
});
|
||||||
},
|
|
||||||
{ inDragMode: true }
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,11 +19,15 @@
|
|||||||
&.horizontal {
|
&.horizontal {
|
||||||
> .view-container > .view {
|
> .view-container > .view {
|
||||||
&:not(:last-child) {
|
&:not(:last-child) {
|
||||||
border-right: var(--dv-group-gap-size) solid transparent;
|
.groupview {
|
||||||
|
border-right: var(--dv-group-gap-size) solid transparent;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&:not(:first-child) {
|
&:not(:first-child) {
|
||||||
border-left: var(--dv-group-gap-size) solid transparent;
|
.groupview {
|
||||||
|
border-left: var(--dv-group-gap-size) solid transparent;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -31,11 +35,16 @@
|
|||||||
&.vertical {
|
&.vertical {
|
||||||
> .view-container > .view {
|
> .view-container > .view {
|
||||||
&:not(:last-child) {
|
&:not(:last-child) {
|
||||||
border-bottom: var(--dv-group-gap-size) solid transparent;
|
.groupview {
|
||||||
|
border-bottom: var(--dv-group-gap-size) solid
|
||||||
|
transparent;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&:not(:first-child) {
|
&:not(:first-child) {
|
||||||
border-top: var(--dv-group-gap-size) solid transparent;
|
.groupview {
|
||||||
|
border-top: var(--dv-group-gap-size) solid transparent;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,13 +51,13 @@ import { DockviewPanelModel } from './dockviewPanelModel';
|
|||||||
import { getPanelData } from '../dnd/dataTransfer';
|
import { getPanelData } from '../dnd/dataTransfer';
|
||||||
import { Parameters } from '../panel/types';
|
import { Parameters } from '../panel/types';
|
||||||
import { Overlay } from '../dnd/overlay';
|
import { Overlay } from '../dnd/overlay';
|
||||||
import { toggleClass, watchElementResize } from '../dom';
|
import { addTestId, toggleClass, watchElementResize } from '../dom';
|
||||||
import { DockviewFloatingGroupPanel } from './dockviewFloatingGroupPanel';
|
import { DockviewFloatingGroupPanel } from './dockviewFloatingGroupPanel';
|
||||||
import {
|
import {
|
||||||
GroupDragEvent,
|
GroupDragEvent,
|
||||||
TabDragEvent,
|
TabDragEvent,
|
||||||
} from './components/titlebar/tabsContainer';
|
} from './components/titlebar/tabsContainer';
|
||||||
import { Box } from '../types';
|
import { AnchoredBox, Box } from '../types';
|
||||||
import {
|
import {
|
||||||
DEFAULT_FLOATING_GROUP_OVERFLOW_SIZE,
|
DEFAULT_FLOATING_GROUP_OVERFLOW_SIZE,
|
||||||
DEFAULT_FLOATING_GROUP_POSITION,
|
DEFAULT_FLOATING_GROUP_POSITION,
|
||||||
@ -126,7 +126,7 @@ export interface PanelReference {
|
|||||||
|
|
||||||
export interface SerializedFloatingGroup {
|
export interface SerializedFloatingGroup {
|
||||||
data: GroupPanelViewState;
|
data: GroupPanelViewState;
|
||||||
position: Box;
|
position: AnchoredBox;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SerializedPopoutGroup {
|
export interface SerializedPopoutGroup {
|
||||||
@ -170,6 +170,17 @@ type MoveGroupOrPanelOptions = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export interface FloatingGroupOptions {
|
||||||
|
x?: number;
|
||||||
|
y?: number;
|
||||||
|
height?: number;
|
||||||
|
width?: number;
|
||||||
|
position?: AnchoredBox;
|
||||||
|
skipRemoveGroup?: boolean;
|
||||||
|
inDragMode?: boolean;
|
||||||
|
skipActiveGroup?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IDockviewComponent extends IBaseGrid<DockviewGroupPanel> {
|
export interface IDockviewComponent extends IBaseGrid<DockviewGroupPanel> {
|
||||||
readonly activePanel: IDockviewPanel | undefined;
|
readonly activePanel: IDockviewPanel | undefined;
|
||||||
readonly totalPanels: number;
|
readonly totalPanels: number;
|
||||||
@ -214,7 +225,7 @@ export interface IDockviewComponent extends IBaseGrid<DockviewGroupPanel> {
|
|||||||
//
|
//
|
||||||
addFloatingGroup(
|
addFloatingGroup(
|
||||||
item: IDockviewPanel | DockviewGroupPanel,
|
item: IDockviewPanel | DockviewGroupPanel,
|
||||||
coord?: { x: number; y: number }
|
options?: FloatingGroupOptions
|
||||||
): void;
|
): void;
|
||||||
addPopoutGroup(
|
addPopoutGroup(
|
||||||
item: IDockviewPanel | DockviewGroupPanel,
|
item: IDockviewPanel | DockviewGroupPanel,
|
||||||
@ -375,6 +386,9 @@ export class DockviewComponent
|
|||||||
this._onDidRemoveGroup,
|
this._onDidRemoveGroup,
|
||||||
this._onDidActiveGroupChange,
|
this._onDidActiveGroupChange,
|
||||||
this._onUnhandledDragOverEvent,
|
this._onUnhandledDragOverEvent,
|
||||||
|
this.onDidViewVisibilityChangeMicroTaskQueue(() => {
|
||||||
|
this.updateWatermark();
|
||||||
|
}),
|
||||||
this.onDidAdd((event) => {
|
this.onDidAdd((event) => {
|
||||||
if (!this._moving) {
|
if (!this._moving) {
|
||||||
this._onDidAddGroup.fire(event);
|
this._onDidAddGroup.fire(event);
|
||||||
@ -754,12 +768,7 @@ export class DockviewComponent
|
|||||||
|
|
||||||
addFloatingGroup(
|
addFloatingGroup(
|
||||||
item: DockviewPanel | DockviewGroupPanel,
|
item: DockviewPanel | DockviewGroupPanel,
|
||||||
coord?: { x?: number; y?: number; height?: number; width?: number },
|
options?: FloatingGroupOptions
|
||||||
options?: {
|
|
||||||
skipRemoveGroup?: boolean;
|
|
||||||
inDragMode: boolean;
|
|
||||||
skipActiveGroup?: boolean;
|
|
||||||
}
|
|
||||||
): void {
|
): void {
|
||||||
let group: DockviewGroupPanel;
|
let group: DockviewGroupPanel;
|
||||||
|
|
||||||
@ -820,22 +829,62 @@ export class DockviewComponent
|
|||||||
|
|
||||||
group.model.location = { type: 'floating' };
|
group.model.location = { type: 'floating' };
|
||||||
|
|
||||||
const overlayLeft =
|
function getAnchoredBox(): AnchoredBox {
|
||||||
typeof coord?.x === 'number'
|
if (options?.position) {
|
||||||
? Math.max(coord.x, 0)
|
const result: any = {};
|
||||||
: DEFAULT_FLOATING_GROUP_POSITION.left;
|
if ('left' in options.position) {
|
||||||
const overlayTop =
|
result.left = Math.max(options.position.left, 0);
|
||||||
typeof coord?.y === 'number'
|
} else if ('right' in options.position) {
|
||||||
? Math.max(coord.y, 0)
|
result.right = Math.max(options.position.right, 0);
|
||||||
: DEFAULT_FLOATING_GROUP_POSITION.top;
|
} else {
|
||||||
|
result.left = DEFAULT_FLOATING_GROUP_POSITION.left;
|
||||||
|
}
|
||||||
|
if ('top' in options.position) {
|
||||||
|
result.top = Math.max(options.position.top, 0);
|
||||||
|
} else if ('bottom' in options.position) {
|
||||||
|
result.bottom = Math.max(options.position.bottom, 0);
|
||||||
|
} else {
|
||||||
|
result.top = DEFAULT_FLOATING_GROUP_POSITION.top;
|
||||||
|
}
|
||||||
|
if ('width' in options.position) {
|
||||||
|
result.width = Math.max(options.position.width, 0);
|
||||||
|
} else {
|
||||||
|
result.width = DEFAULT_FLOATING_GROUP_POSITION.width;
|
||||||
|
}
|
||||||
|
if ('height' in options.position) {
|
||||||
|
result.height = Math.max(options.position.height, 0);
|
||||||
|
} else {
|
||||||
|
result.height = DEFAULT_FLOATING_GROUP_POSITION.height;
|
||||||
|
}
|
||||||
|
return result as AnchoredBox;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
left:
|
||||||
|
typeof options?.x === 'number'
|
||||||
|
? Math.max(options.x, 0)
|
||||||
|
: DEFAULT_FLOATING_GROUP_POSITION.left,
|
||||||
|
top:
|
||||||
|
typeof options?.y === 'number'
|
||||||
|
? Math.max(options.y, 0)
|
||||||
|
: DEFAULT_FLOATING_GROUP_POSITION.top,
|
||||||
|
width:
|
||||||
|
typeof options?.width === 'number'
|
||||||
|
? Math.max(options.width, 0)
|
||||||
|
: DEFAULT_FLOATING_GROUP_POSITION.width,
|
||||||
|
height:
|
||||||
|
typeof options?.height === 'number'
|
||||||
|
? Math.max(options.height, 0)
|
||||||
|
: DEFAULT_FLOATING_GROUP_POSITION.height,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const anchoredBox = getAnchoredBox();
|
||||||
|
|
||||||
const overlay = new Overlay({
|
const overlay = new Overlay({
|
||||||
container: this.gridview.element,
|
container: this.gridview.element,
|
||||||
content: group.element,
|
content: group.element,
|
||||||
height: coord?.height ?? 300,
|
...anchoredBox,
|
||||||
width: coord?.width ?? 300,
|
|
||||||
left: overlayLeft,
|
|
||||||
top: overlayTop,
|
|
||||||
minimumInViewportWidth:
|
minimumInViewportWidth:
|
||||||
this.options.floatingGroupBounds === 'boundedWithinViewport'
|
this.options.floatingGroupBounds === 'boundedWithinViewport'
|
||||||
? undefined
|
? undefined
|
||||||
@ -975,7 +1024,7 @@ export class DockviewComponent
|
|||||||
this.options.floatingGroupBounds?.minimumWidthWithinViewport;
|
this.options.floatingGroupBounds?.minimumWidthWithinViewport;
|
||||||
}
|
}
|
||||||
|
|
||||||
group.overlay.setBounds({});
|
group.overlay.setBounds();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1198,16 +1247,11 @@ export class DockviewComponent
|
|||||||
|
|
||||||
const group = createGroupFromSerializedState(data);
|
const group = createGroupFromSerializedState(data);
|
||||||
|
|
||||||
this.addFloatingGroup(
|
this.addFloatingGroup(group, {
|
||||||
group,
|
position: position,
|
||||||
{
|
skipRemoveGroup: true,
|
||||||
x: position.left,
|
inDragMode: false,
|
||||||
y: position.top,
|
});
|
||||||
height: position.height,
|
|
||||||
width: position.width,
|
|
||||||
},
|
|
||||||
{ skipRemoveGroup: true, inDragMode: false }
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const serializedPopoutGroups = data.popoutGroups ?? [];
|
const serializedPopoutGroups = data.popoutGroups ?? [];
|
||||||
@ -1390,7 +1434,8 @@ export class DockviewComponent
|
|||||||
? options.floating
|
? options.floating
|
||||||
: {};
|
: {};
|
||||||
|
|
||||||
this.addFloatingGroup(group, o, {
|
this.addFloatingGroup(group, {
|
||||||
|
...o,
|
||||||
inDragMode: false,
|
inDragMode: false,
|
||||||
skipRemoveGroup: true,
|
skipRemoveGroup: true,
|
||||||
skipActiveGroup: true,
|
skipActiveGroup: true,
|
||||||
@ -1443,7 +1488,8 @@ export class DockviewComponent
|
|||||||
? options.floating
|
? options.floating
|
||||||
: {};
|
: {};
|
||||||
|
|
||||||
this.addFloatingGroup(group, coordinates, {
|
this.addFloatingGroup(group, {
|
||||||
|
...coordinates,
|
||||||
inDragMode: false,
|
inDragMode: false,
|
||||||
skipRemoveGroup: true,
|
skipRemoveGroup: true,
|
||||||
skipActiveGroup: true,
|
skipActiveGroup: true,
|
||||||
@ -1525,6 +1571,7 @@ export class DockviewComponent
|
|||||||
|
|
||||||
const watermarkContainer = document.createElement('div');
|
const watermarkContainer = document.createElement('div');
|
||||||
watermarkContainer.className = 'dv-watermark-container';
|
watermarkContainer.className = 'dv-watermark-container';
|
||||||
|
addTestId(watermarkContainer, 'watermark-component');
|
||||||
watermarkContainer.appendChild(this.watermark.element);
|
watermarkContainer.appendChild(this.watermark.element);
|
||||||
|
|
||||||
this.gridview.element.appendChild(watermarkContainer);
|
this.gridview.element.appendChild(watermarkContainer);
|
||||||
|
@ -1,37 +1,22 @@
|
|||||||
import { Overlay } from '../dnd/overlay';
|
import { Overlay } from '../dnd/overlay';
|
||||||
import { CompositeDisposable } from '../lifecycle';
|
import { CompositeDisposable } from '../lifecycle';
|
||||||
|
import { AnchoredBox } from '../types';
|
||||||
import { DockviewGroupPanel, IDockviewGroupPanel } from './dockviewGroupPanel';
|
import { DockviewGroupPanel, IDockviewGroupPanel } from './dockviewGroupPanel';
|
||||||
|
|
||||||
export interface IDockviewFloatingGroupPanel {
|
export interface IDockviewFloatingGroupPanel {
|
||||||
readonly group: IDockviewGroupPanel;
|
readonly group: IDockviewGroupPanel;
|
||||||
position(
|
position(bounds: Partial<AnchoredBox>): void;
|
||||||
bounds: Partial<{
|
|
||||||
top: number;
|
|
||||||
left: number;
|
|
||||||
height: number;
|
|
||||||
width: number;
|
|
||||||
}>
|
|
||||||
): void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DockviewFloatingGroupPanel
|
export class DockviewFloatingGroupPanel
|
||||||
extends CompositeDisposable
|
extends CompositeDisposable
|
||||||
implements IDockviewFloatingGroupPanel
|
implements IDockviewFloatingGroupPanel {
|
||||||
{
|
|
||||||
constructor(readonly group: DockviewGroupPanel, readonly overlay: Overlay) {
|
constructor(readonly group: DockviewGroupPanel, readonly overlay: Overlay) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.addDisposables(overlay);
|
this.addDisposables(overlay);
|
||||||
}
|
}
|
||||||
|
|
||||||
position(
|
position(bounds: Partial<AnchoredBox>): void {
|
||||||
bounds: Partial<{
|
|
||||||
top: number;
|
|
||||||
left: number;
|
|
||||||
height: number;
|
|
||||||
width: number;
|
|
||||||
}>
|
|
||||||
): void {
|
|
||||||
this.overlay.setBounds(bounds);
|
this.overlay.setBounds(bounds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ import {
|
|||||||
import { IDockviewPanel } from './dockviewPanel';
|
import { IDockviewPanel } from './dockviewPanel';
|
||||||
import { DockviewPanelRenderer } from '../overlayRenderContainer';
|
import { DockviewPanelRenderer } from '../overlayRenderContainer';
|
||||||
import { IGroupHeaderProps } from './framework';
|
import { IGroupHeaderProps } from './framework';
|
||||||
|
import { AnchoredBox } from '../types';
|
||||||
|
|
||||||
export interface IHeaderActionsRenderer extends IDisposable {
|
export interface IHeaderActionsRenderer extends IDisposable {
|
||||||
readonly element: HTMLElement;
|
readonly element: HTMLElement;
|
||||||
@ -37,11 +38,11 @@ export interface DockviewOptions {
|
|||||||
singleTabMode?: 'fullwidth' | 'default';
|
singleTabMode?: 'fullwidth' | 'default';
|
||||||
disableFloatingGroups?: boolean;
|
disableFloatingGroups?: boolean;
|
||||||
floatingGroupBounds?:
|
floatingGroupBounds?:
|
||||||
| 'boundedWithinViewport'
|
| 'boundedWithinViewport'
|
||||||
| {
|
| {
|
||||||
minimumHeightWithinViewport?: number;
|
minimumHeightWithinViewport?: number;
|
||||||
minimumWidthWithinViewport?: number;
|
minimumWidthWithinViewport?: number;
|
||||||
};
|
};
|
||||||
popoutUrl?: string;
|
popoutUrl?: string;
|
||||||
defaultRenderer?: DockviewPanelRenderer;
|
defaultRenderer?: DockviewPanelRenderer;
|
||||||
debug?: boolean;
|
debug?: boolean;
|
||||||
@ -74,7 +75,7 @@ export class DockviewUnhandledDragOverEvent implements DockviewDndOverlayEvent {
|
|||||||
readonly position: Position,
|
readonly position: Position,
|
||||||
readonly getData: () => PanelTransfer | undefined,
|
readonly getData: () => PanelTransfer | undefined,
|
||||||
readonly group?: DockviewGroupPanel
|
readonly group?: DockviewGroupPanel
|
||||||
) {}
|
) { }
|
||||||
|
|
||||||
accept(): void {
|
accept(): void {
|
||||||
this._isAccepted = true;
|
this._isAccepted = true;
|
||||||
@ -176,13 +177,8 @@ export function isPanelOptionsWithGroup(
|
|||||||
|
|
||||||
type AddPanelFloatingGroupUnion = {
|
type AddPanelFloatingGroupUnion = {
|
||||||
floating:
|
floating:
|
||||||
| {
|
| Partial<AnchoredBox>
|
||||||
height?: number;
|
| true;
|
||||||
width?: number;
|
|
||||||
x?: number;
|
|
||||||
y?: number;
|
|
||||||
}
|
|
||||||
| true;
|
|
||||||
position: never;
|
position: never;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -253,3 +253,7 @@ export function isInDocument(element: Element): boolean {
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function addTestId(element: HTMLElement, id: string): void {
|
||||||
|
element.setAttribute('data-testid', id);
|
||||||
|
}
|
||||||
|
@ -93,6 +93,10 @@ export abstract class BaseGrid<T extends IGridPanelView>
|
|||||||
readonly onDidLayoutChange: Event<void> =
|
readonly onDidLayoutChange: Event<void> =
|
||||||
this._bufferOnDidLayoutChange.onEvent;
|
this._bufferOnDidLayoutChange.onEvent;
|
||||||
|
|
||||||
|
private readonly _onDidViewVisibilityChangeMicroTaskQueue = new AsapEvent();
|
||||||
|
readonly onDidViewVisibilityChangeMicroTaskQueue =
|
||||||
|
this._onDidViewVisibilityChangeMicroTaskQueue.onEvent;
|
||||||
|
|
||||||
get id(): string {
|
get id(): string {
|
||||||
return this._id;
|
return this._id;
|
||||||
}
|
}
|
||||||
@ -158,6 +162,12 @@ export abstract class BaseGrid<T extends IGridPanelView>
|
|||||||
this.layout(0, 0, true); // set some elements height/widths
|
this.layout(0, 0, true); // set some elements height/widths
|
||||||
|
|
||||||
this.addDisposables(
|
this.addDisposables(
|
||||||
|
this.gridview.onDidViewVisibilityChange(() =>
|
||||||
|
this._onDidViewVisibilityChangeMicroTaskQueue.fire()
|
||||||
|
),
|
||||||
|
this.onDidViewVisibilityChangeMicroTaskQueue(() => {
|
||||||
|
this.layout(this.width, this.height, true);
|
||||||
|
}),
|
||||||
Disposable.from(() => {
|
Disposable.from(() => {
|
||||||
this.element.parentElement?.removeChild(this.element);
|
this.element.parentElement?.removeChild(this.element);
|
||||||
}),
|
}),
|
||||||
|
@ -33,9 +33,12 @@ export class BranchNode extends CompositeDisposable implements IView {
|
|||||||
readonly onDidChange: Event<{ size?: number; orthogonalSize?: number }> =
|
readonly onDidChange: Event<{ size?: number; orthogonalSize?: number }> =
|
||||||
this._onDidChange.event;
|
this._onDidChange.event;
|
||||||
|
|
||||||
private readonly _onDidVisibilityChange = new Emitter<boolean>();
|
private readonly _onDidVisibilityChange = new Emitter<{
|
||||||
readonly onDidVisibilityChange: Event<boolean> =
|
visible: boolean;
|
||||||
this._onDidVisibilityChange.event;
|
}>();
|
||||||
|
readonly onDidVisibilityChange: Event<{
|
||||||
|
visible: boolean;
|
||||||
|
}> = this._onDidVisibilityChange.event;
|
||||||
|
|
||||||
get width(): number {
|
get width(): number {
|
||||||
return this.orientation === Orientation.HORIZONTAL
|
return this.orientation === Orientation.HORIZONTAL
|
||||||
@ -200,10 +203,8 @@ export class BranchNode extends CompositeDisposable implements IView {
|
|||||||
this.setupChildrenEvents();
|
this.setupChildrenEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
setVisible(visible: boolean): void {
|
setVisible(_visible: boolean): void {
|
||||||
for (const child of this.children) {
|
// noop
|
||||||
child.setVisible(visible);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
isChildVisible(index: number): boolean {
|
isChildVisible(index: number): boolean {
|
||||||
@ -224,7 +225,9 @@ export class BranchNode extends CompositeDisposable implements IView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const wereAllChildrenHidden = this.splitview.contentSize === 0;
|
const wereAllChildrenHidden = this.splitview.contentSize === 0;
|
||||||
|
|
||||||
this.splitview.setViewVisible(index, visible);
|
this.splitview.setViewVisible(index, visible);
|
||||||
|
// }
|
||||||
const areAllChildrenHidden = this.splitview.contentSize === 0;
|
const areAllChildrenHidden = this.splitview.contentSize === 0;
|
||||||
|
|
||||||
// If all children are hidden then the parent should hide the entire splitview
|
// If all children are hidden then the parent should hide the entire splitview
|
||||||
@ -233,7 +236,7 @@ export class BranchNode extends CompositeDisposable implements IView {
|
|||||||
(visible && wereAllChildrenHidden) ||
|
(visible && wereAllChildrenHidden) ||
|
||||||
(!visible && areAllChildrenHidden)
|
(!visible && areAllChildrenHidden)
|
||||||
) {
|
) {
|
||||||
this._onDidVisibilityChange.fire(visible);
|
this._onDidVisibilityChange.fire({ visible });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,7 +338,7 @@ export class BranchNode extends CompositeDisposable implements IView {
|
|||||||
}),
|
}),
|
||||||
...this.children.map((c, i) => {
|
...this.children.map((c, i) => {
|
||||||
if (c instanceof BranchNode) {
|
if (c instanceof BranchNode) {
|
||||||
return c.onDidVisibilityChange((visible) => {
|
return c.onDidVisibilityChange(({ visible }) => {
|
||||||
this.setChildVisible(i, visible);
|
this.setChildVisible(i, visible);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -171,6 +171,7 @@ export interface IGridView {
|
|||||||
readonly maximumWidth: number;
|
readonly maximumWidth: number;
|
||||||
readonly minimumHeight: number;
|
readonly minimumHeight: number;
|
||||||
readonly maximumHeight: number;
|
readonly maximumHeight: number;
|
||||||
|
readonly isVisible: boolean;
|
||||||
priority?: LayoutPriority;
|
priority?: LayoutPriority;
|
||||||
layout(width: number, height: number): void;
|
layout(width: number, height: number): void;
|
||||||
toJSON(): object;
|
toJSON(): object;
|
||||||
@ -287,6 +288,9 @@ export class Gridview implements IDisposable {
|
|||||||
readonly onDidChange: Event<{ size?: number; orthogonalSize?: number }> =
|
readonly onDidChange: Event<{ size?: number; orthogonalSize?: number }> =
|
||||||
this._onDidChange.event;
|
this._onDidChange.event;
|
||||||
|
|
||||||
|
private readonly _onDidViewVisibilityChange = new Emitter<void>();
|
||||||
|
readonly onDidViewVisibilityChange = this._onDidViewVisibilityChange.event;
|
||||||
|
|
||||||
private readonly _onDidMaximizedNodeChange = new Emitter<void>();
|
private readonly _onDidMaximizedNodeChange = new Emitter<void>();
|
||||||
readonly onDidMaximizedNodeChange = this._onDidMaximizedNodeChange.event;
|
readonly onDidMaximizedNodeChange = this._onDidMaximizedNodeChange.event;
|
||||||
|
|
||||||
@ -453,6 +457,8 @@ export class Gridview implements IDisposable {
|
|||||||
this.disposable.dispose();
|
this.disposable.dispose();
|
||||||
this._onDidChange.dispose();
|
this._onDidChange.dispose();
|
||||||
this._onDidMaximizedNodeChange.dispose();
|
this._onDidMaximizedNodeChange.dispose();
|
||||||
|
this._onDidViewVisibilityChange.dispose();
|
||||||
|
|
||||||
this.root.dispose();
|
this.root.dispose();
|
||||||
this._maximizedNode = undefined;
|
this._maximizedNode = undefined;
|
||||||
this.element.remove();
|
this.element.remove();
|
||||||
@ -531,12 +537,12 @@ export class Gridview implements IDisposable {
|
|||||||
children
|
children
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
result = new LeafNode(
|
const view = deserializer.fromJSON(node);
|
||||||
deserializer.fromJSON(node),
|
if (typeof node.visible === 'boolean') {
|
||||||
orientation,
|
view.setVisible?.(node.visible);
|
||||||
orthogonalSize,
|
}
|
||||||
node.size
|
|
||||||
);
|
result = new LeafNode(view, orientation, orthogonalSize, node.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -723,6 +729,8 @@ export class Gridview implements IDisposable {
|
|||||||
throw new Error('Invalid from location');
|
throw new Error('Invalid from location');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._onDidViewVisibilityChange.fire();
|
||||||
|
|
||||||
parent.setChildVisible(index, visible);
|
parent.setChildVisible(index, visible);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,6 +126,10 @@ export abstract class GridviewPanel<
|
|||||||
return this.api.isActive;
|
return this.api.isActive;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get isVisible(): boolean {
|
||||||
|
return this.api.isVisible;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
id: string,
|
id: string,
|
||||||
component: string,
|
component: string,
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
export const clamp = (value: number, min: number, max: number): number => {
|
export const clamp = (value: number, min: number, max: number): number => {
|
||||||
if (min > max) {
|
if (min > max) {
|
||||||
throw new Error(`${min} > ${max} is an invalid condition`);
|
/**
|
||||||
|
* caveat: an error should be thrown here if this was a proper `clamp` function but we need to handle
|
||||||
|
* cases where `min` > `max` and in those cases return `min`.
|
||||||
|
*/
|
||||||
|
return min;
|
||||||
}
|
}
|
||||||
return Math.min(max, Math.max(value, min));
|
return Math.min(max, Math.max(value, min));
|
||||||
};
|
};
|
||||||
|
@ -291,12 +291,8 @@ export class Splitview {
|
|||||||
throw new Error('Index out of bounds');
|
throw new Error('Index out of bounds');
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleClass(this.container, 'visible', visible);
|
|
||||||
|
|
||||||
const viewItem = this.viewItems[index];
|
const viewItem = this.viewItems[index];
|
||||||
|
|
||||||
toggleClass(this.container, 'visible', visible);
|
|
||||||
|
|
||||||
viewItem.setVisible(visible, viewItem.size);
|
viewItem.setVisible(visible, viewItem.size);
|
||||||
|
|
||||||
this.distributeEmptySpace(index);
|
this.distributeEmptySpace(index);
|
||||||
|
@ -8,3 +8,13 @@ export interface Box {
|
|||||||
height: number;
|
height: number;
|
||||||
width: number;
|
width: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TopLeft = { top: number; left: number };
|
||||||
|
type TopRight = { top: number; right: number };
|
||||||
|
type BottomLeft = { bottom: number; left: number };
|
||||||
|
type BottomRight = { bottom: number; right: number };
|
||||||
|
|
||||||
|
type AnchorPosition = TopLeft | TopRight | BottomLeft | BottomRight;
|
||||||
|
type Size = { width: number; height: number };
|
||||||
|
|
||||||
|
export type AnchoredBox = Size & AnchorPosition;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<div align="center">
|
<div align="center">
|
||||||
<h1>dockview</h1>
|
<h1>dockview</h1>
|
||||||
|
|
||||||
<p>Zero dependency layout manager supporting tabs, groups, grids and splitviews with ReactJS support written in TypeScript</p>
|
<p>Zero dependency layout manager supporting tabs, groups, grids and splitviews. Supports React, Vue and Vanilla TypeScript</p>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
##
|
##
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
Please see the website: https://dockview.dev
|
Please see the website: https://dockview.dev
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
@ -34,23 +36,3 @@ Please see the website: https://dockview.dev
|
|||||||
- Security at mind - verifed publishing and builds through GitHub Actions
|
- Security at mind - verifed publishing and builds through GitHub Actions
|
||||||
|
|
||||||
Want to verify our builds? Go [here](https://www.npmjs.com/package/dockview#Provenance).
|
Want to verify our builds? Go [here](https://www.npmjs.com/package/dockview#Provenance).
|
||||||
|
|
||||||
## Quick start
|
|
||||||
|
|
||||||
Dockview has a peer dependency on `react >= 16.8.0` and `react-dom >= 16.8.0`. You can install dockview from [npm](https://www.npmjs.com/package/dockview).
|
|
||||||
|
|
||||||
```
|
|
||||||
npm install --save dockview
|
|
||||||
```
|
|
||||||
|
|
||||||
Within your project you must import or reference the stylesheet at `dockview/dist/styles/dockview.css` and attach a theme.
|
|
||||||
|
|
||||||
```css
|
|
||||||
@import '~dockview/dist/styles/dockview.css';
|
|
||||||
```
|
|
||||||
|
|
||||||
You should also attach a dockview theme to an element containing your components. For example:
|
|
||||||
|
|
||||||
```html
|
|
||||||
<body classname="dockview-theme-dark"></body>
|
|
||||||
```
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "dockview-react",
|
"name": "dockview-react",
|
||||||
"version": "1.14.0",
|
"version": "1.14.2",
|
||||||
"description": "Zero dependency layout manager supporting tabs, grids and splitviews",
|
"description": "Zero dependency layout manager supporting tabs, grids and splitviews",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"splitview",
|
"splitview",
|
||||||
@ -54,6 +54,6 @@
|
|||||||
"test:cov": "cross-env ../../node_modules/.bin/jest --selectProjects dockview-react --coverage"
|
"test:cov": "cross-env ../../node_modules/.bin/jest --selectProjects dockview-react --coverage"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"dockview": "^1.14.0"
|
"dockview": "^1.14.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<div align="center">
|
<div align="center">
|
||||||
<h1>dockview</h1>
|
<h1>dockview</h1>
|
||||||
|
|
||||||
<p>Zero dependency layout manager supporting tabs, groups, grids and splitviews with ReactJS support written in TypeScript</p>
|
<p>Zero dependency layout manager supporting tabs, groups, grids and splitviews. Supports React, Vue and Vanilla TypeScript</p>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
##
|
##
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
Please see the website: https://dockview.dev
|
Please see the website: https://dockview.dev
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
@ -34,23 +36,3 @@ Please see the website: https://dockview.dev
|
|||||||
- Security at mind - verifed publishing and builds through GitHub Actions
|
- Security at mind - verifed publishing and builds through GitHub Actions
|
||||||
|
|
||||||
Want to verify our builds? Go [here](https://www.npmjs.com/package/dockview#Provenance).
|
Want to verify our builds? Go [here](https://www.npmjs.com/package/dockview#Provenance).
|
||||||
|
|
||||||
## Quick start
|
|
||||||
|
|
||||||
Dockview has a peer dependency on `react >= 16.8.0` and `react-dom >= 16.8.0`. You can install dockview from [npm](https://www.npmjs.com/package/dockview).
|
|
||||||
|
|
||||||
```
|
|
||||||
npm install --save dockview
|
|
||||||
```
|
|
||||||
|
|
||||||
Within your project you must import or reference the stylesheet at `dockview/dist/styles/dockview.css` and attach a theme.
|
|
||||||
|
|
||||||
```css
|
|
||||||
@import '~dockview/dist/styles/dockview.css';
|
|
||||||
```
|
|
||||||
|
|
||||||
You should also attach a dockview theme to an element containing your components. For example:
|
|
||||||
|
|
||||||
```html
|
|
||||||
<body classname="dockview-theme-dark"></body>
|
|
||||||
```
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "dockview-vue",
|
"name": "dockview-vue",
|
||||||
"version": "1.14.0",
|
"version": "1.14.2",
|
||||||
"description": "Zero dependency layout manager supporting tabs, grids and splitviews",
|
"description": "Zero dependency layout manager supporting tabs, grids and splitviews",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"splitview",
|
"splitview",
|
||||||
@ -52,6 +52,6 @@
|
|||||||
"test:cov": "cross-env ../../node_modules/.bin/jest --selectProjects dockview-vue --coverage"
|
"test:cov": "cross-env ../../node_modules/.bin/jest --selectProjects dockview-vue --coverage"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"dockview-core": "^1.14.0"
|
"dockview-core": "^1.14.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,55 +70,61 @@ PROPERTY_KEYS.forEach((coreOptionKey) => {
|
|||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (!el.value) {
|
if (!el.value) {
|
||||||
throw new Error('element is not mounted');
|
throw new Error('dockview-vue: element is not mounted');
|
||||||
|
}
|
||||||
|
|
||||||
|
const inst = getCurrentInstance();
|
||||||
|
|
||||||
|
if(!inst) {
|
||||||
|
throw new Error('dockview-vue: getCurrentInstance() returned null')
|
||||||
}
|
}
|
||||||
|
|
||||||
const frameworkOptions: DockviewFrameworkOptions = {
|
const frameworkOptions: DockviewFrameworkOptions = {
|
||||||
parentElement: el.value,
|
parentElement: el.value,
|
||||||
createComponent(options) {
|
createComponent(options) {
|
||||||
const component = findComponent(
|
const component = findComponent(
|
||||||
getCurrentInstance()!,
|
inst,
|
||||||
options.name
|
options.name
|
||||||
);
|
);
|
||||||
return new VueRenderer(component!, getCurrentInstance()!);
|
return new VueRenderer(component!, inst);
|
||||||
},
|
},
|
||||||
createTabComponent(options) {
|
createTabComponent(options) {
|
||||||
let component = findComponent(getCurrentInstance()!, options.name);
|
let component = findComponent(inst, options.name);
|
||||||
|
|
||||||
if (!component && props.defaultTabComponent) {
|
if (!component && props.defaultTabComponent) {
|
||||||
component = findComponent(
|
component = findComponent(
|
||||||
getCurrentInstance()!,
|
inst,
|
||||||
props.defaultTabComponent
|
props.defaultTabComponent
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (component) {
|
if (component) {
|
||||||
return new VueRenderer(component, getCurrentInstance()!);
|
return new VueRenderer(component, inst);
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
},
|
},
|
||||||
createWatermarkComponent: props.watermarkComponent
|
createWatermarkComponent: props.watermarkComponent
|
||||||
? () => {
|
? () => {
|
||||||
const component = findComponent(
|
const component = findComponent(
|
||||||
getCurrentInstance()!,
|
inst,
|
||||||
props.watermarkComponent!
|
props.watermarkComponent!
|
||||||
);
|
);
|
||||||
|
|
||||||
return new VueWatermarkRenderer(
|
return new VueWatermarkRenderer(
|
||||||
component!,
|
component!,
|
||||||
getCurrentInstance()!
|
inst
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
createLeftHeaderActionComponent: props.leftHeaderActionsComponent
|
createLeftHeaderActionComponent: props.leftHeaderActionsComponent
|
||||||
? (group) => {
|
? (group) => {
|
||||||
const component = findComponent(
|
const component = findComponent(
|
||||||
getCurrentInstance()!,
|
inst,
|
||||||
props.leftHeaderActionsComponent!
|
props.leftHeaderActionsComponent!
|
||||||
);
|
);
|
||||||
return new VueHeaderActionsRenderer(
|
return new VueHeaderActionsRenderer(
|
||||||
component!,
|
component!,
|
||||||
getCurrentInstance()!,
|
inst,
|
||||||
group
|
group
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -126,12 +132,12 @@ onMounted(() => {
|
|||||||
createPrefixHeaderActionComponent: props.prefixHeaderActionsComponent
|
createPrefixHeaderActionComponent: props.prefixHeaderActionsComponent
|
||||||
? (group) => {
|
? (group) => {
|
||||||
const component = findComponent(
|
const component = findComponent(
|
||||||
getCurrentInstance()!,
|
inst,
|
||||||
props.prefixHeaderActionsComponent!
|
props.prefixHeaderActionsComponent!
|
||||||
);
|
);
|
||||||
return new VueHeaderActionsRenderer(
|
return new VueHeaderActionsRenderer(
|
||||||
component!,
|
component!,
|
||||||
getCurrentInstance()!,
|
inst,
|
||||||
group
|
group
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -139,12 +145,12 @@ onMounted(() => {
|
|||||||
createRightHeaderActionComponent: props.rightHeaderActionsComponent
|
createRightHeaderActionComponent: props.rightHeaderActionsComponent
|
||||||
? (group) => {
|
? (group) => {
|
||||||
const component = findComponent(
|
const component = findComponent(
|
||||||
getCurrentInstance()!,
|
inst,
|
||||||
props.rightHeaderActionsComponent!
|
props.rightHeaderActionsComponent!
|
||||||
);
|
);
|
||||||
return new VueHeaderActionsRenderer(
|
return new VueHeaderActionsRenderer(
|
||||||
component!,
|
component!,
|
||||||
getCurrentInstance()!,
|
inst,
|
||||||
group
|
group
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "dockview",
|
"name": "dockview",
|
||||||
"version": "1.14.0",
|
"version": "1.14.2",
|
||||||
"description": "Zero dependency layout manager supporting tabs, grids and splitviews",
|
"description": "Zero dependency layout manager supporting tabs, grids and splitviews",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"splitview",
|
"splitview",
|
||||||
@ -54,6 +54,6 @@
|
|||||||
"test:cov": "cross-env ../../node_modules/.bin/jest --selectProjects dockview --coverage"
|
"test:cov": "cross-env ../../node_modules/.bin/jest --selectProjects dockview --coverage"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"dockview-core": "^1.14.0"
|
"dockview-core": "^1.14.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,16 @@ import { fireEvent, render, screen } from '@testing-library/react';
|
|||||||
import { DockviewDefaultTab } from '../../dockview/defaultTab';
|
import { DockviewDefaultTab } from '../../dockview/defaultTab';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { fromPartial } from '@total-typescript/shoehorn';
|
import { fromPartial } from '@total-typescript/shoehorn';
|
||||||
import { DockviewApi, DockviewPanelApi } from 'dockview-core';
|
import { DockviewApi, DockviewPanelApi, TitleEvent } from 'dockview-core';
|
||||||
|
import { Emitter } from 'dockview-core/dist/cjs/events';
|
||||||
|
import { act } from 'react-dom/test-utils';
|
||||||
|
import { Disposable } from 'dockview-core/dist/cjs/lifecycle';
|
||||||
|
|
||||||
describe('defaultTab', () => {
|
describe('defaultTab', () => {
|
||||||
test('has close button by default', async () => {
|
test('has close button by default', async () => {
|
||||||
const api = fromPartial<DockviewPanelApi>({});
|
const api = fromPartial<DockviewPanelApi>({
|
||||||
|
onDidTitleChange: jest.fn().mockImplementation(() => Disposable.NONE),
|
||||||
|
});
|
||||||
const containerApi = fromPartial<DockviewApi>({});
|
const containerApi = fromPartial<DockviewApi>({});
|
||||||
const params = {};
|
const params = {};
|
||||||
|
|
||||||
@ -25,6 +30,7 @@ describe('defaultTab', () => {
|
|||||||
test('that title is displayed', async () => {
|
test('that title is displayed', async () => {
|
||||||
const api = fromPartial<DockviewPanelApi>({
|
const api = fromPartial<DockviewPanelApi>({
|
||||||
title: 'test_title',
|
title: 'test_title',
|
||||||
|
onDidTitleChange: jest.fn().mockImplementation(() => Disposable.NONE),
|
||||||
});
|
});
|
||||||
const containerApi = fromPartial<DockviewApi>({});
|
const containerApi = fromPartial<DockviewApi>({});
|
||||||
const params = {};
|
const params = {};
|
||||||
@ -43,8 +49,43 @@ describe('defaultTab', () => {
|
|||||||
).toBe('test_title');
|
).toBe('test_title');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('that title is updated', async () => {
|
||||||
|
const onDidTitleChange = new Emitter<TitleEvent>();
|
||||||
|
|
||||||
|
const api = fromPartial<DockviewPanelApi>({
|
||||||
|
title: 'test_title',
|
||||||
|
onDidTitleChange: onDidTitleChange.event,
|
||||||
|
});
|
||||||
|
const containerApi = fromPartial<DockviewApi>({});
|
||||||
|
const params = {};
|
||||||
|
|
||||||
|
render(
|
||||||
|
<DockviewDefaultTab
|
||||||
|
api={api}
|
||||||
|
containerApi={containerApi}
|
||||||
|
params={params}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
let element = await screen.getByTestId('dockview-dv-default-tab');
|
||||||
|
expect(
|
||||||
|
element.querySelector('.dv-default-tab-content')?.textContent
|
||||||
|
).toBe('test_title');
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
onDidTitleChange.fire({ title: 'test_title_2' });
|
||||||
|
});
|
||||||
|
|
||||||
|
element = await screen.getByTestId('dockview-dv-default-tab');
|
||||||
|
expect(
|
||||||
|
element.querySelector('.dv-default-tab-content')?.textContent
|
||||||
|
).toBe('test_title_2');
|
||||||
|
});
|
||||||
|
|
||||||
test('has no close button when hideClose=true', async () => {
|
test('has no close button when hideClose=true', async () => {
|
||||||
const api = fromPartial<DockviewPanelApi>({});
|
const api = fromPartial<DockviewPanelApi>({
|
||||||
|
onDidTitleChange: jest.fn().mockImplementation(() => Disposable.NONE),
|
||||||
|
});
|
||||||
const containerApi = fromPartial<DockviewApi>({});
|
const containerApi = fromPartial<DockviewApi>({});
|
||||||
const params = {};
|
const params = {};
|
||||||
|
|
||||||
@ -64,6 +105,7 @@ describe('defaultTab', () => {
|
|||||||
test('that settings closeActionOverride skips api.close()', async () => {
|
test('that settings closeActionOverride skips api.close()', async () => {
|
||||||
const api = fromPartial<DockviewPanelApi>({
|
const api = fromPartial<DockviewPanelApi>({
|
||||||
close: jest.fn(),
|
close: jest.fn(),
|
||||||
|
onDidTitleChange: jest.fn().mockImplementation(() => Disposable.NONE),
|
||||||
});
|
});
|
||||||
const containerApi = fromPartial<DockviewApi>({});
|
const containerApi = fromPartial<DockviewApi>({});
|
||||||
const params = {};
|
const params = {};
|
||||||
@ -85,13 +127,14 @@ describe('defaultTab', () => {
|
|||||||
) as HTMLElement;
|
) as HTMLElement;
|
||||||
fireEvent.click(btn);
|
fireEvent.click(btn);
|
||||||
|
|
||||||
expect(closeActionOverride).toBeCalledTimes(1);
|
expect(closeActionOverride).toHaveBeenCalledTimes(1);
|
||||||
expect(api.close).toBeCalledTimes(0);
|
expect(api.close).toHaveBeenCalledTimes(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('that clicking close calls api.close()', async () => {
|
test('that clicking close calls api.close()', async () => {
|
||||||
const api = fromPartial<DockviewPanelApi>({
|
const api = fromPartial<DockviewPanelApi>({
|
||||||
close: jest.fn(),
|
close: jest.fn(),
|
||||||
|
onDidTitleChange: jest.fn().mockImplementation(() => Disposable.NONE),
|
||||||
});
|
});
|
||||||
const containerApi = fromPartial<DockviewApi>({});
|
const containerApi = fromPartial<DockviewApi>({});
|
||||||
const params = {};
|
const params = {};
|
||||||
@ -110,11 +153,13 @@ describe('defaultTab', () => {
|
|||||||
) as HTMLElement;
|
) as HTMLElement;
|
||||||
fireEvent.click(btn);
|
fireEvent.click(btn);
|
||||||
|
|
||||||
expect(api.close).toBeCalledTimes(1);
|
expect(api.close).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('has close button when hideClose=false', async () => {
|
test('has close button when hideClose=false', async () => {
|
||||||
const api = fromPartial<DockviewPanelApi>({});
|
const api = fromPartial<DockviewPanelApi>({
|
||||||
|
onDidTitleChange: jest.fn().mockImplementation(() => Disposable.NONE),
|
||||||
|
});
|
||||||
const containerApi = fromPartial<DockviewApi>({});
|
const containerApi = fromPartial<DockviewApi>({});
|
||||||
const params = {};
|
const params = {};
|
||||||
|
|
||||||
@ -134,6 +179,7 @@ describe('defaultTab', () => {
|
|||||||
test('that mouseDown on close button prevents panel becoming active', async () => {
|
test('that mouseDown on close button prevents panel becoming active', async () => {
|
||||||
const api = fromPartial<DockviewPanelApi>({
|
const api = fromPartial<DockviewPanelApi>({
|
||||||
setActive: jest.fn(),
|
setActive: jest.fn(),
|
||||||
|
onDidTitleChange: jest.fn().mockImplementation(() => Disposable.NONE),
|
||||||
});
|
});
|
||||||
const containerApi = fromPartial<DockviewApi>({});
|
const containerApi = fromPartial<DockviewApi>({});
|
||||||
const params = {};
|
const params = {};
|
||||||
@ -152,9 +198,9 @@ describe('defaultTab', () => {
|
|||||||
) as HTMLElement;
|
) as HTMLElement;
|
||||||
|
|
||||||
fireEvent.mouseDown(btn);
|
fireEvent.mouseDown(btn);
|
||||||
expect(api.setActive).toBeCalledTimes(0);
|
expect(api.setActive).toHaveBeenCalledTimes(0);
|
||||||
|
|
||||||
fireEvent.click(element);
|
fireEvent.click(element);
|
||||||
expect(api.setActive).toBeCalledTimes(1);
|
expect(api.setActive).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,22 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { CloseButton } from '../svg';
|
import { CloseButton } from '../svg';
|
||||||
import { IDockviewPanelHeaderProps } from 'dockview-core';
|
import { DockviewPanelApi, IDockviewPanelHeaderProps } from 'dockview-core';
|
||||||
|
|
||||||
|
function useTitle(api: DockviewPanelApi): string | undefined {
|
||||||
|
const [title, setTitle] = React.useState<string | undefined>(api.title);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
const disposable = api.onDidTitleChange((event) => {
|
||||||
|
setTitle(event.title);
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
disposable.dispose();
|
||||||
|
};
|
||||||
|
}, [api]);
|
||||||
|
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
export type IDockviewDefaultTabProps = IDockviewPanelHeaderProps &
|
export type IDockviewDefaultTabProps = IDockviewPanelHeaderProps &
|
||||||
React.DOMAttributes<HTMLDivElement> & {
|
React.DOMAttributes<HTMLDivElement> & {
|
||||||
@ -18,6 +34,8 @@ export const DockviewDefaultTab: React.FunctionComponent<
|
|||||||
closeActionOverride,
|
closeActionOverride,
|
||||||
...rest
|
...rest
|
||||||
}) => {
|
}) => {
|
||||||
|
const title = useTitle(api);
|
||||||
|
|
||||||
const onClose = React.useCallback(
|
const onClose = React.useCallback(
|
||||||
(event: React.MouseEvent<HTMLSpanElement>) => {
|
(event: React.MouseEvent<HTMLSpanElement>) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@ -57,7 +75,7 @@ export const DockviewDefaultTab: React.FunctionComponent<
|
|||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
className="dv-default-tab"
|
className="dv-default-tab"
|
||||||
>
|
>
|
||||||
<span className="dv-default-tab-content">{api.title}</span>
|
<span className="dv-default-tab-content">{title}</span>
|
||||||
{!hideClose && (
|
{!hideClose && (
|
||||||
<div
|
<div
|
||||||
className="dv-default-tab-action"
|
className="dv-default-tab-action"
|
||||||
|
13
packages/docs/blog/2024-05-28-dockview-1.14.1.md
Normal file
13
packages/docs/blog/2024-05-28-dockview-1.14.1.md
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
---
|
||||||
|
slug: dockview-1.14.1-release
|
||||||
|
title: Dockview 1.14.1
|
||||||
|
tags: [release]
|
||||||
|
---
|
||||||
|
|
||||||
|
# Release Notes
|
||||||
|
|
||||||
|
Please reference docs @ [dockview.dev](https://dockview.dev).
|
||||||
|
|
||||||
|
## 🛠 Miscs
|
||||||
|
|
||||||
|
- Bug: fix CSS related to group gap sizing [#596](https://github.com/mathuo/dockview/issues/613)
|
15
packages/docs/blog/2024-06-08-dockview-1.14.2.md
Normal file
15
packages/docs/blog/2024-06-08-dockview-1.14.2.md
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
slug: dockview-1.14.2-release
|
||||||
|
title: Dockview 1.14.2
|
||||||
|
tags: [release]
|
||||||
|
---
|
||||||
|
|
||||||
|
# Release Notes
|
||||||
|
|
||||||
|
Please reference docs @ [dockview.dev](https://dockview.dev).
|
||||||
|
|
||||||
|
## 🛠 Miscs
|
||||||
|
|
||||||
|
- Bug: setTitle fixes [#623](https://github.com/mathuo/dockview/pull/623)
|
||||||
|
- Bug: Vue3 component rendering issues [#625](https://github.com/mathuo/dockview/pull/625)
|
||||||
|
- Improves docs [#617](https://github.com/mathuo/dockview/pull/617) [#620](https://github.com/mathuo/dockview/pull/620)
|
@ -165,6 +165,6 @@ api.addPanel({
|
|||||||
api.addPanel({
|
api.addPanel({
|
||||||
id: 'panel_2',
|
id: 'panel_2',
|
||||||
component: 'default',
|
component: 'default',
|
||||||
floating: { x: 10, y: 10, width: 300, height: 300 },
|
floating: { left: 10, top: 10, width: 300, height: 300 },
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "dockview-docs",
|
"name": "dockview-docs",
|
||||||
"version": "1.14.0",
|
"version": "1.14.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "npm run build-templates && docusaurus build",
|
"build": "npm run build-templates && docusaurus build",
|
||||||
@ -37,7 +37,7 @@
|
|||||||
"ag-grid-react": "^31.0.2",
|
"ag-grid-react": "^31.0.2",
|
||||||
"axios": "^1.6.3",
|
"axios": "^1.6.3",
|
||||||
"clsx": "^2.1.0",
|
"clsx": "^2.1.0",
|
||||||
"dockview": "^1.14.0",
|
"dockview": "^1.14.2",
|
||||||
"prism-react-renderer": "^2.3.1",
|
"prism-react-renderer": "^2.3.1",
|
||||||
"react-dnd": "^16.0.1",
|
"react-dnd": "^16.0.1",
|
||||||
"react-laag": "^2.0.5",
|
"react-laag": "^2.0.5",
|
||||||
|
@ -77,6 +77,11 @@
|
|||||||
border: none;
|
border: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
color: gray;
|
||||||
|
cursor: help;
|
||||||
|
}
|
||||||
|
|
||||||
span {
|
span {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
|
@ -185,6 +185,19 @@ const DockviewDemo = (props: { theme?: string }) => {
|
|||||||
|
|
||||||
const [watermark, setWatermark] = React.useState<boolean>(false);
|
const [watermark, setWatermark] = React.useState<boolean>(false);
|
||||||
|
|
||||||
|
const [gapCheck, setGapCheck] = React.useState<boolean>(false);
|
||||||
|
|
||||||
|
const css = React.useMemo(() => {
|
||||||
|
if (!gapCheck) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
'--dv-group-gap-size': '0.5rem',
|
||||||
|
'--demo-border': '5px dashed purple',
|
||||||
|
} as React.CSSProperties;
|
||||||
|
}, [gapCheck]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
@ -195,6 +208,7 @@ const DockviewDemo = (props: { theme?: string }) => {
|
|||||||
padding: '8px',
|
padding: '8px',
|
||||||
backgroundColor: 'rgba(0,0,50,0.25)',
|
backgroundColor: 'rgba(0,0,50,0.25)',
|
||||||
borderRadius: '8px',
|
borderRadius: '8px',
|
||||||
|
...css,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
@ -217,6 +231,15 @@ const DockviewDemo = (props: { theme?: string }) => {
|
|||||||
activeGroup={activeGroup}
|
activeGroup={activeGroup}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{/* <div>
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
setGapCheck(!gapCheck);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{gapCheck ? 'Disable Gap Check' : 'Enable Gap Check'}
|
||||||
|
</button>
|
||||||
|
</div> */}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
@ -24,6 +24,7 @@ export const GridActions = (props: {
|
|||||||
|
|
||||||
const onSave = () => {
|
const onSave = () => {
|
||||||
if (props.api) {
|
if (props.api) {
|
||||||
|
console.log(props.api.toJSON());
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
'dv-demo-state',
|
'dv-demo-state',
|
||||||
JSON.stringify(props.api.toJSON())
|
JSON.stringify(props.api.toJSON())
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
import { DockviewApi, DockviewGroupLocation } from 'dockview';
|
import {
|
||||||
|
DockviewApi,
|
||||||
|
DockviewGroupLocation,
|
||||||
|
DockviewGroupPanel,
|
||||||
|
} from 'dockview';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
const GroupAction = (props: {
|
const GroupAction = (props: {
|
||||||
@ -12,14 +16,27 @@ const GroupAction = (props: {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const isActive = props.activeGroup === props.groupId;
|
const isActive = props.activeGroup === props.groupId;
|
||||||
const group = React.useMemo(
|
|
||||||
() => props.api.getGroup(props.groupId),
|
const [group, setGroup] = React.useState<DockviewGroupPanel | undefined>(
|
||||||
[props.api, props.groupId]
|
undefined
|
||||||
);
|
);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
const disposable = props.api.onDidLayoutFromJSON(() => {
|
||||||
|
setGroup(props.api.getGroup(props.groupId));
|
||||||
|
});
|
||||||
|
|
||||||
|
setGroup(props.api.getGroup(props.groupId));
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
disposable.dispose();
|
||||||
|
};
|
||||||
|
}, [props.api, props.groupId]);
|
||||||
|
|
||||||
const [location, setLocation] =
|
const [location, setLocation] =
|
||||||
React.useState<DockviewGroupLocation | null>(null);
|
React.useState<DockviewGroupLocation | null>(null);
|
||||||
const [isMaximized, setIsMaximized] = React.useState<boolean>(false);
|
const [isMaximized, setIsMaximized] = React.useState<boolean>(false);
|
||||||
|
const [isVisible, setIsVisible] = React.useState<boolean>(true);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (!group) {
|
if (!group) {
|
||||||
@ -35,12 +52,18 @@ const GroupAction = (props: {
|
|||||||
setIsMaximized(group.api.isMaximized());
|
setIsMaximized(group.api.isMaximized());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const disposable3 = group.api.onDidVisibilityChange(() => {
|
||||||
|
setIsVisible(group.api.isVisible);
|
||||||
|
});
|
||||||
|
|
||||||
setLocation(group.api.location);
|
setLocation(group.api.location);
|
||||||
setIsMaximized(group.api.isMaximized());
|
setIsMaximized(group.api.isMaximized());
|
||||||
|
setIsVisible(group.api.isVisible);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
disposable.dispose();
|
disposable.dispose();
|
||||||
disposable2.dispose();
|
disposable2.dispose();
|
||||||
|
disposable3.dispose();
|
||||||
};
|
};
|
||||||
}, [group]);
|
}, [group]);
|
||||||
|
|
||||||
@ -65,7 +88,14 @@ const GroupAction = (props: {
|
|||||||
}
|
}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (group) {
|
if (group) {
|
||||||
props.api.addFloatingGroup(group);
|
props.api.addFloatingGroup(group, {
|
||||||
|
position: {
|
||||||
|
width: 400,
|
||||||
|
height: 300,
|
||||||
|
top: 50,
|
||||||
|
right: 50,
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@ -107,6 +137,23 @@ const GroupAction = (props: {
|
|||||||
fullscreen
|
fullscreen
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
className="demo-icon-button"
|
||||||
|
onClick={() => {
|
||||||
|
console.log(group);
|
||||||
|
if (group) {
|
||||||
|
if (group.api.isVisible) {
|
||||||
|
group.api.setVisible(false);
|
||||||
|
} else {
|
||||||
|
group.api.setVisible(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span className="material-symbols-outlined">
|
||||||
|
{isVisible ? 'visibility' : 'visibility_off'}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
className="demo-icon-button"
|
className="demo-icon-button"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { DockviewApi } from 'dockview';
|
import { DockviewApi, IDockviewPanel } from 'dockview';
|
||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
const PanelAction = (props: {
|
const PanelAction = (props: {
|
||||||
panels: string[];
|
panels: string[];
|
||||||
@ -9,6 +10,50 @@ const PanelAction = (props: {
|
|||||||
const onClick = () => {
|
const onClick = () => {
|
||||||
props.api.getPanel(props.panelId)?.focus();
|
props.api.getPanel(props.panelId)?.focus();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
const panel = props.api.getPanel(props.panelId);
|
||||||
|
if (panel) {
|
||||||
|
const disposable = panel.api.onDidVisibilityChange((event) => {
|
||||||
|
setVisible(event.isVisible);
|
||||||
|
});
|
||||||
|
setVisible(panel.api.isVisible);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
disposable.dispose();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}, [props.api, props.panelId]);
|
||||||
|
|
||||||
|
const [panel, setPanel] = React.useState<IDockviewPanel | undefined>(
|
||||||
|
undefined
|
||||||
|
);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
const list = [
|
||||||
|
props.api.onDidLayoutFromJSON(() => {
|
||||||
|
setPanel(props.api.getPanel(props.panelId));
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
|
if (panel) {
|
||||||
|
const disposable = panel.api.onDidVisibilityChange((event) => {
|
||||||
|
setVisible(event.isVisible);
|
||||||
|
});
|
||||||
|
setVisible(panel.api.isVisible);
|
||||||
|
|
||||||
|
list.push(disposable);
|
||||||
|
}
|
||||||
|
|
||||||
|
setPanel(props.api.getPanel(props.panelId));
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
list.forEach((l) => l.dispose());
|
||||||
|
};
|
||||||
|
}, [props.api, props.panelId]);
|
||||||
|
|
||||||
|
const [visible, setVisible] = React.useState<boolean>(true);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="button-action">
|
<div className="button-action">
|
||||||
<div style={{ display: 'flex' }}>
|
<div style={{ display: 'flex' }}>
|
||||||
@ -29,7 +74,14 @@ const PanelAction = (props: {
|
|||||||
onClick={() => {
|
onClick={() => {
|
||||||
const panel = props.api.getPanel(props.panelId);
|
const panel = props.api.getPanel(props.panelId);
|
||||||
if (panel) {
|
if (panel) {
|
||||||
props.api.addFloatingGroup(panel);
|
props.api.addFloatingGroup(panel, {
|
||||||
|
position: {
|
||||||
|
width: 400,
|
||||||
|
height: 300,
|
||||||
|
bottom: 50,
|
||||||
|
right: 50,
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@ -57,6 +109,15 @@ const PanelAction = (props: {
|
|||||||
>
|
>
|
||||||
<span className="material-symbols-outlined">close</span>
|
<span className="material-symbols-outlined">close</span>
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
title="Panel visiblity cannot be edited manually."
|
||||||
|
disabled={true}
|
||||||
|
className="demo-icon-button"
|
||||||
|
>
|
||||||
|
<span className="material-symbols-outlined">
|
||||||
|
{visible ? 'visibility' : 'visibility_off'}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -84,7 +84,7 @@ function addFloatingPanel2(api: DockviewApi) {
|
|||||||
id: (++panelCount).toString(),
|
id: (++panelCount).toString(),
|
||||||
title: `Tab ${panelCount}`,
|
title: `Tab ${panelCount}`,
|
||||||
component: 'default',
|
component: 'default',
|
||||||
floating: { width: 250, height: 150, x: 50, y: 50 },
|
floating: { width: 250, height: 150, left: 50, top: 50 },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -259,11 +259,9 @@ const RightComponent = (props: IDockviewHeaderActionsProps) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
const disposable = props.group.api.onDidLocationChange(
|
const disposable = props.group.api.onDidLocationChange((event) => {
|
||||||
(event) => {
|
setFloating(event.location.type === 'floating');
|
||||||
setFloating(event.location.type === 'floating');
|
});
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
disposable.dispose();
|
disposable.dispose();
|
||||||
@ -275,7 +273,14 @@ const RightComponent = (props: IDockviewHeaderActionsProps) => {
|
|||||||
const group = props.containerApi.addGroup();
|
const group = props.containerApi.addGroup();
|
||||||
props.group.api.moveTo({ group });
|
props.group.api.moveTo({ group });
|
||||||
} else {
|
} else {
|
||||||
props.containerApi.addFloatingGroup(props.group);
|
props.containerApi.addFloatingGroup(props.group, {
|
||||||
|
position: {
|
||||||
|
width: 400,
|
||||||
|
height: 300,
|
||||||
|
bottom: 50,
|
||||||
|
right: 50,
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import { argv } from 'process';
|
import { argv } from 'process';
|
||||||
|
import { execSync } from 'child_process';
|
||||||
|
|
||||||
import { fileURLToPath } from 'url';
|
import { fileURLToPath } from 'url';
|
||||||
|
|
||||||
@ -14,7 +15,7 @@ const { version } = JSON.parse(
|
|||||||
|
|
||||||
const REACT_VERSION = '18.2.0';
|
const REACT_VERSION = '18.2.0';
|
||||||
const VUE_VERSION = '3.4.21';
|
const VUE_VERSION = '3.4.21';
|
||||||
const DOCKVIEW_VERSION = 'latest'; // version;
|
const DOCKVIEW_VERSION = version; //'latest';;
|
||||||
const USE_LOCAL_CDN = argv.slice(2).includes('--local');
|
const USE_LOCAL_CDN = argv.slice(2).includes('--local');
|
||||||
|
|
||||||
const local = 'http://localhost:1111';
|
const local = 'http://localhost:1111';
|
||||||
@ -35,11 +36,13 @@ const DOCKVIEW_CDN = {
|
|||||||
'dockview-core': `https://cdn.jsdelivr.net/npm/dockview-core@${DOCKVIEW_VERSION}/dist/dockview-core.esm.js`,
|
'dockview-core': `https://cdn.jsdelivr.net/npm/dockview-core@${DOCKVIEW_VERSION}/dist/dockview-core.esm.js`,
|
||||||
'dockview-core/': `https://cdn.jsdelivr.net/npm/dockview-core@${DOCKVIEW_VERSION}/`,
|
'dockview-core/': `https://cdn.jsdelivr.net/npm/dockview-core@${DOCKVIEW_VERSION}/`,
|
||||||
'dockview-vue': `https://cdn.jsdelivr.net/npm/dockview-vue@${DOCKVIEW_VERSION}/dist/dockview-vue.es.js`,
|
'dockview-vue': `https://cdn.jsdelivr.net/npm/dockview-vue@${DOCKVIEW_VERSION}/dist/dockview-vue.es.js`,
|
||||||
|
'dockview-vue/': `https://cdn.jsdelivr.net/npm/dockview-vue@${DOCKVIEW_VERSION}/`,
|
||||||
},
|
},
|
||||||
local: {
|
local: {
|
||||||
'dockview-core': `${local}/dockview-core/dist/dockview-core.esm.js`,
|
'dockview-core': `${local}/dockview-core/dist/dockview-core.esm.js`,
|
||||||
'dockview-core/': `${local}/dockview-core/`,
|
'dockview-core/': `${local}/dockview-core/`,
|
||||||
'dockview-vue': `${local}/dockview-vue/dist/dockview-vue.es.js`,
|
'dockview-vue': `${local}/dockview-vue/dist/dockview-vue.es.js`,
|
||||||
|
'dockview-vue/': `${local}/dockview-vue/`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
typescript: {
|
typescript: {
|
||||||
|
@ -3,7 +3,7 @@ import { useActiveFramework } from '../frameworkSpecific';
|
|||||||
import BrowserOnly from '@docusaurus/BrowserOnly';
|
import BrowserOnly from '@docusaurus/BrowserOnly';
|
||||||
|
|
||||||
const BASE_SANDBOX_URL =
|
const BASE_SANDBOX_URL =
|
||||||
'https://codesandbox.io/s/github/mathuo/dockview/tree/master/packages/docs';
|
'https://codesandbox.io/s/github/mathuo/dockview/tree/gh-pages';
|
||||||
|
|
||||||
export const _CodeRunner = (props: { id: string; height: number }) => {
|
export const _CodeRunner = (props: { id: string; height: number }) => {
|
||||||
const [framework] = useActiveFramework();
|
const [framework] = useActiveFramework();
|
||||||
|
File diff suppressed because it is too large
Load Diff
1
packages/docs/static/img/vue-icon.svg
vendored
Normal file
1
packages/docs/static/img/vue-icon.svg
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 261.76 226.69"><path d="M161.096.001l-30.225 52.351L100.647.001H-.005l130.877 226.688L261.749.001z" fill="#41b883"/><path d="M161.096.001l-30.225 52.351L100.647.001H52.346l78.526 136.01L209.398.001z" fill="#34495e"/></svg>
|
After Width: | Height: | Size: 276 B |
@ -1,32 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "dockview.resize",
|
|
||||||
"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,10 @@
|
|||||||
import 'dockview-core/dist/styles/dockview.css';
|
import 'dockview-vue/dist/styles/dockview.css';
|
||||||
import { PropType, createApp, defineComponent } from 'vue';
|
import { PropType, createApp, defineComponent } from 'vue';
|
||||||
import { DockviewVue } from 'dockview-vue';
|
import {
|
||||||
import { DockviewReadyEvent, IDockviewPanelProps } from 'dockview-core';
|
DockviewVue,
|
||||||
|
DockviewReadyEvent,
|
||||||
|
IDockviewPanelProps,
|
||||||
|
} from 'dockview-vue';
|
||||||
|
|
||||||
const Panel = defineComponent({
|
const Panel = defineComponent({
|
||||||
name: 'Panel',
|
name: 'Panel',
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
{
|
|
||||||
"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
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +1,11 @@
|
|||||||
import 'dockview-core/dist/styles/dockview.css';
|
import 'dockview-vue/dist/styles/dockview.css';
|
||||||
import { PropType, createApp, defineComponent } from 'vue';
|
import { PropType, createApp, defineComponent } from 'vue';
|
||||||
import { DockviewVue } from 'dockview-vue';
|
|
||||||
import {
|
import {
|
||||||
|
DockviewVue,
|
||||||
DockviewReadyEvent,
|
DockviewReadyEvent,
|
||||||
IDockviewPanelHeaderProps,
|
IDockviewPanelHeaderProps,
|
||||||
IDockviewPanelProps,
|
IDockviewPanelProps,
|
||||||
} from 'dockview-core';
|
} from 'dockview-vue';
|
||||||
|
|
||||||
const Panel = defineComponent({
|
const Panel = defineComponent({
|
||||||
name: 'Panel',
|
name: 'Panel',
|
||||||
|
@ -14,7 +14,7 @@ export function defaultConfig(api: DockviewApi) {
|
|||||||
id: 'panel_1',
|
id: 'panel_1',
|
||||||
component: 'default',
|
component: 'default',
|
||||||
renderer: 'always',
|
renderer: 'always',
|
||||||
title: 'Panel 1',
|
title: 'Panel 1'
|
||||||
});
|
});
|
||||||
|
|
||||||
api.addPanel({
|
api.addPanel({
|
||||||
|
@ -32,7 +32,14 @@ export const GroupActions = (props: {
|
|||||||
onClick={() => {
|
onClick={() => {
|
||||||
const panel = props.api?.getGroup(x);
|
const panel = props.api?.getGroup(x);
|
||||||
if (panel) {
|
if (panel) {
|
||||||
props.api?.addFloatingGroup(panel);
|
props.api?.addFloatingGroup(panel, {
|
||||||
|
position: {
|
||||||
|
width: 400,
|
||||||
|
height: 300,
|
||||||
|
bottom: 50,
|
||||||
|
right: 50,
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -32,7 +32,14 @@ export const PanelActions = (props: {
|
|||||||
onClick={() => {
|
onClick={() => {
|
||||||
const panel = props.api?.getPanel(x);
|
const panel = props.api?.getPanel(x);
|
||||||
if (panel) {
|
if (panel) {
|
||||||
props.api?.addFloatingGroup(panel);
|
props.api?.addFloatingGroup(panel, {
|
||||||
|
position: {
|
||||||
|
width: 400,
|
||||||
|
height: 300,
|
||||||
|
bottom: 50,
|
||||||
|
right: 50,
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -209,9 +209,8 @@ export const DockviewPersistence = (props: { theme?: string }) => {
|
|||||||
setDisableFloatingGroups((x) => !x);
|
setDisableFloatingGroups((x) => !x);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{`${
|
{`${disableFloatingGroups ? 'Enable' : 'Disable'
|
||||||
disableFloatingGroups ? 'Enable' : 'Disable'
|
} floating groups`}
|
||||||
} floating groups`}
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@ -265,7 +264,14 @@ const RightComponent = (props: IDockviewHeaderActionsProps) => {
|
|||||||
const group = props.containerApi.addGroup();
|
const group = props.containerApi.addGroup();
|
||||||
props.group.api.moveTo({ group });
|
props.group.api.moveTo({ group });
|
||||||
} else {
|
} else {
|
||||||
props.containerApi.addFloatingGroup(props.group);
|
props.containerApi.addFloatingGroup(props.group, {
|
||||||
|
position: {
|
||||||
|
width: 400,
|
||||||
|
height: 300,
|
||||||
|
bottom: 50,
|
||||||
|
right: 50,
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import 'dockview-core/dist/styles/dockview.css';
|
import 'dockview-vue/dist/styles/dockview.css';
|
||||||
import { PropType, createApp, defineComponent } from 'vue';
|
import { PropType, createApp, defineComponent } from 'vue';
|
||||||
import { DockviewVue } from 'dockview-vue';
|
|
||||||
import {
|
import {
|
||||||
|
DockviewVue,
|
||||||
DockviewApi,
|
DockviewApi,
|
||||||
DockviewReadyEvent,
|
DockviewReadyEvent,
|
||||||
IDockviewHeaderActionsProps,
|
IDockviewHeaderActionsProps,
|
||||||
IDockviewPanelProps,
|
IDockviewPanelProps,
|
||||||
} from 'dockview-core';
|
} from 'dockview-vue';
|
||||||
|
|
||||||
let panelCount = 0;
|
let panelCount = 0;
|
||||||
|
|
||||||
@ -93,7 +93,14 @@ const RightAction = defineComponent({
|
|||||||
const group = this.params.containerApi.addGroup();
|
const group = this.params.containerApi.addGroup();
|
||||||
this.group.api.moveTo({ group });
|
this.group.api.moveTo({ group });
|
||||||
} else {
|
} else {
|
||||||
this.containerApi.addFloatingGroup(this.params.group);
|
this.containerApi.addFloatingGroup(this.params.group, {
|
||||||
|
position: {
|
||||||
|
width: 400,
|
||||||
|
height: 300,
|
||||||
|
bottom: 50,
|
||||||
|
right: 50,
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import 'dockview-core/dist/styles/dockview.css';
|
import 'dockview-vue/dist/styles/dockview.css';
|
||||||
import { PropType, createApp, defineComponent } from 'vue';
|
import { PropType, createApp, defineComponent } from 'vue';
|
||||||
import { DockviewVue } from 'dockview-vue';
|
|
||||||
import {
|
import {
|
||||||
|
DockviewVue,
|
||||||
DockviewReadyEvent,
|
DockviewReadyEvent,
|
||||||
IDockviewHeaderActionsProps,
|
IDockviewHeaderActionsProps,
|
||||||
IDockviewPanelProps,
|
IDockviewPanelProps,
|
||||||
} from 'dockview-core';
|
} from 'dockview-vue';
|
||||||
import './app.css';
|
import './app.css';
|
||||||
|
|
||||||
const LeftAction = defineComponent({
|
const LeftAction = defineComponent({
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import 'dockview-core/dist/styles/dockview.css';
|
import 'dockview-vue/dist/styles/dockview.css';
|
||||||
import { PropType, createApp, defineComponent } from 'vue';
|
import { PropType, createApp, defineComponent } from 'vue';
|
||||||
import { DockviewVue } from 'dockview-vue';
|
|
||||||
import {
|
import {
|
||||||
|
DockviewVue,
|
||||||
DockviewApi,
|
DockviewApi,
|
||||||
DockviewReadyEvent,
|
DockviewReadyEvent,
|
||||||
IDockviewHeaderActionsProps,
|
IDockviewHeaderActionsProps,
|
||||||
IDockviewPanelProps,
|
IDockviewPanelProps,
|
||||||
} from 'dockview-core';
|
} from 'dockview-vue';
|
||||||
|
|
||||||
let panelCount = 0;
|
let panelCount = 0;
|
||||||
|
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
import 'dockview-core/dist/styles/dockview.css';
|
import 'dockview-vue/dist/styles/dockview.css';
|
||||||
import { PropType, createApp, defineComponent } from 'vue';
|
import { PropType, createApp, defineComponent } from 'vue';
|
||||||
import { DockviewVue } from 'dockview-vue';
|
import {
|
||||||
import { DockviewReadyEvent, IDockviewPanelProps } from 'dockview-core';
|
DockviewVue,
|
||||||
|
DockviewReadyEvent,
|
||||||
|
IDockviewPanelProps,
|
||||||
|
} from 'dockview-vue';
|
||||||
|
|
||||||
const Panel = defineComponent({
|
const Panel = defineComponent({
|
||||||
name: 'Panel',
|
name: 'Panel',
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
import 'dockview-core/dist/styles/dockview.css';
|
import 'dockview-vue/dist/styles/dockview.css';
|
||||||
import { Prop, PropType, createApp, defineComponent } from 'vue';
|
import { PropType, createApp, defineComponent } from 'vue';
|
||||||
import { DockviewVue } from 'dockview-vue';
|
|
||||||
import {
|
import {
|
||||||
|
DockviewVue,
|
||||||
DockviewReadyEvent,
|
DockviewReadyEvent,
|
||||||
IDockviewHeaderActionsProps,
|
IDockviewHeaderActionsProps,
|
||||||
IDockviewPanelProps,
|
IDockviewPanelProps,
|
||||||
} from 'dockview-core';
|
} from 'dockview-vue';
|
||||||
|
|
||||||
let panelCount = 0;
|
let panelCount = 0;
|
||||||
|
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
import 'dockview-core/dist/styles/dockview.css';
|
import 'dockview-vue/dist/styles/dockview.css';
|
||||||
import { PropType, createApp, defineComponent } from 'vue';
|
import { PropType, createApp, defineComponent } from 'vue';
|
||||||
import { DockviewVue } from 'dockview-vue';
|
import {
|
||||||
import { DockviewReadyEvent, IDockviewPanelProps } from 'dockview-core';
|
DockviewVue,
|
||||||
|
DockviewReadyEvent,
|
||||||
|
IDockviewPanelProps,
|
||||||
|
} from 'dockview-vue';
|
||||||
|
|
||||||
const Panel = defineComponent({
|
const Panel = defineComponent({
|
||||||
name: 'Panel',
|
name: 'Panel',
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import 'dockview-core/dist/styles/dockview.css';
|
import 'dockview-vue/dist/styles/dockview.css';
|
||||||
import { PropType, createApp, defineComponent } from 'vue';
|
import { PropType, createApp, defineComponent } from 'vue';
|
||||||
import { DockviewVue } from 'dockview-vue';
|
|
||||||
import {
|
import {
|
||||||
|
DockviewVue,
|
||||||
DockviewApi,
|
DockviewApi,
|
||||||
DockviewReadyEvent,
|
DockviewReadyEvent,
|
||||||
IDockviewHeaderActionsProps,
|
IDockviewHeaderActionsProps,
|
||||||
IDockviewPanelProps,
|
IDockviewPanelProps,
|
||||||
} from 'dockview-core';
|
} from 'dockview-vue';
|
||||||
|
|
||||||
let panelCount = 0;
|
let panelCount = 0;
|
||||||
|
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
import 'dockview-core/dist/styles/dockview.css';
|
import 'dockview-vue/dist/styles/dockview.css';
|
||||||
import { PropType, createApp, defineComponent } from 'vue';
|
import { PropType, createApp, defineComponent } from 'vue';
|
||||||
import { DockviewVue } from 'dockview-vue';
|
import {
|
||||||
import { DockviewReadyEvent, IDockviewPanelProps } from 'dockview-core';
|
DockviewVue,
|
||||||
|
DockviewReadyEvent,
|
||||||
|
IDockviewPanelProps,
|
||||||
|
} from 'dockview-vue';
|
||||||
|
|
||||||
const Panel = defineComponent({
|
const Panel = defineComponent({
|
||||||
name: 'Panel',
|
name: 'Panel',
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
import 'dockview-core/dist/styles/dockview.css';
|
import 'dockview-vue/dist/styles/dockview.css';
|
||||||
import { PropType, createApp, defineComponent } from 'vue';
|
import { PropType, createApp, defineComponent } from 'vue';
|
||||||
import { DockviewVue } from 'dockview-vue';
|
import {
|
||||||
import { DockviewReadyEvent, IDockviewPanelProps } from 'dockview-core';
|
DockviewVue,
|
||||||
|
DockviewReadyEvent,
|
||||||
|
IDockviewPanelProps,
|
||||||
|
} from 'dockview-vue';
|
||||||
|
|
||||||
const Panel = defineComponent({
|
const Panel = defineComponent({
|
||||||
name: 'Panel',
|
name: 'Panel',
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
import 'dockview-core/dist/styles/dockview.css';
|
import 'dockview-vue/dist/styles/dockview.css';
|
||||||
import { PropType, createApp, defineComponent } from 'vue';
|
import { PropType, createApp, defineComponent } from 'vue';
|
||||||
import { DockviewVue } from 'dockview-vue';
|
import {
|
||||||
import { DockviewReadyEvent, IDockviewPanelProps } from 'dockview-core';
|
DockviewVue,
|
||||||
|
DockviewReadyEvent,
|
||||||
|
IDockviewPanelProps,
|
||||||
|
} from 'dockview-vue';
|
||||||
import './resize.css';
|
import './resize.css';
|
||||||
|
|
||||||
const Panel = defineComponent({
|
const Panel = defineComponent({
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import 'dockview-core/dist/styles/dockview.css';
|
import 'dockview-vue/dist/styles/dockview.css';
|
||||||
import { createApp, defineComponent } from 'vue';
|
import { createApp, defineComponent } from 'vue';
|
||||||
import { DockviewVue } from 'dockview-vue';
|
import { DockviewVue, DockviewReadyEvent } from 'dockview-vue';
|
||||||
import { DockviewReadyEvent } from 'dockview-core';
|
|
||||||
|
|
||||||
const TEXT =
|
const TEXT =
|
||||||
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.';
|
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.';
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import 'dockview-core/dist/styles/dockview.css';
|
import 'dockview-vue/dist/styles/dockview.css';
|
||||||
import { PropType, createApp, defineComponent } from 'vue';
|
import { PropType, createApp, defineComponent } from 'vue';
|
||||||
import { DockviewVue } from 'dockview-vue';
|
|
||||||
import {
|
import {
|
||||||
|
DockviewVue,
|
||||||
DockviewApi,
|
DockviewApi,
|
||||||
DockviewReadyEvent,
|
DockviewReadyEvent,
|
||||||
IDockviewPanelProps,
|
IDockviewPanelProps,
|
||||||
} from 'dockview-core';
|
} from 'dockview-vue';
|
||||||
|
|
||||||
const Panel = defineComponent({
|
const Panel = defineComponent({
|
||||||
name: 'Panel',
|
name: 'Panel',
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import 'dockview-core/dist/styles/dockview.css';
|
import 'dockview-vue/dist/styles/dockview.css';
|
||||||
import { PropType, createApp, defineComponent } from 'vue';
|
import { PropType, createApp, defineComponent } from 'vue';
|
||||||
import { DockviewVue } from 'dockview-vue';
|
|
||||||
import {
|
import {
|
||||||
|
DockviewVue,
|
||||||
DockviewReadyEvent,
|
DockviewReadyEvent,
|
||||||
IDockviewPanelHeaderProps,
|
IDockviewPanelHeaderProps,
|
||||||
IDockviewPanelProps,
|
IDockviewPanelProps,
|
||||||
} from 'dockview-core';
|
} from 'dockview-vue';
|
||||||
|
|
||||||
const Panel = defineComponent({
|
const Panel = defineComponent({
|
||||||
name: 'Panel',
|
name: 'Panel',
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
import 'dockview-core/dist/styles/dockview.css';
|
import 'dockview-vue/dist/styles/dockview.css';
|
||||||
import { PropType, createApp, defineComponent } from 'vue';
|
import { PropType, createApp, defineComponent } from 'vue';
|
||||||
import { DockviewVue } from 'dockview-vue';
|
import {
|
||||||
import { DockviewReadyEvent, IDockviewPanelProps } from 'dockview-core';
|
DockviewVue,
|
||||||
|
DockviewReadyEvent,
|
||||||
|
IDockviewPanelProps,
|
||||||
|
} from 'dockview-vue';
|
||||||
|
|
||||||
const Panel = defineComponent({
|
const Panel = defineComponent({
|
||||||
name: 'Panel',
|
name: 'Panel',
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import 'dockview-core/dist/styles/dockview.css';
|
import 'dockview-vue/dist/styles/dockview.css';
|
||||||
import { PropType, createApp, defineComponent } from 'vue';
|
import { PropType, createApp, defineComponent } from 'vue';
|
||||||
import { DockviewVue } from 'dockview-vue';
|
|
||||||
import {
|
import {
|
||||||
|
DockviewVue,
|
||||||
DockviewApi,
|
DockviewApi,
|
||||||
DockviewReadyEvent,
|
DockviewReadyEvent,
|
||||||
IDockviewPanelProps,
|
IDockviewPanelProps,
|
||||||
IWatermarkPanelProps,
|
IWatermarkPanelProps,
|
||||||
Orientation,
|
Orientation,
|
||||||
} from 'dockview-core';
|
} from 'dockview-vue';
|
||||||
|
|
||||||
const Panel = defineComponent({
|
const Panel = defineComponent({
|
||||||
name: 'Panel',
|
name: 'Panel',
|
||||||
|
Loading…
Reference in New Issue
Block a user