mirror of
https://github.com/mathuo/dockview
synced 2025-02-02 14:35:46 +00:00
Merge pull request #541 from mathuo/538-interested-in-porting-dockview-to-vuejs
feat: Vue 3 Support
This commit is contained in:
commit
6ca39ba58b
3
.vscode/extensions.json
vendored
3
.vscode/extensions.json
vendored
@ -7,7 +7,8 @@
|
||||
"esbenp.prettier-vscode",
|
||||
"redhat.vscode-yaml",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"editorconfig.editorconfig"
|
||||
"editorconfig.editorconfig",
|
||||
"vue.volar"
|
||||
],
|
||||
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
|
||||
"unwantedRecommendations": []
|
||||
|
12
package.json
12
package.json
@ -45,6 +45,9 @@
|
||||
"@types/react-dom": "^18.2.18",
|
||||
"@typescript-eslint/eslint-plugin": "^6.17.0",
|
||||
"@typescript-eslint/parser": "^6.17.0",
|
||||
"@vitejs/plugin-vue": "^5.0.4",
|
||||
"@vue/tsconfig": "^0.5.1",
|
||||
"concurrently": "^8.2.2",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^8.56.0",
|
||||
"fs-extra": "^11.2.0",
|
||||
@ -66,9 +69,16 @@
|
||||
"ts-node": "^10.9.2",
|
||||
"tslib": "^2.6.2",
|
||||
"typedoc": "^0.25.6",
|
||||
"typescript": "^5.3.3"
|
||||
"typescript": "^5.3.3",
|
||||
"vite": "^5.1.5",
|
||||
"vue": "^3.4.21",
|
||||
"vue-sfc-loader": "^0.1.0",
|
||||
"vue-tsc": "^2.0.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ag-grid-vue3": "^31.1.1"
|
||||
}
|
||||
}
|
||||
|
56
packages/dockview-angular/README.md
Normal file
56
packages/dockview-angular/README.md
Normal file
@ -0,0 +1,56 @@
|
||||
<div align="center">
|
||||
<h1>dockview</h1>
|
||||
|
||||
<p>Zero dependency layout manager supporting tabs, groups, grids and splitviews with ReactJS support written in TypeScript</p>
|
||||
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
[![npm version](https://badge.fury.io/js/dockview.svg)](https://www.npmjs.com/package/dockview)
|
||||
[![npm](https://img.shields.io/npm/dm/dockview)](https://www.npmjs.com/package/dockview)
|
||||
[![CI Build](https://github.com/mathuo/dockview/workflows/CI/badge.svg)](https://github.com/mathuo/dockview/actions?query=workflow%3ACI)
|
||||
[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=mathuo_dockview&metric=coverage)](https://sonarcloud.io/summary/overall?id=mathuo_dockview)
|
||||
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=mathuo_dockview&metric=alert_status)](https://sonarcloud.io/summary/overall?id=mathuo_dockview)
|
||||
[![Bundle Phobia](https://badgen.net/bundlephobia/minzip/dockview)](https://bundlephobia.com/result?p=dockview)
|
||||
|
||||
##
|
||||
|
||||
Please see the website: https://dockview.dev
|
||||
|
||||
## Features
|
||||
|
||||
- Serialization / deserialization with full layout management
|
||||
- Support for split-views, grid-views and 'dockable' views
|
||||
- Themeable and customizable
|
||||
- Tab and Group docking / Drag n' Drop
|
||||
- Popout Windows
|
||||
- Floating Groups
|
||||
- Extensive API
|
||||
- Supports Shadow DOMs
|
||||
- High test coverage
|
||||
- Documentation website with live examples
|
||||
- Transparent builds and Code Analysis
|
||||
- Security at mind - verifed publishing and builds through GitHub Actions
|
||||
|
||||
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>
|
||||
```
|
6
packages/dockview-angular/gulpfile.js
Normal file
6
packages/dockview-angular/gulpfile.js
Normal file
@ -0,0 +1,6 @@
|
||||
const gulp = require('gulp');
|
||||
const buildfile = require('../../scripts/build');
|
||||
|
||||
buildfile.init();
|
||||
|
||||
gulp.task('run', gulp.series(['sass']));
|
34
packages/dockview-angular/jest.config.ts
Normal file
34
packages/dockview-angular/jest.config.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import { JestConfigWithTsJest } from 'ts-jest';
|
||||
|
||||
const config: JestConfigWithTsJest = {
|
||||
preset: 'ts-jest',
|
||||
roots: ['<rootDir>/packages/dockview-angular'],
|
||||
modulePaths: ['<rootDir>/packages/dockview-angular/src'],
|
||||
displayName: { name: 'dockview-angular', color: 'blue' },
|
||||
rootDir: '../../',
|
||||
collectCoverageFrom: [
|
||||
'<rootDir>/packages/dockview-angular/src/**/*.{js,jsx,ts,tsx}',
|
||||
],
|
||||
setupFiles: [
|
||||
// '<rootDir>/packages/dockview-angular/src/__tests__/__mocks__/resizeObserver.js',
|
||||
],
|
||||
setupFilesAfterEnv: ['<rootDir>/jest-setup.ts'],
|
||||
coveragePathIgnorePatterns: ['/node_modules/'],
|
||||
modulePathIgnorePatterns: [
|
||||
// '<rootDir>/packages/dockview-angular/src/__tests__/__mocks__',
|
||||
// '<rootDir>/packages/dockview-angular/src/__tests__/__test_utils__',
|
||||
],
|
||||
coverageDirectory: '<rootDir>/packages/dockview-angular/coverage/',
|
||||
testResultsProcessor: 'jest-sonar-reporter',
|
||||
testEnvironment: 'jsdom',
|
||||
transform: {
|
||||
'^.+\\.tsx?$': [
|
||||
'ts-jest',
|
||||
{
|
||||
tsconfig: '<rootDir>/tsconfig.test.json',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
59
packages/dockview-angular/package.json
Normal file
59
packages/dockview-angular/package.json
Normal file
@ -0,0 +1,59 @@
|
||||
{
|
||||
"name": "dockview-angular",
|
||||
"version": "0.0.0-beta-0",
|
||||
"description": "Zero dependency layout manager supporting tabs, grids and splitviews",
|
||||
"keywords": [
|
||||
"splitview",
|
||||
"split-view",
|
||||
"gridview",
|
||||
"grid-view",
|
||||
"dockview",
|
||||
"dock-view",
|
||||
"grid",
|
||||
"tabs",
|
||||
"layout",
|
||||
"layout manager",
|
||||
"dock layout",
|
||||
"dock",
|
||||
"docking",
|
||||
"splitter",
|
||||
"drag-and-drop",
|
||||
"drag",
|
||||
"drop",
|
||||
"react",
|
||||
"react-component"
|
||||
],
|
||||
"homepage": "https://github.com/mathuo/dockview",
|
||||
"bugs": {
|
||||
"url": "https://github.com/mathuo/dockview/issues"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mathuo/dockview.git"
|
||||
},
|
||||
"license": "MIT",
|
||||
"author": "https://github.com/mathuo",
|
||||
"main": "./dist/cjs/index.js",
|
||||
"module": "./dist/esm/index.js",
|
||||
"types": "./dist/cjs/index.d.ts",
|
||||
"files": [
|
||||
"dist",
|
||||
"README.md"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "npm run build:package && npm run build:bundles",
|
||||
"build:bundles": "rollup -c",
|
||||
"build:cjs": "cross-env ../../node_modules/.bin/tsc --build ./tsconfig.json --verbose --extendedDiagnostics",
|
||||
"build:css": "gulp sass",
|
||||
"build:esm": "cross-env ../../node_modules/.bin/tsc --build ./tsconfig.esm.json --verbose --extendedDiagnostics",
|
||||
"build:package": "npm run build:cjs && npm run build:esm && npm run build:css",
|
||||
"clean": "rimraf dist/ .build/ .rollup.cache/",
|
||||
"prepublishOnly": "npm run rebuild && npm run test",
|
||||
"rebuild": "npm run clean && npm run build",
|
||||
"test": "cross-env ../../node_modules/.bin/jest --selectProjects dockview",
|
||||
"test:cov": "cross-env ../../node_modules/.bin/jest --selectProjects dockview --coverage"
|
||||
},
|
||||
"dependencies": {
|
||||
"dockview-core": "^1.10.1"
|
||||
}
|
||||
}
|
113
packages/dockview-angular/rollup.config.js
Normal file
113
packages/dockview-angular/rollup.config.js
Normal file
@ -0,0 +1,113 @@
|
||||
/* eslint-disable */
|
||||
|
||||
const { join } = require('path');
|
||||
const typescript = require('@rollup/plugin-typescript');
|
||||
const terser = require('@rollup/plugin-terser');
|
||||
const postcss = require('rollup-plugin-postcss');
|
||||
const nodeResolve = require('@rollup/plugin-node-resolve');
|
||||
|
||||
const { name, version, homepage, license } = require('./package.json');
|
||||
const main = join(__dirname, './scripts/rollupEntryTarget.ts');
|
||||
const mainNoStyles = join(__dirname, './src/index.ts');
|
||||
const outputDir = join(__dirname, 'dist');
|
||||
|
||||
function outputFile(format, isMinified, withStyles) {
|
||||
let filename = join(outputDir, name);
|
||||
|
||||
if (format !== 'umd') {
|
||||
filename += `.${format}`;
|
||||
}
|
||||
if (isMinified) {
|
||||
filename += '.min';
|
||||
}
|
||||
if (!withStyles) {
|
||||
filename += '.noStyle';
|
||||
}
|
||||
|
||||
return `${filename}.js`;
|
||||
}
|
||||
|
||||
function getInput(options) {
|
||||
const { withStyles } = options;
|
||||
|
||||
if (withStyles) {
|
||||
return main;
|
||||
}
|
||||
|
||||
return mainNoStyles;
|
||||
}
|
||||
|
||||
function createBundle(format, options) {
|
||||
const { withStyles, isMinified } = options;
|
||||
const input = getInput(options);
|
||||
const file = outputFile(format, isMinified, withStyles);
|
||||
|
||||
const external = [];
|
||||
|
||||
const output = {
|
||||
file,
|
||||
format,
|
||||
sourcemap: true,
|
||||
globals: {},
|
||||
banner: [
|
||||
`/**`,
|
||||
` * ${name}`,
|
||||
` * @version ${version}`,
|
||||
` * @link ${homepage}`,
|
||||
` * @license ${license}`,
|
||||
` */`,
|
||||
].join('\n'),
|
||||
};
|
||||
|
||||
const plugins = [
|
||||
nodeResolve({
|
||||
include: ['node_modules/dockview-core/**'],
|
||||
}),
|
||||
typescript({
|
||||
tsconfig: 'tsconfig.esm.json',
|
||||
}),
|
||||
];
|
||||
|
||||
if (isMinified) {
|
||||
plugins.push(terser());
|
||||
}
|
||||
if (withStyles) {
|
||||
plugins.push(postcss());
|
||||
}
|
||||
|
||||
if (format === 'umd') {
|
||||
output['name'] = name;
|
||||
}
|
||||
|
||||
external.push('react', 'react-dom');
|
||||
|
||||
if (format === 'umd') {
|
||||
output.globals['react'] = 'React';
|
||||
output.globals['react-dom'] = 'ReactDOM';
|
||||
}
|
||||
|
||||
return {
|
||||
input,
|
||||
output,
|
||||
plugins,
|
||||
external,
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = [
|
||||
// amd
|
||||
createBundle('amd', { withStyles: false, isMinified: false }),
|
||||
createBundle('amd', { withStyles: true, isMinified: false }),
|
||||
createBundle('amd', { withStyles: false, isMinified: true }),
|
||||
createBundle('amd', { withStyles: true, isMinified: true }),
|
||||
// umd
|
||||
createBundle('umd', { withStyles: false, isMinified: false }),
|
||||
createBundle('umd', { withStyles: true, isMinified: false }),
|
||||
createBundle('umd', { withStyles: false, isMinified: true }),
|
||||
createBundle('umd', { withStyles: true, isMinified: true }),
|
||||
// cjs
|
||||
createBundle('cjs', { withStyles: true, isMinified: false }),
|
||||
// esm
|
||||
createBundle('esm', { withStyles: true, isMinified: false }),
|
||||
createBundle('esm', { withStyles: true, isMinified: true }),
|
||||
];
|
2
packages/dockview-angular/scripts/rollupEntryTarget.ts
Normal file
2
packages/dockview-angular/scripts/rollupEntryTarget.ts
Normal file
@ -0,0 +1,2 @@
|
||||
import '../dist/styles/dockview.css';
|
||||
export * from '../src/index';
|
5
packages/dockview-angular/src/__tests__/empty.spec.ts
Normal file
5
packages/dockview-angular/src/__tests__/empty.spec.ts
Normal file
@ -0,0 +1,5 @@
|
||||
describe('empty', () => {
|
||||
test('that passes', () => {
|
||||
expect(true).toBeTruthy();
|
||||
});
|
||||
});
|
1
packages/dockview-angular/src/index.ts
Normal file
1
packages/dockview-angular/src/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from 'dockview-core';
|
14
packages/dockview-angular/tsconfig.esm.json
Normal file
14
packages/dockview-angular/tsconfig.esm.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"module": "ES2020",
|
||||
"moduleResolution": "node",
|
||||
"target": "es6",
|
||||
"outDir": "dist/esm",
|
||||
"tsBuildInfoFile": ".build/tsconfig.tsbuildinfo.esm",
|
||||
"jsx": "react",
|
||||
"rootDir": "src"
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["**/node_modules", "src/__tests__"]
|
||||
}
|
11
packages/dockview-angular/tsconfig.json
Normal file
11
packages/dockview-angular/tsconfig.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "dist/cjs",
|
||||
"tsBuildInfoFile": ".build/tsconfig.tsbuildinfo.cjs",
|
||||
"jsx": "react",
|
||||
"rootDir": "src"
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["**/node_modules", "src/__tests__"]
|
||||
}
|
5
packages/dockview-angular/typedoc.json
Normal file
5
packages/dockview-angular/typedoc.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": ["../../typedoc.base.json"],
|
||||
"entryPoints": ["src/index.ts"],
|
||||
"exclude": ["**/dist/**"]
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "dockview-core",
|
||||
"version": "1.12.0",
|
||||
"description": "Zero dependency layout manager supporting tabs, grids and splitviews with ReactJS support",
|
||||
"description": "Zero dependency layout manager supporting tabs, grids and splitviews",
|
||||
"keywords": [
|
||||
"splitview",
|
||||
"split-view",
|
||||
@ -53,4 +53,4 @@
|
||||
"test": "cross-env ../../node_modules/.bin/jest --selectProjects dockview-core",
|
||||
"test:cov": "cross-env ../../node_modules/.bin/jest --selectProjects dockview-core --coverage"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
import * as React from 'react';
|
||||
import React from 'react';
|
||||
|
||||
/**
|
||||
* useful utility type to erase readonly signatures for testing purposes
|
||||
|
@ -2,7 +2,7 @@ import { fireEvent } from '@testing-library/dom';
|
||||
import { Emitter, Event } from '../../../../events';
|
||||
import { ContentContainer } from '../../../../dockview/components/panel/content';
|
||||
import {
|
||||
GroupPanelContentPartInitParameters,
|
||||
GroupPanelPartInitParameters,
|
||||
IContentRenderer,
|
||||
} from '../../../../dockview/types';
|
||||
import { CompositeDisposable } from '../../../../lifecycle';
|
||||
@ -20,18 +20,13 @@ class TestContentRenderer
|
||||
{
|
||||
readonly element: HTMLElement;
|
||||
|
||||
readonly _onDidFocus = new Emitter<void>();
|
||||
readonly _onDidBlur = new Emitter<void>();
|
||||
readonly onDidFocus: Event<void> = this._onDidFocus.event;
|
||||
readonly onDidBlur: Event<void> = this._onDidBlur.event;
|
||||
|
||||
constructor(public id: string) {
|
||||
super();
|
||||
this.element = document.createElement('div');
|
||||
this.element.id = id;
|
||||
}
|
||||
|
||||
init(parameters: GroupPanelContentPartInitParameters): void {
|
||||
init(parameters: GroupPanelPartInitParameters): void {
|
||||
//
|
||||
}
|
||||
|
||||
@ -110,16 +105,6 @@ describe('contentContainer', () => {
|
||||
expect(focus).toBe(1);
|
||||
expect(blur).toBe(1);
|
||||
|
||||
// renderer explicitly asks for focus
|
||||
contentRenderer._onDidFocus.fire();
|
||||
expect(focus).toBe(2);
|
||||
expect(blur).toBe(1);
|
||||
|
||||
// renderer explicitly looses focus
|
||||
contentRenderer._onDidBlur.fire();
|
||||
expect(focus).toBe(2);
|
||||
expect(blur).toBe(2);
|
||||
|
||||
const contentRenderer2 = new TestContentRenderer('id-2');
|
||||
|
||||
const panel2 = {
|
||||
@ -130,25 +115,19 @@ describe('contentContainer', () => {
|
||||
} as Partial<IDockviewPanel>;
|
||||
|
||||
cut.openPanel(panel2 as IDockviewPanel);
|
||||
expect(focus).toBe(2);
|
||||
expect(blur).toBe(2);
|
||||
|
||||
// previous renderer events should no longer be attached to container
|
||||
contentRenderer._onDidFocus.fire();
|
||||
contentRenderer._onDidBlur.fire();
|
||||
expect(focus).toBe(2);
|
||||
expect(blur).toBe(2);
|
||||
// expect(focus).toBe(2);
|
||||
// expect(blur).toBe(1);
|
||||
|
||||
// new panel recieves focus
|
||||
fireEvent.focus(contentRenderer2.element);
|
||||
expect(focus).toBe(3);
|
||||
expect(blur).toBe(2);
|
||||
expect(focus).toBe(2);
|
||||
expect(blur).toBe(1);
|
||||
|
||||
// new panel looses focus
|
||||
fireEvent.blur(contentRenderer2.element);
|
||||
jest.runAllTimers();
|
||||
expect(focus).toBe(3);
|
||||
expect(blur).toBe(3);
|
||||
expect(focus).toBe(2);
|
||||
expect(blur).toBe(2);
|
||||
|
||||
disposable.dispose();
|
||||
});
|
||||
|
@ -18,6 +18,7 @@ import {
|
||||
} from '../../dockview/components/titlebar/tabsContainer';
|
||||
import { fromPartial } from '@total-typescript/shoehorn';
|
||||
import { DockviewApi } from '../../api/component.api';
|
||||
import { DockviewDndOverlayEvent } from '../../dockview/options';
|
||||
|
||||
class PanelContentPartTest implements IContentRenderer {
|
||||
element: HTMLElement = document.createElement('div');
|
||||
@ -2040,7 +2041,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 1000);
|
||||
@ -2147,7 +2147,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 1000);
|
||||
@ -2289,7 +2288,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 1000);
|
||||
@ -2418,7 +2416,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 1000);
|
||||
@ -2467,66 +2464,6 @@ describe('dockviewComponent', () => {
|
||||
});
|
||||
});
|
||||
|
||||
test('orthogonal realigment #5', () => {
|
||||
const container = document.createElement('div');
|
||||
|
||||
const dockview = new DockviewComponent({
|
||||
parentElement: container,
|
||||
components: {
|
||||
default: PanelContentPartTest,
|
||||
},
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.VERTICAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 1000);
|
||||
|
||||
expect(dockview.orientation).toBe(Orientation.VERTICAL);
|
||||
|
||||
dockview.addPanel({
|
||||
id: 'panel1',
|
||||
component: 'default',
|
||||
position: {
|
||||
direction: 'left',
|
||||
},
|
||||
});
|
||||
|
||||
expect(dockview.orientation).toBe(Orientation.HORIZONTAL);
|
||||
|
||||
expect(JSON.parse(JSON.stringify(dockview.toJSON()))).toEqual({
|
||||
activeGroup: '1',
|
||||
grid: {
|
||||
root: {
|
||||
type: 'branch',
|
||||
data: [
|
||||
{
|
||||
type: 'leaf',
|
||||
data: {
|
||||
views: ['panel1'],
|
||||
id: '1',
|
||||
activeView: 'panel1',
|
||||
},
|
||||
size: 1000,
|
||||
},
|
||||
],
|
||||
size: 1000,
|
||||
},
|
||||
height: 1000,
|
||||
width: 1000,
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
},
|
||||
panels: {
|
||||
panel1: {
|
||||
id: 'panel1',
|
||||
contentComponent: 'default',
|
||||
title: 'panel1',
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('that a empty component has no groups', () => {
|
||||
const container = document.createElement('div');
|
||||
|
||||
@ -2538,7 +2475,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
expect(dockview.groups.length).toBe(0);
|
||||
@ -2555,7 +2491,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
expect(dockview.groups.length).toBe(0);
|
||||
@ -2595,7 +2530,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
expect(JSON.parse(JSON.stringify(dockview.toJSON()))).toEqual({
|
||||
@ -2624,7 +2558,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(100, 100);
|
||||
@ -2711,7 +2644,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(100, 100);
|
||||
@ -2774,7 +2706,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
expect(dockview.orientation).toBe(Orientation.HORIZONTAL);
|
||||
@ -2865,7 +2796,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -2897,7 +2827,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -2922,8 +2851,6 @@ describe('dockviewComponent', () => {
|
||||
test('that external dnd events do not trigger the top-level center dnd target unless empty', () => {
|
||||
const container = document.createElement('div');
|
||||
|
||||
const showDndOverlay = jest.fn().mockReturnValue(true);
|
||||
|
||||
const dockview = new DockviewComponent({
|
||||
parentElement: container,
|
||||
components: {
|
||||
@ -2932,8 +2859,13 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
showDndOverlay: showDndOverlay,
|
||||
});
|
||||
|
||||
let events: DockviewDndOverlayEvent[] = [];
|
||||
|
||||
dockview.onUnhandledDragOverEvent((e) => {
|
||||
events.push(e);
|
||||
e.accept();
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -2973,13 +2905,11 @@ describe('dockviewComponent', () => {
|
||||
});
|
||||
fireEvent(dockview.element, eventLeft);
|
||||
|
||||
expect(showDndOverlay).toHaveBeenCalledWith({
|
||||
nativeEvent: eventLeft,
|
||||
position: 'left',
|
||||
target: 'edge',
|
||||
getData: getPanelData,
|
||||
});
|
||||
expect(showDndOverlay).toBeCalledTimes(1);
|
||||
expect(events[0].nativeEvent).toBe(eventLeft);
|
||||
expect(events[0].position).toBe('left');
|
||||
expect(events[0].target).toBe('edge');
|
||||
expect(events[0].getData).toBe(getPanelData);
|
||||
expect(events.length).toBe(1);
|
||||
|
||||
// right
|
||||
|
||||
@ -2992,13 +2922,11 @@ describe('dockviewComponent', () => {
|
||||
});
|
||||
fireEvent(dockview.element, eventRight);
|
||||
|
||||
expect(showDndOverlay).toHaveBeenCalledWith({
|
||||
nativeEvent: eventRight,
|
||||
position: 'right',
|
||||
target: 'edge',
|
||||
getData: getPanelData,
|
||||
});
|
||||
expect(showDndOverlay).toBeCalledTimes(2);
|
||||
expect(events[1].nativeEvent).toBe(eventRight);
|
||||
expect(events[1].position).toBe('right');
|
||||
expect(events[1].target).toBe('edge');
|
||||
expect(events[1].getData).toBe(getPanelData);
|
||||
expect(events.length).toBe(2);
|
||||
|
||||
// top
|
||||
|
||||
@ -3011,13 +2939,11 @@ describe('dockviewComponent', () => {
|
||||
});
|
||||
fireEvent(dockview.element, eventTop);
|
||||
|
||||
expect(showDndOverlay).toHaveBeenCalledWith({
|
||||
nativeEvent: eventTop,
|
||||
position: 'top',
|
||||
target: 'edge',
|
||||
getData: getPanelData,
|
||||
});
|
||||
expect(showDndOverlay).toBeCalledTimes(3);
|
||||
expect(events[2].nativeEvent).toBe(eventTop);
|
||||
expect(events[2].position).toBe('top');
|
||||
expect(events[2].target).toBe('edge');
|
||||
expect(events[2].getData).toBe(getPanelData);
|
||||
expect(events.length).toBe(3);
|
||||
|
||||
// top
|
||||
|
||||
@ -3030,13 +2956,11 @@ describe('dockviewComponent', () => {
|
||||
});
|
||||
fireEvent(dockview.element, eventBottom);
|
||||
|
||||
expect(showDndOverlay).toHaveBeenCalledWith({
|
||||
nativeEvent: eventBottom,
|
||||
position: 'bottom',
|
||||
target: 'edge',
|
||||
getData: getPanelData,
|
||||
});
|
||||
expect(showDndOverlay).toBeCalledTimes(4);
|
||||
expect(events[3].nativeEvent).toBe(eventBottom);
|
||||
expect(events[3].position).toBe('bottom');
|
||||
expect(events[3].target).toBe('edge');
|
||||
expect(events[3].getData).toBe(getPanelData);
|
||||
expect(events.length).toBe(4);
|
||||
|
||||
// center
|
||||
|
||||
@ -3050,7 +2974,7 @@ describe('dockviewComponent', () => {
|
||||
fireEvent(dockview.element, eventCenter);
|
||||
|
||||
// expect not to be called for center
|
||||
expect(showDndOverlay).toBeCalledTimes(4);
|
||||
expect(events.length).toBe(4);
|
||||
|
||||
dockview.removePanel(panel1);
|
||||
dockview.removePanel(panel2);
|
||||
@ -3066,13 +2990,11 @@ describe('dockviewComponent', () => {
|
||||
});
|
||||
fireEvent(dockview.element, eventCenter2);
|
||||
|
||||
expect(showDndOverlay).toHaveBeenCalledWith({
|
||||
nativeEvent: eventTop,
|
||||
position: 'center',
|
||||
target: 'edge',
|
||||
getData: getPanelData,
|
||||
});
|
||||
expect(showDndOverlay).toBeCalledTimes(5);
|
||||
expect(events[4].nativeEvent).toBe(eventCenter2);
|
||||
expect(events[4].position).toBe('center');
|
||||
expect(events[4].target).toBe('edge');
|
||||
expect(events[4].getData).toBe(getPanelData);
|
||||
expect(events.length).toBe(5);
|
||||
});
|
||||
|
||||
test('that dragging a tab triggers onWillDragPanel', () => {
|
||||
@ -3086,7 +3008,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -3126,7 +3047,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -3167,7 +3087,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -3257,7 +3176,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -3380,7 +3298,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
expect(dockview.disableResizing).toBeFalsy();
|
||||
@ -3398,7 +3315,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
disableAutoResizing: true,
|
||||
});
|
||||
|
||||
@ -3417,7 +3333,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -3445,7 +3360,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -3488,7 +3402,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -3531,7 +3444,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -3582,7 +3494,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -3633,7 +3544,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -3684,7 +3594,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -3743,7 +3652,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -3786,7 +3694,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -3829,7 +3736,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -3880,7 +3786,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -3931,7 +3836,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -3982,7 +3886,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -4041,7 +3944,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -4092,7 +3994,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -4142,7 +4043,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -4193,7 +4093,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -4243,7 +4142,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -4283,7 +4181,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -4322,7 +4219,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -4362,7 +4258,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -4423,7 +4318,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -4462,7 +4356,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -4495,7 +4388,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -4568,7 +4460,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -4613,7 +4504,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
panel1 = dockview.addPanel({
|
||||
@ -4667,7 +4557,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
const api = new DockviewApi(dockview);
|
||||
|
||||
|
@ -641,7 +641,6 @@ describe('dockviewGroupPanelModel', () => {
|
||||
return {
|
||||
id: 'testcomponentid',
|
||||
options: {
|
||||
showDndOverlay: jest.fn(),
|
||||
parentElement: document.createElement('div'),
|
||||
},
|
||||
getPanel: jest.fn(),
|
||||
@ -649,6 +648,7 @@ describe('dockviewGroupPanelModel', () => {
|
||||
onDidRemovePanel: jest.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
const accessor = new accessorMock() as DockviewComponent;
|
||||
const groupviewMock = jest.fn<Partial<DockviewGroupPanelModel>, []>(
|
||||
() => {
|
||||
@ -678,6 +678,12 @@ describe('dockviewGroupPanelModel', () => {
|
||||
new groupPanelMock() as DockviewGroupPanel
|
||||
);
|
||||
|
||||
let counter = 0;
|
||||
|
||||
cut.onUnhandledDragOverEvent(() => {
|
||||
counter++;
|
||||
});
|
||||
|
||||
const element = container
|
||||
.getElementsByClassName('content-container')
|
||||
.item(0)!;
|
||||
@ -690,7 +696,7 @@ describe('dockviewGroupPanelModel', () => {
|
||||
fireEvent.dragEnter(element);
|
||||
fireEvent.dragOver(element);
|
||||
|
||||
expect(accessor.options.showDndOverlay).toBeCalledTimes(1);
|
||||
expect(counter).toBe(1);
|
||||
|
||||
expect(
|
||||
element.getElementsByClassName('drop-target-dropzone').length
|
||||
@ -702,7 +708,6 @@ describe('dockviewGroupPanelModel', () => {
|
||||
return {
|
||||
id: 'testcomponentid',
|
||||
options: {
|
||||
showDndOverlay: () => true,
|
||||
parentElement: document.createElement('div'),
|
||||
},
|
||||
getPanel: jest.fn(),
|
||||
@ -739,6 +744,10 @@ describe('dockviewGroupPanelModel', () => {
|
||||
new groupPanelMock() as DockviewGroupPanel
|
||||
);
|
||||
|
||||
cut.onUnhandledDragOverEvent((e) => {
|
||||
e.accept();
|
||||
});
|
||||
|
||||
const element = container
|
||||
.getElementsByClassName('content-container')
|
||||
.item(0)!;
|
||||
@ -794,7 +803,6 @@ describe('dockviewGroupPanelModel', () => {
|
||||
return {
|
||||
id: 'testcomponentid',
|
||||
options: {
|
||||
showDndOverlay: jest.fn(),
|
||||
parentElement: document.createElement('div'),
|
||||
},
|
||||
getPanel: jest.fn(),
|
||||
@ -833,6 +841,12 @@ describe('dockviewGroupPanelModel', () => {
|
||||
new groupPanelMock() as DockviewGroupPanel
|
||||
);
|
||||
|
||||
let counter = 0;
|
||||
|
||||
cut.onUnhandledDragOverEvent(() => {
|
||||
counter++;
|
||||
});
|
||||
|
||||
cut.openPanel(new TestPanel('panel1', panelApi));
|
||||
|
||||
const element = container
|
||||
@ -852,7 +866,7 @@ describe('dockviewGroupPanelModel', () => {
|
||||
fireEvent.dragEnter(element);
|
||||
fireEvent.dragOver(element);
|
||||
|
||||
expect(accessor.options.showDndOverlay).toBeCalledTimes(0);
|
||||
expect(counter).toBe(0);
|
||||
|
||||
expect(
|
||||
element.getElementsByClassName('drop-target-dropzone').length
|
||||
@ -864,7 +878,6 @@ describe('dockviewGroupPanelModel', () => {
|
||||
return {
|
||||
id: 'testcomponentid',
|
||||
options: {
|
||||
showDndOverlay: jest.fn(),
|
||||
parentElement: document.createElement('div'),
|
||||
},
|
||||
getPanel: jest.fn(),
|
||||
@ -903,6 +916,12 @@ describe('dockviewGroupPanelModel', () => {
|
||||
new groupPanelMock() as DockviewGroupPanel
|
||||
);
|
||||
|
||||
let counter = 0;
|
||||
|
||||
cut.onUnhandledDragOverEvent(() => {
|
||||
counter++;
|
||||
});
|
||||
|
||||
cut.openPanel(new TestPanel('panel1', panelApi));
|
||||
cut.openPanel(new TestPanel('panel2', panelApi));
|
||||
|
||||
@ -923,7 +942,7 @@ describe('dockviewGroupPanelModel', () => {
|
||||
fireEvent.dragEnter(element);
|
||||
fireEvent.dragOver(element);
|
||||
|
||||
expect(accessor.options.showDndOverlay).toBeCalledTimes(0);
|
||||
expect(counter).toBe(0);
|
||||
|
||||
expect(
|
||||
element.getElementsByClassName('drop-target-dropzone').length
|
||||
@ -935,7 +954,6 @@ describe('dockviewGroupPanelModel', () => {
|
||||
return {
|
||||
id: 'testcomponentid',
|
||||
options: {
|
||||
showDndOverlay: jest.fn(),
|
||||
parentElement: document.createElement('div'),
|
||||
},
|
||||
getPanel: jest.fn(),
|
||||
@ -974,6 +992,12 @@ describe('dockviewGroupPanelModel', () => {
|
||||
new groupPanelMock() as DockviewGroupPanel
|
||||
);
|
||||
|
||||
let counter = 0;
|
||||
|
||||
cut.onUnhandledDragOverEvent(() => {
|
||||
counter++;
|
||||
});
|
||||
|
||||
cut.openPanel(new TestPanel('panel1', panelApi));
|
||||
cut.openPanel(new TestPanel('panel2', panelApi));
|
||||
|
||||
@ -994,7 +1018,7 @@ describe('dockviewGroupPanelModel', () => {
|
||||
fireEvent.dragEnter(element);
|
||||
fireEvent.dragOver(element);
|
||||
|
||||
expect(accessor.options.showDndOverlay).toBeCalledTimes(1);
|
||||
expect(counter).toBe(1);
|
||||
|
||||
expect(
|
||||
element.getElementsByClassName('drop-target-dropzone').length
|
||||
|
@ -5,6 +5,7 @@ import {
|
||||
import {
|
||||
AddGroupOptions,
|
||||
AddPanelOptions,
|
||||
DockviewDndOverlayEvent,
|
||||
MovementOptions,
|
||||
} from '../dockview/options';
|
||||
import { Parameters } from '../panel/types';
|
||||
@ -695,6 +696,10 @@ export class DockviewApi implements CommonApi<SerializedDockview> {
|
||||
return this.component.onWillDragPanel;
|
||||
}
|
||||
|
||||
get onUnhandledDragOverEvent(): Event<DockviewDndOverlayEvent> {
|
||||
return this.component.onUnhandledDragOverEvent;
|
||||
}
|
||||
|
||||
/**
|
||||
* All panel objects.
|
||||
*/
|
||||
|
@ -1,12 +1,17 @@
|
||||
import { Position, positionToDirection } from '../dnd/droptarget';
|
||||
import { DockviewComponent } from '../dockview/dockviewComponent';
|
||||
import { DockviewGroupPanel } from '../dockview/dockviewGroupPanel';
|
||||
import { DockviewGroupLocation } from '../dockview/dockviewGroupPanelModel';
|
||||
import {
|
||||
DockviewGroupChangeEvent,
|
||||
DockviewGroupLocation,
|
||||
} from '../dockview/dockviewGroupPanelModel';
|
||||
import { Emitter, Event } from '../events';
|
||||
import { MutableDisposable } from '../lifecycle';
|
||||
import { GridviewPanelApi, GridviewPanelApiImpl } from './gridviewPanelApi';
|
||||
|
||||
export interface DockviewGroupPanelApi extends GridviewPanelApi {
|
||||
readonly onDidLocationChange: Event<DockviewGroupPanelFloatingChangeEvent>;
|
||||
readonly onDidActivePanelChange: Event<DockviewGroupChangeEvent>;
|
||||
readonly location: DockviewGroupLocation;
|
||||
/**
|
||||
* If you require the Window object
|
||||
@ -27,6 +32,8 @@ export interface DockviewGroupPanelFloatingChangeEvent {
|
||||
const NOT_INITIALIZED_MESSAGE = 'DockviewGroupPanelApiImpl not initialized';
|
||||
|
||||
export class DockviewGroupPanelApiImpl extends GridviewPanelApiImpl {
|
||||
private readonly _mutableDisposable = new MutableDisposable();
|
||||
|
||||
private _group: DockviewGroupPanel | undefined;
|
||||
|
||||
readonly _onDidLocationChange =
|
||||
@ -34,6 +41,10 @@ export class DockviewGroupPanelApiImpl extends GridviewPanelApiImpl {
|
||||
readonly onDidLocationChange: Event<DockviewGroupPanelFloatingChangeEvent> =
|
||||
this._onDidLocationChange.event;
|
||||
|
||||
private readonly _onDidActivePanelChange =
|
||||
new Emitter<DockviewGroupChangeEvent>();
|
||||
readonly onDidActivePanelChange = this._onDidActivePanelChange.event;
|
||||
|
||||
get location(): DockviewGroupLocation {
|
||||
if (!this._group) {
|
||||
throw new Error(NOT_INITIALIZED_MESSAGE);
|
||||
@ -44,7 +55,11 @@ export class DockviewGroupPanelApiImpl extends GridviewPanelApiImpl {
|
||||
constructor(id: string, private readonly accessor: DockviewComponent) {
|
||||
super(id, '__dockviewgroup__');
|
||||
|
||||
this.addDisposables(this._onDidLocationChange);
|
||||
this.addDisposables(
|
||||
this._onDidLocationChange,
|
||||
this._onDidActivePanelChange,
|
||||
this._mutableDisposable
|
||||
);
|
||||
}
|
||||
|
||||
close(): void {
|
||||
@ -116,5 +131,19 @@ export class DockviewGroupPanelApiImpl extends GridviewPanelApiImpl {
|
||||
|
||||
initialize(group: DockviewGroupPanel): void {
|
||||
this._group = group;
|
||||
|
||||
/**
|
||||
* TODO: Annoying initialization order caveat
|
||||
*
|
||||
* Due to the order on initialization we know that the model isn't defined until later in the same stack-frame of setup.
|
||||
* By queuing a microtask we can ensure the setup is completed within the same stack-frame, but after everything else has
|
||||
* finished ensuring the `model` is defined.
|
||||
*/
|
||||
queueMicrotask(() => {
|
||||
this._mutableDisposable.value =
|
||||
this._group!.model.onDidActivePanelChange((event) => {
|
||||
this._onDidActivePanelChange.fire(event);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -68,9 +68,10 @@ export function positionToDirection(position: Position): Direction {
|
||||
|
||||
export type Position = 'top' | 'bottom' | 'left' | 'right' | 'center';
|
||||
|
||||
export type CanDisplayOverlay =
|
||||
| boolean
|
||||
| ((dragEvent: DragEvent, state: Position) => boolean);
|
||||
export type CanDisplayOverlay = (
|
||||
dragEvent: DragEvent,
|
||||
state: Position
|
||||
) => boolean;
|
||||
|
||||
export type MeasuredValue = { value: number; type: 'pixels' | 'percentage' };
|
||||
|
||||
@ -170,6 +171,11 @@ export class Droptarget extends CompositeDisposable {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.options.canDisplayOverlay(e, quadrant)) {
|
||||
this.removeDropTarget();
|
||||
return;
|
||||
}
|
||||
|
||||
const willShowOverlayEvent = new WillShowOverlayEvent({
|
||||
nativeEvent: e,
|
||||
position: quadrant,
|
||||
@ -186,16 +192,6 @@ export class Droptarget extends CompositeDisposable {
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof this.options.canDisplayOverlay === 'boolean') {
|
||||
if (!this.options.canDisplayOverlay) {
|
||||
this.removeDropTarget();
|
||||
return;
|
||||
}
|
||||
} else if (!this.options.canDisplayOverlay(e, quadrant)) {
|
||||
this.removeDropTarget();
|
||||
return;
|
||||
}
|
||||
|
||||
this.markAsUsed(e);
|
||||
|
||||
if (!this.targetElement) {
|
||||
|
@ -157,9 +157,6 @@ export class ContentContainer
|
||||
}
|
||||
|
||||
if (doRender) {
|
||||
const _onDidFocus = panel.view.content.onDidFocus;
|
||||
const _onDidBlur = panel.view.content.onDidBlur;
|
||||
|
||||
const focusTracker = trackFocus(container);
|
||||
const disposable = new CompositeDisposable();
|
||||
|
||||
@ -169,17 +166,6 @@ export class ContentContainer
|
||||
focusTracker.onDidBlur(() => this._onDidBlur.fire())
|
||||
);
|
||||
|
||||
if (_onDidFocus) {
|
||||
disposable.addDisposables(
|
||||
_onDidFocus(() => this._onDidFocus.fire())
|
||||
);
|
||||
}
|
||||
if (_onDidBlur) {
|
||||
disposable.addDisposables(
|
||||
_onDidBlur(() => this._onDidBlur.fire())
|
||||
);
|
||||
}
|
||||
|
||||
this.disposable.value = disposable;
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import {
|
||||
} from '../dnd/droptarget';
|
||||
import { tail, sequenceEquals, remove } from '../array';
|
||||
import { DockviewPanel, IDockviewPanel } from './dockviewPanel';
|
||||
import { CompositeDisposable, Disposable, IDisposable } from '../lifecycle';
|
||||
import { CompositeDisposable, Disposable } from '../lifecycle';
|
||||
import { Event, Emitter, addDisposableWindowListener } from '../events';
|
||||
import { Watermark } from './components/watermark/watermark';
|
||||
import { IWatermarkRenderer, GroupviewPanelState } from './types';
|
||||
@ -23,6 +23,9 @@ import {
|
||||
AddGroupOptions,
|
||||
AddPanelOptions,
|
||||
DockviewComponentOptions,
|
||||
DockviewDndOverlayEvent,
|
||||
DockviewOptions,
|
||||
DockviewUnhandledDragOverEvent,
|
||||
isGroupOptionsWithGroup,
|
||||
isGroupOptionsWithPanel,
|
||||
isPanelOptionsWithGroup,
|
||||
@ -233,25 +236,6 @@ function typeValidate(data: SerializedDockview): void {
|
||||
typeValidate2(grid.root, '.grid.root');
|
||||
}
|
||||
|
||||
export type DockviewComponentUpdateOptions = Pick<
|
||||
DockviewComponentOptions,
|
||||
| 'orientation'
|
||||
| 'components'
|
||||
| 'frameworkComponents'
|
||||
| 'tabComponents'
|
||||
| 'frameworkTabComponents'
|
||||
| 'showDndOverlay'
|
||||
| 'watermarkFrameworkComponent'
|
||||
| 'defaultTabComponent'
|
||||
| 'createLeftHeaderActionsElement'
|
||||
| 'createRightHeaderActionsElement'
|
||||
| 'createPrefixHeaderActionsElement'
|
||||
| 'disableFloatingGroups'
|
||||
| 'floatingGroupBounds'
|
||||
| 'rootOverlayModel'
|
||||
| 'disableDnd'
|
||||
>;
|
||||
|
||||
type MoveGroupOptions = {
|
||||
from: { group: DockviewGroupPanel };
|
||||
to: { group: DockviewGroupPanel; position: Position };
|
||||
@ -286,8 +270,9 @@ export interface IDockviewComponent extends IBaseGrid<DockviewGroupPanel> {
|
||||
readonly onDidRemoveGroup: Event<DockviewGroupPanel>;
|
||||
readonly onDidAddGroup: Event<DockviewGroupPanel>;
|
||||
readonly onDidActiveGroupChange: Event<DockviewGroupPanel | undefined>;
|
||||
readonly onUnhandledDragOverEvent: Event<DockviewDndOverlayEvent>;
|
||||
readonly options: DockviewComponentOptions;
|
||||
updateOptions(options: DockviewComponentUpdateOptions): void;
|
||||
updateOptions(options: DockviewOptions): void;
|
||||
moveGroupOrPanel(options: MoveGroupOrPanelOptions): void;
|
||||
moveGroup(options: MoveGroupOptions): void;
|
||||
doSetGroupActive: (group: DockviewGroupPanel, skipFocus?: boolean) => void;
|
||||
@ -354,6 +339,11 @@ export class DockviewComponent
|
||||
readonly onWillShowOverlay: Event<WillShowOverlayLocationEvent> =
|
||||
this._onWillShowOverlay.event;
|
||||
|
||||
private readonly _onUnhandledDragOverEvent =
|
||||
new Emitter<DockviewDndOverlayEvent>();
|
||||
readonly onUnhandledDragOverEvent: Event<DockviewDndOverlayEvent> =
|
||||
this._onUnhandledDragOverEvent.event;
|
||||
|
||||
private readonly _onDidRemovePanel = new Emitter<IDockviewPanel>();
|
||||
readonly onDidRemovePanel: Event<IDockviewPanel> =
|
||||
this._onDidRemovePanel.event;
|
||||
@ -436,8 +426,10 @@ export class DockviewComponent
|
||||
constructor(options: DockviewComponentOptions) {
|
||||
super({
|
||||
proportionalLayout: true,
|
||||
orientation: options.orientation ?? Orientation.HORIZONTAL,
|
||||
styles: options.styles,
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
styles: options.hideBorders
|
||||
? { separatorBorder: 'transparent' }
|
||||
: undefined,
|
||||
parentElement: options.parentElement,
|
||||
disableAutoResizing: options.disableAutoResizing,
|
||||
locked: options.locked,
|
||||
@ -467,6 +459,7 @@ export class DockviewComponent
|
||||
this._onDidAddGroup,
|
||||
this._onDidRemoveGroup,
|
||||
this._onDidActiveGroupChange,
|
||||
this._onUnhandledDragOverEvent,
|
||||
this.onDidAdd((event) => {
|
||||
if (!this._moving) {
|
||||
this._onDidAddGroup.fire(event);
|
||||
@ -547,25 +540,25 @@ export class DockviewComponent
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.options.showDndOverlay) {
|
||||
if (position === 'center' && this.gridview.length !== 0) {
|
||||
/**
|
||||
* for external events only show the four-corner drag overlays, disable
|
||||
* the center position so that external drag events can fall through to the group
|
||||
* and panel drop target handlers
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.options.showDndOverlay({
|
||||
nativeEvent: event,
|
||||
position: position,
|
||||
target: 'edge',
|
||||
getData: getPanelData,
|
||||
});
|
||||
if (position === 'center' && this.gridview.length !== 0) {
|
||||
/**
|
||||
* for external events only show the four-corner drag overlays, disable
|
||||
* the center position so that external drag events can fall through to the group
|
||||
* and panel drop target handlers
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
const firedEvent = new DockviewUnhandledDragOverEvent(
|
||||
event,
|
||||
'edge',
|
||||
position,
|
||||
getPanelData
|
||||
);
|
||||
|
||||
this._onUnhandledDragOverEvent.fire(firedEvent);
|
||||
|
||||
return firedEvent.isAccepted;
|
||||
},
|
||||
acceptedTargetZones: ['top', 'bottom', 'left', 'right', 'center'],
|
||||
overlayModel:
|
||||
@ -1052,24 +1045,17 @@ export class DockviewComponent
|
||||
}
|
||||
}
|
||||
|
||||
updateOptions(options: DockviewComponentUpdateOptions): void {
|
||||
const changed_orientation =
|
||||
typeof options.orientation === 'string' &&
|
||||
this.gridview.orientation !== options.orientation;
|
||||
updateOptions(options: Partial<DockviewComponentOptions>): void {
|
||||
const changed_floatingGroupBounds =
|
||||
options.floatingGroupBounds !== undefined &&
|
||||
'floatingGroupBounds' in options &&
|
||||
options.floatingGroupBounds !== this.options.floatingGroupBounds;
|
||||
|
||||
const changed_rootOverlayOptions =
|
||||
options.rootOverlayModel !== undefined &&
|
||||
'rootOverlayModel' in options &&
|
||||
options.rootOverlayModel !== this.options.rootOverlayModel;
|
||||
|
||||
this._options = { ...this.options, ...options };
|
||||
|
||||
if (changed_orientation) {
|
||||
this.gridview.orientation = options.orientation!;
|
||||
}
|
||||
|
||||
if (changed_floatingGroupBounds) {
|
||||
for (const group of this._floatingGroups) {
|
||||
switch (this.options.floatingGroupBounds) {
|
||||
@ -2162,6 +2148,9 @@ export class DockviewComponent
|
||||
|
||||
this._onWillShowOverlay.fire(event);
|
||||
}),
|
||||
view.model.onUnhandledDragOverEvent((event) => {
|
||||
this._onUnhandledDragOverEvent.fire(event);
|
||||
}),
|
||||
view.model.onDidAddPanel((event) => {
|
||||
if (this._moving) {
|
||||
return;
|
||||
|
@ -31,7 +31,11 @@ import {
|
||||
import { IWatermarkRenderer } from './types';
|
||||
import { DockviewGroupPanel } from './dockviewGroupPanel';
|
||||
import { IDockviewPanel } from './dockviewPanel';
|
||||
import { IHeaderActionsRenderer } from './options';
|
||||
import {
|
||||
DockviewDndOverlayEvent,
|
||||
DockviewUnhandledDragOverEvent,
|
||||
IHeaderActionsRenderer,
|
||||
} from './options';
|
||||
import { OverlayRenderContainer } from '../overlayRenderContainer';
|
||||
import { TitleEvent } from '../api/dockviewPanelApi';
|
||||
|
||||
@ -310,6 +314,11 @@ export class DockviewGroupPanelModel
|
||||
readonly onDidActivePanelChange: Event<DockviewGroupChangeEvent> =
|
||||
this._onDidActivePanelChange.event;
|
||||
|
||||
private readonly _onUnhandledDragOverEvent =
|
||||
new Emitter<DockviewDndOverlayEvent>();
|
||||
readonly onUnhandledDragOverEvent: Event<DockviewDndOverlayEvent> =
|
||||
this._onUnhandledDragOverEvent.event;
|
||||
|
||||
private readonly _api: DockviewApi;
|
||||
|
||||
get element(): HTMLElement {
|
||||
@ -491,7 +500,8 @@ export class DockviewGroupPanelModel
|
||||
this._onWillDrop,
|
||||
this._onDidAddPanel,
|
||||
this._onDidRemovePanel,
|
||||
this._onDidActivePanelChange
|
||||
this._onDidActivePanelChange,
|
||||
this._onUnhandledDragOverEvent
|
||||
);
|
||||
}
|
||||
|
||||
@ -536,45 +546,48 @@ export class DockviewGroupPanelModel
|
||||
this.setActive(this.isActive, true);
|
||||
this.updateContainer();
|
||||
|
||||
if (this.accessor.options.createRightHeaderActionsElement) {
|
||||
if (this.accessor.options.headerRightActionComponent) {
|
||||
this._rightHeaderActions =
|
||||
this.accessor.options.createRightHeaderActionsElement(
|
||||
this.accessor.options.headerRightActionComponent(
|
||||
this.groupPanel
|
||||
);
|
||||
this.addDisposables(this._rightHeaderActions);
|
||||
this._rightHeaderActions.init({
|
||||
containerApi: this._api,
|
||||
api: this.groupPanel.api,
|
||||
group: this.groupPanel,
|
||||
});
|
||||
this.tabsContainer.setRightActionsElement(
|
||||
this._rightHeaderActions.element
|
||||
);
|
||||
}
|
||||
|
||||
if (this.accessor.options.createLeftHeaderActionsElement) {
|
||||
if (this.accessor.options.headerLeftActionComponent) {
|
||||
this._leftHeaderActions =
|
||||
this.accessor.options.createLeftHeaderActionsElement(
|
||||
this.accessor.options.headerLeftActionComponent(
|
||||
this.groupPanel
|
||||
);
|
||||
this.addDisposables(this._leftHeaderActions);
|
||||
this._leftHeaderActions.init({
|
||||
containerApi: this._api,
|
||||
api: this.groupPanel.api,
|
||||
group: this.groupPanel,
|
||||
});
|
||||
this.tabsContainer.setLeftActionsElement(
|
||||
this._leftHeaderActions.element
|
||||
);
|
||||
}
|
||||
|
||||
if (this.accessor.options.createPrefixHeaderActionsElement) {
|
||||
if (this.accessor.options.headerPrefixActionComponent) {
|
||||
this._prefixHeaderActions =
|
||||
this.accessor.options.createPrefixHeaderActionsElement(
|
||||
this.accessor.options.headerPrefixActionComponent(
|
||||
this.groupPanel
|
||||
);
|
||||
this.addDisposables(this._prefixHeaderActions);
|
||||
this._prefixHeaderActions.init({
|
||||
containerApi: this._api,
|
||||
api: this.groupPanel.api,
|
||||
group: this.groupPanel,
|
||||
});
|
||||
this.tabsContainer.setPrefixActionsElement(
|
||||
this._prefixHeaderActions.element
|
||||
@ -853,10 +866,8 @@ export class DockviewGroupPanelModel
|
||||
this._panels.splice(index, 1);
|
||||
|
||||
if (this.mostRecentlyUsed.includes(panel)) {
|
||||
this.mostRecentlyUsed.splice(
|
||||
this.mostRecentlyUsed.indexOf(panel),
|
||||
1
|
||||
);
|
||||
const index = this.mostRecentlyUsed.indexOf(panel);
|
||||
this.mostRecentlyUsed.splice(index, 1);
|
||||
}
|
||||
|
||||
const disposable = this._panelDisposables.get(panel.id);
|
||||
@ -977,17 +988,17 @@ export class DockviewGroupPanelModel
|
||||
position: Position,
|
||||
target: DockviewGroupDropLocation
|
||||
): boolean {
|
||||
// custom overlay handler
|
||||
if (this.accessor.options.showDndOverlay) {
|
||||
return this.accessor.options.showDndOverlay({
|
||||
nativeEvent: event,
|
||||
target,
|
||||
group: this.accessor.getPanel(this.id)!,
|
||||
position,
|
||||
getData: getPanelData,
|
||||
});
|
||||
}
|
||||
return false;
|
||||
const firedEvent = new DockviewUnhandledDragOverEvent(
|
||||
event,
|
||||
target,
|
||||
position,
|
||||
getPanelData,
|
||||
this.accessor.getPanel(this.id)!
|
||||
);
|
||||
|
||||
this._onUnhandledDragOverEvent.fire(firedEvent);
|
||||
|
||||
return firedEvent.isAccepted;
|
||||
}
|
||||
|
||||
private handleDropEvent(
|
||||
|
@ -44,7 +44,7 @@ export class DockviewPanelModel implements IDockviewPanelModel {
|
||||
}
|
||||
|
||||
init(params: GroupPanelPartInitParameters): void {
|
||||
this.content.init({ ...params, tab: this.tab });
|
||||
this.content.init(params);
|
||||
this.tab.init(params);
|
||||
}
|
||||
|
||||
|
43
packages/dockview-core/src/dockview/framework.ts
Normal file
43
packages/dockview-core/src/dockview/framework.ts
Normal file
@ -0,0 +1,43 @@
|
||||
import { DockviewApi } from '../api/component.api';
|
||||
import { DockviewGroupPanelApi } from '../api/dockviewGroupPanelApi';
|
||||
import { DockviewPanelApi } from '../api/dockviewPanelApi';
|
||||
import { PanelParameters } from '../framwork';
|
||||
import { DockviewGroupPanel, IDockviewGroupPanel } from './dockviewGroupPanel';
|
||||
import { IDockviewPanel } from './dockviewPanel';
|
||||
|
||||
export interface IGroupPanelBaseProps<T extends { [index: string]: any } = any>
|
||||
extends PanelParameters<T> {
|
||||
api: DockviewPanelApi;
|
||||
containerApi: DockviewApi;
|
||||
}
|
||||
|
||||
export type IDockviewPanelHeaderProps<
|
||||
T extends { [index: string]: any } = any
|
||||
> = IGroupPanelBaseProps<T>;
|
||||
|
||||
export type IDockviewPanelProps<T extends { [index: string]: any } = any> =
|
||||
IGroupPanelBaseProps<T>;
|
||||
|
||||
export interface IDockviewHeaderActionsProps {
|
||||
api: DockviewGroupPanelApi;
|
||||
containerApi: DockviewApi;
|
||||
panels: IDockviewPanel[];
|
||||
activePanel: IDockviewPanel | undefined;
|
||||
isGroupActive: boolean;
|
||||
group: DockviewGroupPanel;
|
||||
}
|
||||
|
||||
export interface IGroupHeaderProps {
|
||||
api: DockviewGroupPanelApi;
|
||||
containerApi: DockviewApi;
|
||||
group: IDockviewGroupPanel;
|
||||
}
|
||||
|
||||
export interface IWatermarkPanelProps {
|
||||
containerApi: DockviewApi;
|
||||
group?: IDockviewGroupPanel;
|
||||
}
|
||||
|
||||
export interface DockviewReadyEvent {
|
||||
api: DockviewApi;
|
||||
}
|
@ -9,25 +9,24 @@ import {
|
||||
} from './types';
|
||||
import { Parameters } from '../panel/types';
|
||||
import { DockviewGroupPanel } from './dockviewGroupPanel';
|
||||
import { ISplitviewStyles, Orientation } from '../splitview/splitview';
|
||||
import { PanelTransfer } from '../dnd/dataTransfer';
|
||||
import { IDisposable } from '../lifecycle';
|
||||
import { DroptargetOverlayModel, Position } from '../dnd/droptarget';
|
||||
import { DockviewGroupDropLocation, GroupOptions } from './dockviewGroupPanelModel';
|
||||
import {
|
||||
DockviewGroupDropLocation,
|
||||
GroupOptions,
|
||||
} from './dockviewGroupPanelModel';
|
||||
import { IDockviewPanel } from './dockviewPanel';
|
||||
import {
|
||||
ComponentConstructor,
|
||||
FrameworkFactory,
|
||||
} from '../panel/componentFactory';
|
||||
import { DockviewGroupPanelApi } from '../api/dockviewGroupPanelApi';
|
||||
import { DockviewPanelRenderer } from '../overlayRenderContainer';
|
||||
import { IGroupHeaderProps } from './framework';
|
||||
|
||||
export interface IHeaderActionsRenderer extends IDisposable {
|
||||
readonly element: HTMLElement;
|
||||
init(params: {
|
||||
containerApi: DockviewApi;
|
||||
api: DockviewGroupPanelApi;
|
||||
}): void;
|
||||
init(params: IGroupHeaderProps): void;
|
||||
}
|
||||
|
||||
export interface GroupPanelFrameworkComponentFactory {
|
||||
@ -42,54 +41,15 @@ export interface TabContextMenuEvent {
|
||||
panel: IDockviewPanel;
|
||||
}
|
||||
|
||||
export interface DockviewRenderFunctions {
|
||||
tabComponents?: {
|
||||
[componentName: string]: ComponentConstructor<ITabRenderer>;
|
||||
};
|
||||
components?: {
|
||||
[componentName: string]: ComponentConstructor<IContentRenderer>;
|
||||
};
|
||||
frameworkTabComponents?: {
|
||||
[componentName: string]: any;
|
||||
};
|
||||
frameworkComponents?: {
|
||||
[componentName: string]: any;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ViewFactoryData {
|
||||
content: string;
|
||||
tab?: string;
|
||||
}
|
||||
|
||||
export interface DockviewDndOverlayEvent {
|
||||
nativeEvent: DragEvent;
|
||||
target: DockviewGroupDropLocation;
|
||||
position: Position;
|
||||
group?: DockviewGroupPanel;
|
||||
getData: () => PanelTransfer | undefined;
|
||||
}
|
||||
|
||||
export interface DockviewComponentOptions extends DockviewRenderFunctions {
|
||||
export interface DockviewOptions {
|
||||
disableAutoResizing?: boolean;
|
||||
watermarkComponent?: WatermarkConstructor;
|
||||
watermarkFrameworkComponent?: any;
|
||||
frameworkComponentFactory?: GroupPanelFrameworkComponentFactory;
|
||||
orientation?: Orientation;
|
||||
styles?: ISplitviewStyles;
|
||||
defaultTabComponent?: string;
|
||||
showDndOverlay?: (event: DockviewDndOverlayEvent) => boolean;
|
||||
createRightHeaderActionsElement?: (
|
||||
group: DockviewGroupPanel
|
||||
) => IHeaderActionsRenderer;
|
||||
createLeftHeaderActionsElement?: (
|
||||
group: DockviewGroupPanel
|
||||
) => IHeaderActionsRenderer;
|
||||
createPrefixHeaderActionsElement?: (
|
||||
group: DockviewGroupPanel
|
||||
) => IHeaderActionsRenderer;
|
||||
hideBorders?: boolean;
|
||||
singleTabMode?: 'fullwidth' | 'default';
|
||||
parentElement: HTMLElement;
|
||||
disableFloatingGroups?: boolean;
|
||||
floatingGroupBounds?:
|
||||
| 'boundedWithinViewport'
|
||||
@ -105,6 +65,91 @@ export interface DockviewComponentOptions extends DockviewRenderFunctions {
|
||||
disableDnd?: boolean;
|
||||
}
|
||||
|
||||
export interface DockviewDndOverlayEvent {
|
||||
nativeEvent: DragEvent;
|
||||
target: DockviewGroupDropLocation;
|
||||
position: Position;
|
||||
group?: DockviewGroupPanel;
|
||||
getData: () => PanelTransfer | undefined;
|
||||
//
|
||||
isAccepted: boolean;
|
||||
accept(): void;
|
||||
}
|
||||
|
||||
export class DockviewUnhandledDragOverEvent implements DockviewDndOverlayEvent {
|
||||
private _isAccepted = false;
|
||||
|
||||
get isAccepted(): boolean {
|
||||
return this._isAccepted;
|
||||
}
|
||||
|
||||
constructor(
|
||||
readonly nativeEvent: DragEvent,
|
||||
readonly target: DockviewGroupDropLocation,
|
||||
readonly position: Position,
|
||||
readonly getData: () => PanelTransfer | undefined,
|
||||
readonly group?: DockviewGroupPanel
|
||||
) {}
|
||||
|
||||
accept(): void {
|
||||
this._isAccepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
export const PROPERTY_KEYS: (keyof DockviewOptions)[] = (() => {
|
||||
/**
|
||||
* by readong the keys from an empty value object TypeScript will error
|
||||
* when we add or remove new properties to `DockviewOptions`
|
||||
*/
|
||||
const properties: Record<keyof DockviewOptions, undefined> = {
|
||||
disableAutoResizing: undefined,
|
||||
hideBorders: undefined,
|
||||
singleTabMode: undefined,
|
||||
disableFloatingGroups: undefined,
|
||||
floatingGroupBounds: undefined,
|
||||
popoutUrl: undefined,
|
||||
defaultRenderer: undefined,
|
||||
debug: undefined,
|
||||
rootOverlayModel: undefined,
|
||||
locked: undefined,
|
||||
disableDnd: undefined,
|
||||
};
|
||||
|
||||
return Object.keys(properties) as (keyof DockviewOptions)[];
|
||||
})();
|
||||
|
||||
export interface DockviewFrameworkOptions {
|
||||
headerRightActionComponent?: (
|
||||
group: DockviewGroupPanel
|
||||
) => IHeaderActionsRenderer;
|
||||
headerLeftActionComponent?: (
|
||||
group: DockviewGroupPanel
|
||||
) => IHeaderActionsRenderer;
|
||||
headerPrefixActionComponent?: (
|
||||
group: DockviewGroupPanel
|
||||
) => IHeaderActionsRenderer;
|
||||
tabComponents?: {
|
||||
[componentName: string]: ComponentConstructor<ITabRenderer>;
|
||||
};
|
||||
components?: {
|
||||
[componentName: string]: ComponentConstructor<IContentRenderer>;
|
||||
};
|
||||
frameworkTabComponents?: {
|
||||
[componentName: string]: any;
|
||||
};
|
||||
frameworkComponents?: {
|
||||
[componentName: string]: any;
|
||||
};
|
||||
parentElement: HTMLElement;
|
||||
defaultTabComponent?: string;
|
||||
watermarkComponent?: WatermarkConstructor;
|
||||
watermarkFrameworkComponent?: any;
|
||||
frameworkComponentFactory?: GroupPanelFrameworkComponentFactory;
|
||||
}
|
||||
|
||||
export type DockviewComponentOptions = DockviewOptions &
|
||||
DockviewFrameworkOptions;
|
||||
|
||||
export interface PanelOptions<P extends object = Parameters> {
|
||||
component: string;
|
||||
tabComponent?: string;
|
||||
|
@ -18,11 +18,6 @@ export interface GroupPanelPartInitParameters
|
||||
containerApi: DockviewApi;
|
||||
}
|
||||
|
||||
export interface GroupPanelContentPartInitParameters
|
||||
extends GroupPanelPartInitParameters {
|
||||
tab: ITabRenderer;
|
||||
}
|
||||
|
||||
export interface WatermarkRendererInitParameters {
|
||||
containerApi: DockviewApi;
|
||||
group?: IDockviewGroupPanel;
|
||||
@ -31,7 +26,7 @@ export interface WatermarkRendererInitParameters {
|
||||
export interface IWatermarkRenderer
|
||||
extends Optional<
|
||||
Omit<IPanel, 'id' | 'init'>,
|
||||
'dispose' | 'update' | 'layout' | 'toJSON'
|
||||
'dispose' | 'update' | 'layout' | 'toJSON' | 'focus'
|
||||
> {
|
||||
readonly element: HTMLElement;
|
||||
init: (params: WatermarkRendererInitParameters) => void;
|
||||
@ -41,7 +36,7 @@ export interface IWatermarkRenderer
|
||||
export interface ITabRenderer
|
||||
extends Optional<
|
||||
Omit<IPanel, 'id'>,
|
||||
'dispose' | 'update' | 'layout' | 'toJSON'
|
||||
'dispose' | 'update' | 'layout' | 'toJSON' | 'focus'
|
||||
> {
|
||||
readonly element: HTMLElement;
|
||||
init(parameters: GroupPanelPartInitParameters): void;
|
||||
@ -50,12 +45,10 @@ export interface ITabRenderer
|
||||
export interface IContentRenderer
|
||||
extends Optional<
|
||||
Omit<IPanel, 'id'>,
|
||||
'dispose' | 'update' | 'layout' | 'toJSON'
|
||||
'dispose' | 'update' | 'layout' | 'toJSON' | 'focus'
|
||||
> {
|
||||
readonly element: HTMLElement;
|
||||
readonly onDidFocus?: Event<void>;
|
||||
readonly onDidBlur?: Event<void>;
|
||||
init(parameters: GroupPanelContentPartInitParameters): void;
|
||||
init(parameters: GroupPanelPartInitParameters): void;
|
||||
}
|
||||
|
||||
// watermark component
|
||||
|
6
packages/dockview-core/src/framwork.ts
Normal file
6
packages/dockview-core/src/framwork.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import { Parameters } from "./panel/types";
|
||||
|
||||
export interface PanelParameters<T extends {} = Parameters> {
|
||||
params: T;
|
||||
}
|
||||
|
@ -23,19 +23,28 @@ export {
|
||||
export * from './paneview/paneview';
|
||||
export * from './gridview/gridview';
|
||||
export { GridviewComponentOptions } from './gridview/options';
|
||||
export * from './dockview/dockviewGroupPanelModel';
|
||||
export * from './gridview/baseComponentGridview';
|
||||
|
||||
export * from './paneview/draggablePaneviewPanel';
|
||||
|
||||
export * from './dockview/components/panel/content';
|
||||
export * from './dockview/components/tab/tab';
|
||||
export * from './dockview/dockviewGroupPanelModel';
|
||||
export {
|
||||
TabDragEvent,
|
||||
GroupDragEvent,
|
||||
} from './dockview/components/titlebar/tabsContainer';
|
||||
export * from './dockview/types';
|
||||
export * from './dockview/dockviewGroupPanel';
|
||||
export {
|
||||
IGroupPanelBaseProps,
|
||||
IDockviewPanelHeaderProps,
|
||||
IDockviewPanelProps,
|
||||
IDockviewHeaderActionsProps,
|
||||
IGroupHeaderProps,
|
||||
IWatermarkPanelProps,
|
||||
DockviewReadyEvent,
|
||||
} from './dockview/framework';
|
||||
|
||||
export * from './dockview/options';
|
||||
export * from './dockview/dockviewPanel';
|
||||
|
56
packages/dockview-react/README.md
Normal file
56
packages/dockview-react/README.md
Normal file
@ -0,0 +1,56 @@
|
||||
<div align="center">
|
||||
<h1>dockview</h1>
|
||||
|
||||
<p>Zero dependency layout manager supporting tabs, groups, grids and splitviews with ReactJS support written in TypeScript</p>
|
||||
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
[![npm version](https://badge.fury.io/js/dockview.svg)](https://www.npmjs.com/package/dockview)
|
||||
[![npm](https://img.shields.io/npm/dm/dockview)](https://www.npmjs.com/package/dockview)
|
||||
[![CI Build](https://github.com/mathuo/dockview/workflows/CI/badge.svg)](https://github.com/mathuo/dockview/actions?query=workflow%3ACI)
|
||||
[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=mathuo_dockview&metric=coverage)](https://sonarcloud.io/summary/overall?id=mathuo_dockview)
|
||||
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=mathuo_dockview&metric=alert_status)](https://sonarcloud.io/summary/overall?id=mathuo_dockview)
|
||||
[![Bundle Phobia](https://badgen.net/bundlephobia/minzip/dockview)](https://bundlephobia.com/result?p=dockview)
|
||||
|
||||
##
|
||||
|
||||
Please see the website: https://dockview.dev
|
||||
|
||||
## Features
|
||||
|
||||
- Serialization / deserialization with full layout management
|
||||
- Support for split-views, grid-views and 'dockable' views
|
||||
- Themeable and customizable
|
||||
- Tab and Group docking / Drag n' Drop
|
||||
- Popout Windows
|
||||
- Floating Groups
|
||||
- Extensive API
|
||||
- Supports Shadow DOMs
|
||||
- High test coverage
|
||||
- Documentation website with live examples
|
||||
- Transparent builds and Code Analysis
|
||||
- Security at mind - verifed publishing and builds through GitHub Actions
|
||||
|
||||
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>
|
||||
```
|
6
packages/dockview-react/gulpfile.js
Normal file
6
packages/dockview-react/gulpfile.js
Normal file
@ -0,0 +1,6 @@
|
||||
const gulp = require('gulp');
|
||||
const buildfile = require('../../scripts/build');
|
||||
|
||||
buildfile.init();
|
||||
|
||||
gulp.task('run', gulp.series(['sass']));
|
34
packages/dockview-react/jest.config.ts
Normal file
34
packages/dockview-react/jest.config.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import { JestConfigWithTsJest } from 'ts-jest';
|
||||
|
||||
const config: JestConfigWithTsJest = {
|
||||
preset: 'ts-jest',
|
||||
roots: ['<rootDir>/packages/dockview-react'],
|
||||
modulePaths: ['<rootDir>/packages/dockview-react/src'],
|
||||
displayName: { name: 'dockview-react', color: 'blue' },
|
||||
rootDir: '../../',
|
||||
collectCoverageFrom: [
|
||||
'<rootDir>/packages/dockview-react/src/**/*.{js,jsx,ts,tsx}',
|
||||
],
|
||||
setupFiles: [
|
||||
// '<rootDir>/packages/dockview-react/src/__tests__/__mocks__/resizeObserver.js',
|
||||
],
|
||||
setupFilesAfterEnv: ['<rootDir>/jest-setup.ts'],
|
||||
coveragePathIgnorePatterns: ['/node_modules/'],
|
||||
modulePathIgnorePatterns: [
|
||||
// '<rootDir>/packages/dockview-react/src/__tests__/__mocks__',
|
||||
// '<rootDir>/packages/dockview-react/src/__tests__/__test_utils__',
|
||||
],
|
||||
coverageDirectory: '<rootDir>/packages/dockview-react/coverage/',
|
||||
testResultsProcessor: 'jest-sonar-reporter',
|
||||
testEnvironment: 'jsdom',
|
||||
transform: {
|
||||
'^.+\\.tsx?$': [
|
||||
'ts-jest',
|
||||
{
|
||||
tsconfig: '<rootDir>/tsconfig.test.json',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
59
packages/dockview-react/package.json
Normal file
59
packages/dockview-react/package.json
Normal file
@ -0,0 +1,59 @@
|
||||
{
|
||||
"name": "dockview-react",
|
||||
"version": "0.0.0-beta-0",
|
||||
"description": "Zero dependency layout manager supporting tabs, grids and splitviews",
|
||||
"keywords": [
|
||||
"splitview",
|
||||
"split-view",
|
||||
"gridview",
|
||||
"grid-view",
|
||||
"dockview",
|
||||
"dock-view",
|
||||
"grid",
|
||||
"tabs",
|
||||
"layout",
|
||||
"layout manager",
|
||||
"dock layout",
|
||||
"dock",
|
||||
"docking",
|
||||
"splitter",
|
||||
"drag-and-drop",
|
||||
"drag",
|
||||
"drop",
|
||||
"react",
|
||||
"react-component"
|
||||
],
|
||||
"homepage": "https://github.com/mathuo/dockview",
|
||||
"bugs": {
|
||||
"url": "https://github.com/mathuo/dockview/issues"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mathuo/dockview.git"
|
||||
},
|
||||
"license": "MIT",
|
||||
"author": "https://github.com/mathuo",
|
||||
"main": "./dist/cjs/index.js",
|
||||
"module": "./dist/esm/index.js",
|
||||
"types": "./dist/cjs/index.d.ts",
|
||||
"files": [
|
||||
"dist",
|
||||
"README.md"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "npm run build:package && npm run build:bundles",
|
||||
"build:bundles": "rollup -c",
|
||||
"build:cjs": "cross-env ../../node_modules/.bin/tsc --build ./tsconfig.json --verbose --extendedDiagnostics",
|
||||
"build:css": "gulp sass",
|
||||
"build:esm": "cross-env ../../node_modules/.bin/tsc --build ./tsconfig.esm.json --verbose --extendedDiagnostics",
|
||||
"build:package": "npm run build:cjs && npm run build:esm && npm run build:css",
|
||||
"clean": "rimraf dist/ .build/ .rollup.cache/",
|
||||
"prepublishOnly": "npm run rebuild && npm run test",
|
||||
"rebuild": "npm run clean && npm run build",
|
||||
"test": "cross-env ../../node_modules/.bin/jest --selectProjects dockview",
|
||||
"test:cov": "cross-env ../../node_modules/.bin/jest --selectProjects dockview --coverage"
|
||||
},
|
||||
"dependencies": {
|
||||
"dockview": "^1.10.1"
|
||||
}
|
||||
}
|
113
packages/dockview-react/rollup.config.js
Normal file
113
packages/dockview-react/rollup.config.js
Normal file
@ -0,0 +1,113 @@
|
||||
/* eslint-disable */
|
||||
|
||||
const { join } = require('path');
|
||||
const typescript = require('@rollup/plugin-typescript');
|
||||
const terser = require('@rollup/plugin-terser');
|
||||
const postcss = require('rollup-plugin-postcss');
|
||||
const nodeResolve = require('@rollup/plugin-node-resolve');
|
||||
|
||||
const { name, version, homepage, license } = require('./package.json');
|
||||
const main = join(__dirname, './scripts/rollupEntryTarget.ts');
|
||||
const mainNoStyles = join(__dirname, './src/index.ts');
|
||||
const outputDir = join(__dirname, 'dist');
|
||||
|
||||
function outputFile(format, isMinified, withStyles) {
|
||||
let filename = join(outputDir, name);
|
||||
|
||||
if (format !== 'umd') {
|
||||
filename += `.${format}`;
|
||||
}
|
||||
if (isMinified) {
|
||||
filename += '.min';
|
||||
}
|
||||
if (!withStyles) {
|
||||
filename += '.noStyle';
|
||||
}
|
||||
|
||||
return `${filename}.js`;
|
||||
}
|
||||
|
||||
function getInput(options) {
|
||||
const { withStyles } = options;
|
||||
|
||||
if (withStyles) {
|
||||
return main;
|
||||
}
|
||||
|
||||
return mainNoStyles;
|
||||
}
|
||||
|
||||
function createBundle(format, options) {
|
||||
const { withStyles, isMinified } = options;
|
||||
const input = getInput(options);
|
||||
const file = outputFile(format, isMinified, withStyles);
|
||||
|
||||
const external = [];
|
||||
|
||||
const output = {
|
||||
file,
|
||||
format,
|
||||
sourcemap: true,
|
||||
globals: {},
|
||||
banner: [
|
||||
`/**`,
|
||||
` * ${name}`,
|
||||
` * @version ${version}`,
|
||||
` * @link ${homepage}`,
|
||||
` * @license ${license}`,
|
||||
` */`,
|
||||
].join('\n'),
|
||||
};
|
||||
|
||||
const plugins = [
|
||||
nodeResolve({
|
||||
include: ['node_modules/dockview-core/**'],
|
||||
}),
|
||||
typescript({
|
||||
tsconfig: 'tsconfig.esm.json',
|
||||
}),
|
||||
];
|
||||
|
||||
if (isMinified) {
|
||||
plugins.push(terser());
|
||||
}
|
||||
if (withStyles) {
|
||||
plugins.push(postcss());
|
||||
}
|
||||
|
||||
if (format === 'umd') {
|
||||
output['name'] = name;
|
||||
}
|
||||
|
||||
external.push('react', 'react-dom');
|
||||
|
||||
if (format === 'umd') {
|
||||
output.globals['react'] = 'React';
|
||||
output.globals['react-dom'] = 'ReactDOM';
|
||||
}
|
||||
|
||||
return {
|
||||
input,
|
||||
output,
|
||||
plugins,
|
||||
external,
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = [
|
||||
// amd
|
||||
createBundle('amd', { withStyles: false, isMinified: false }),
|
||||
createBundle('amd', { withStyles: true, isMinified: false }),
|
||||
createBundle('amd', { withStyles: false, isMinified: true }),
|
||||
createBundle('amd', { withStyles: true, isMinified: true }),
|
||||
// umd
|
||||
createBundle('umd', { withStyles: false, isMinified: false }),
|
||||
createBundle('umd', { withStyles: true, isMinified: false }),
|
||||
createBundle('umd', { withStyles: false, isMinified: true }),
|
||||
createBundle('umd', { withStyles: true, isMinified: true }),
|
||||
// cjs
|
||||
createBundle('cjs', { withStyles: true, isMinified: false }),
|
||||
// esm
|
||||
createBundle('esm', { withStyles: true, isMinified: false }),
|
||||
createBundle('esm', { withStyles: true, isMinified: true }),
|
||||
];
|
2
packages/dockview-react/scripts/rollupEntryTarget.ts
Normal file
2
packages/dockview-react/scripts/rollupEntryTarget.ts
Normal file
@ -0,0 +1,2 @@
|
||||
import '../dist/styles/dockview.css';
|
||||
export * from '../src/index';
|
5
packages/dockview-react/src/__tests__/empty.spec.ts
Normal file
5
packages/dockview-react/src/__tests__/empty.spec.ts
Normal file
@ -0,0 +1,5 @@
|
||||
describe('empty', () => {
|
||||
test('that passes', () => {
|
||||
expect(true).toBeTruthy();
|
||||
});
|
||||
});
|
0
packages/dockview-react/src/index.scss
Normal file
0
packages/dockview-react/src/index.scss
Normal file
1
packages/dockview-react/src/index.ts
Normal file
1
packages/dockview-react/src/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from 'dockview';
|
14
packages/dockview-react/tsconfig.esm.json
Normal file
14
packages/dockview-react/tsconfig.esm.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"module": "ES2020",
|
||||
"moduleResolution": "node",
|
||||
"target": "es6",
|
||||
"outDir": "dist/esm",
|
||||
"tsBuildInfoFile": ".build/tsconfig.tsbuildinfo.esm",
|
||||
"jsx": "react",
|
||||
"rootDir": "src"
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["**/node_modules", "src/__tests__"]
|
||||
}
|
11
packages/dockview-react/tsconfig.json
Normal file
11
packages/dockview-react/tsconfig.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "dist/cjs",
|
||||
"tsBuildInfoFile": ".build/tsconfig.tsbuildinfo.cjs",
|
||||
"jsx": "react",
|
||||
"rootDir": "src"
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["**/node_modules", "src/__tests__"]
|
||||
}
|
5
packages/dockview-react/typedoc.json
Normal file
5
packages/dockview-react/typedoc.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": ["../../typedoc.base.json"],
|
||||
"entryPoints": ["src/index.ts"],
|
||||
"exclude": ["**/dist/**"]
|
||||
}
|
56
packages/dockview-vue/README.md
Normal file
56
packages/dockview-vue/README.md
Normal file
@ -0,0 +1,56 @@
|
||||
<div align="center">
|
||||
<h1>dockview</h1>
|
||||
|
||||
<p>Zero dependency layout manager supporting tabs, groups, grids and splitviews with ReactJS support written in TypeScript</p>
|
||||
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
[![npm version](https://badge.fury.io/js/dockview.svg)](https://www.npmjs.com/package/dockview)
|
||||
[![npm](https://img.shields.io/npm/dm/dockview)](https://www.npmjs.com/package/dockview)
|
||||
[![CI Build](https://github.com/mathuo/dockview/workflows/CI/badge.svg)](https://github.com/mathuo/dockview/actions?query=workflow%3ACI)
|
||||
[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=mathuo_dockview&metric=coverage)](https://sonarcloud.io/summary/overall?id=mathuo_dockview)
|
||||
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=mathuo_dockview&metric=alert_status)](https://sonarcloud.io/summary/overall?id=mathuo_dockview)
|
||||
[![Bundle Phobia](https://badgen.net/bundlephobia/minzip/dockview)](https://bundlephobia.com/result?p=dockview)
|
||||
|
||||
##
|
||||
|
||||
Please see the website: https://dockview.dev
|
||||
|
||||
## Features
|
||||
|
||||
- Serialization / deserialization with full layout management
|
||||
- Support for split-views, grid-views and 'dockable' views
|
||||
- Themeable and customizable
|
||||
- Tab and Group docking / Drag n' Drop
|
||||
- Popout Windows
|
||||
- Floating Groups
|
||||
- Extensive API
|
||||
- Supports Shadow DOMs
|
||||
- High test coverage
|
||||
- Documentation website with live examples
|
||||
- Transparent builds and Code Analysis
|
||||
- Security at mind - verifed publishing and builds through GitHub Actions
|
||||
|
||||
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>
|
||||
```
|
6
packages/dockview-vue/gulpfile.js
Normal file
6
packages/dockview-vue/gulpfile.js
Normal file
@ -0,0 +1,6 @@
|
||||
const gulp = require('gulp');
|
||||
const buildfile = require('../../scripts/build');
|
||||
|
||||
buildfile.init();
|
||||
|
||||
gulp.task('run', gulp.series(['sass']));
|
34
packages/dockview-vue/jest.config.ts
Normal file
34
packages/dockview-vue/jest.config.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import { JestConfigWithTsJest } from 'ts-jest';
|
||||
|
||||
const config: JestConfigWithTsJest = {
|
||||
preset: 'ts-jest',
|
||||
roots: ['<rootDir>/packages/dockview-vue'],
|
||||
modulePaths: ['<rootDir>/packages/dockview-vue/src'],
|
||||
displayName: { name: 'dockview', color: 'blue' },
|
||||
rootDir: '../../',
|
||||
collectCoverageFrom: [
|
||||
'<rootDir>/packages/dockview-vue/src/**/*.{js,jsx,ts,tsx}',
|
||||
],
|
||||
setupFiles: [
|
||||
// '<rootDir>/packages/dockview-vue/src/__tests__/__mocks__/resizeObserver.js',
|
||||
],
|
||||
setupFilesAfterEnv: ['<rootDir>/jest-setup.ts'],
|
||||
coveragePathIgnorePatterns: ['/node_modules/'],
|
||||
modulePathIgnorePatterns: [
|
||||
// '<rootDir>/packages/dockview-vue/src/__tests__/__mocks__',
|
||||
// '<rootDir>/packages/dockview-vue/src/__tests__/__test_utils__',
|
||||
],
|
||||
coverageDirectory: '<rootDir>/packages/dockview-vue/coverage/',
|
||||
testResultsProcessor: 'jest-sonar-reporter',
|
||||
testEnvironment: 'jsdom',
|
||||
transform: {
|
||||
'^.+\\.tsx?$': [
|
||||
'ts-jest',
|
||||
{
|
||||
tsconfig: '<rootDir>/tsconfig.test.json',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
61
packages/dockview-vue/package.json
Normal file
61
packages/dockview-vue/package.json
Normal file
@ -0,0 +1,61 @@
|
||||
{
|
||||
"name": "dockview-vue",
|
||||
"version": "0.0.0-beta-0",
|
||||
"description": "Zero dependency layout manager supporting tabs, grids and splitviews",
|
||||
"keywords": [
|
||||
"splitview",
|
||||
"split-view",
|
||||
"gridview",
|
||||
"grid-view",
|
||||
"dockview",
|
||||
"dock-view",
|
||||
"grid",
|
||||
"tabs",
|
||||
"layout",
|
||||
"layout manager",
|
||||
"dock layout",
|
||||
"dock",
|
||||
"docking",
|
||||
"splitter",
|
||||
"drag-and-drop",
|
||||
"drag",
|
||||
"drop",
|
||||
"react",
|
||||
"react-component"
|
||||
],
|
||||
"main": "dist/dockview-vue.umd.js",
|
||||
"module": "dist/dockview-vue.es.js",
|
||||
"types": "dist/types/index.d.ts",
|
||||
"homepage": "https://github.com/mathuo/dockview",
|
||||
"bugs": {
|
||||
"url": "https://github.com/mathuo/dockview/issues"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mathuo/dockview.git"
|
||||
},
|
||||
"license": "MIT",
|
||||
"author": "https://github.com/mathuo",
|
||||
"files": [
|
||||
"dist",
|
||||
"README.md"
|
||||
],
|
||||
"scripts": {
|
||||
"build-only": "vite build",
|
||||
"build": "npm run build:package && npm run build:bundles",
|
||||
"build:bundles": "rollup -c",
|
||||
"build:cjs": "cross-env ../../node_modules/.bin/vue-tsc --build ./tsconfig.json --verbose --extendedDiagnostics",
|
||||
"build:css": "gulp sass",
|
||||
"build:esm": "cross-env ../../node_modules/.bin/vue-tsc --build ./tsconfig.esm.json --verbose --extendedDiagnostics",
|
||||
"build:package": "npm run build-only && npm run build:types",
|
||||
"clean": "rimraf dist/ .build/ .rollup.cache/",
|
||||
"prepublishOnly": "npm run rebuild && npm run test",
|
||||
"rebuild": "npm run clean && npm run build",
|
||||
"test": "cross-env ../../node_modules/.bin/jest --selectProjects dockview",
|
||||
"test:cov": "cross-env ../../node_modules/.bin/jest --selectProjects dockview --coverage",
|
||||
"build:types": "vue-tsc --project tsconfig.build-types.json --declaration --emitDeclarationOnly --outDir dist/types "
|
||||
},
|
||||
"dependencies": {
|
||||
"dockview-core": "^1.10.1"
|
||||
}
|
||||
}
|
116
packages/dockview-vue/rollup.config.js
Normal file
116
packages/dockview-vue/rollup.config.js
Normal file
@ -0,0 +1,116 @@
|
||||
/* eslint-disable */
|
||||
|
||||
const { join } = require('path');
|
||||
const typescript = require('@rollup/plugin-typescript');
|
||||
const terser = require('@rollup/plugin-terser');
|
||||
const postcss = require('rollup-plugin-postcss');
|
||||
const nodeResolve = require('@rollup/plugin-node-resolve');
|
||||
const vue = require('@vitejs/plugin-vue');
|
||||
|
||||
const { name, version, homepage, license } = require('./package.json');
|
||||
const main = join(__dirname, './scripts/rollupEntryTarget.ts');
|
||||
const mainNoStyles = join(__dirname, './src/index.ts');
|
||||
const outputDir = join(__dirname, 'dist');
|
||||
|
||||
function outputFile(format, isMinified, withStyles) {
|
||||
let filename = join(outputDir, name);
|
||||
|
||||
if (format !== 'umd') {
|
||||
filename += `.${format}`;
|
||||
}
|
||||
if (isMinified) {
|
||||
filename += '.min';
|
||||
}
|
||||
if (!withStyles) {
|
||||
filename += '.noStyle';
|
||||
}
|
||||
|
||||
return `${filename}.js`;
|
||||
}
|
||||
|
||||
function getInput(options) {
|
||||
const { withStyles } = options;
|
||||
|
||||
if (withStyles) {
|
||||
return main;
|
||||
}
|
||||
|
||||
return mainNoStyles;
|
||||
}
|
||||
|
||||
function createBundle(format, options) {
|
||||
const { withStyles, isMinified } = options;
|
||||
const input = getInput(options);
|
||||
const file = outputFile(format, isMinified, withStyles);
|
||||
|
||||
const external = [];
|
||||
|
||||
const output = {
|
||||
file,
|
||||
format,
|
||||
sourcemap: true,
|
||||
globals: {},
|
||||
banner: [
|
||||
`/**`,
|
||||
` * ${name}`,
|
||||
` * @version ${version}`,
|
||||
` * @link ${homepage}`,
|
||||
` * @license ${license}`,
|
||||
` */`,
|
||||
].join('\n'),
|
||||
};
|
||||
|
||||
const plugins = [
|
||||
nodeResolve({
|
||||
include: ['node_modules/dockview-core/**'],
|
||||
}),
|
||||
|
||||
typescript({
|
||||
tsconfig: 'tsconfig.config.json',
|
||||
}),
|
||||
vue({}),
|
||||
];
|
||||
|
||||
if (isMinified) {
|
||||
plugins.push(terser());
|
||||
}
|
||||
if (withStyles) {
|
||||
plugins.push(postcss());
|
||||
}
|
||||
|
||||
if (format === 'umd') {
|
||||
output['name'] = name;
|
||||
}
|
||||
|
||||
external.push('react', 'react-dom');
|
||||
|
||||
if (format === 'umd') {
|
||||
output.globals['react'] = 'React';
|
||||
output.globals['react-dom'] = 'ReactDOM';
|
||||
}
|
||||
|
||||
return {
|
||||
input,
|
||||
output,
|
||||
plugins,
|
||||
external,
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = [
|
||||
// amd
|
||||
createBundle('amd', { withStyles: false, isMinified: false }),
|
||||
createBundle('amd', { withStyles: true, isMinified: false }),
|
||||
createBundle('amd', { withStyles: false, isMinified: true }),
|
||||
createBundle('amd', { withStyles: true, isMinified: true }),
|
||||
// umd
|
||||
createBundle('umd', { withStyles: false, isMinified: false }),
|
||||
createBundle('umd', { withStyles: true, isMinified: false }),
|
||||
createBundle('umd', { withStyles: false, isMinified: true }),
|
||||
createBundle('umd', { withStyles: true, isMinified: true }),
|
||||
// cjs
|
||||
createBundle('cjs', { withStyles: true, isMinified: false }),
|
||||
// esm
|
||||
createBundle('esm', { withStyles: true, isMinified: false }),
|
||||
createBundle('esm', { withStyles: true, isMinified: true }),
|
||||
];
|
2
packages/dockview-vue/scripts/rollupEntryTarget.ts
Normal file
2
packages/dockview-vue/scripts/rollupEntryTarget.ts
Normal file
@ -0,0 +1,2 @@
|
||||
import '../dist/styles/dockview.css';
|
||||
export * from '../src/index';
|
5
packages/dockview-vue/src/__tests__/empty.spec.ts
Normal file
5
packages/dockview-vue/src/__tests__/empty.spec.ts
Normal file
@ -0,0 +1,5 @@
|
||||
describe('empty', () => {
|
||||
test('that passes', () => {
|
||||
expect(true).toBeTruthy();
|
||||
});
|
||||
});
|
316
packages/dockview-vue/src/dockview/dockview.vue
Normal file
316
packages/dockview-vue/src/dockview/dockview.vue
Normal file
@ -0,0 +1,316 @@
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
DockviewApi,
|
||||
DockviewComponent,
|
||||
type IContentRenderer,
|
||||
type ITabRenderer,
|
||||
type IWatermarkRenderer,
|
||||
type IDockviewPanelProps,
|
||||
type IDockviewPanelHeaderProps,
|
||||
type IGroupPanelBaseProps,
|
||||
type IWatermarkPanelProps,
|
||||
type DockviewOptions,
|
||||
PROPERTY_KEYS,
|
||||
type DockviewFrameworkOptions,
|
||||
type DockviewReadyEvent,
|
||||
} from 'dockview-core';
|
||||
import {
|
||||
ref,
|
||||
onMounted,
|
||||
defineProps,
|
||||
defineEmits,
|
||||
watch,
|
||||
onBeforeUnmount,
|
||||
markRaw,
|
||||
toRaw,
|
||||
getCurrentInstance,
|
||||
} from 'vue';
|
||||
import {
|
||||
VueContentRenderer,
|
||||
VueHeaderActionsRenderer,
|
||||
VueTabRenderer,
|
||||
VueWatermarkRenderer,
|
||||
type VueComponent,
|
||||
} from '../utils';
|
||||
|
||||
interface VueProps {
|
||||
components: Record<string, VueComponent<IDockviewPanelProps>>;
|
||||
tabComponents?: Record<string, VueComponent<IDockviewPanelHeaderProps>>;
|
||||
watermarkComponent?: VueComponent<IWatermarkPanelProps>;
|
||||
defaultTabComponent?: VueComponent<IDockviewPanelHeaderProps>;
|
||||
rightHeaderActionsComponent?: VueComponent<IGroupPanelBaseProps>;
|
||||
leftHeaderActionsComponent?: VueComponent<IGroupPanelBaseProps>;
|
||||
prefixHeaderActionsComponent?: VueComponent<IGroupPanelBaseProps>;
|
||||
}
|
||||
|
||||
const VUE_PROPERTIES = (() => {
|
||||
const _value: Record<keyof VueProps, undefined> = {
|
||||
components: undefined,
|
||||
tabComponents: undefined,
|
||||
watermarkComponent: undefined,
|
||||
defaultTabComponent: undefined,
|
||||
rightHeaderActionsComponent: undefined,
|
||||
leftHeaderActionsComponent: undefined,
|
||||
prefixHeaderActionsComponent: undefined,
|
||||
};
|
||||
|
||||
return Object.keys(_value) as (keyof VueProps)[];
|
||||
})();
|
||||
|
||||
type VueEvents = {
|
||||
ready: [event: DockviewReadyEvent];
|
||||
};
|
||||
|
||||
const DEFAULT_REACT_TAB = 'props.defaultTabComponent';
|
||||
|
||||
export type IDockviewVueProps = DockviewOptions & VueProps;
|
||||
|
||||
function extractCoreOptions(props: IDockviewVueProps): DockviewOptions {
|
||||
const coreOptions = (PROPERTY_KEYS as (keyof DockviewOptions)[]).reduce(
|
||||
(obj, key) => {
|
||||
(obj as any)[key] = props[key];
|
||||
return obj;
|
||||
},
|
||||
{} as Partial<DockviewOptions>
|
||||
);
|
||||
|
||||
return coreOptions as DockviewOptions;
|
||||
}
|
||||
|
||||
const emit = defineEmits<VueEvents>();
|
||||
|
||||
|
||||
/**
|
||||
* Anything here that is a Vue.js component should not be reactive
|
||||
* i.e. markRaw(toRaw(...))
|
||||
*/
|
||||
const props = defineProps<IDockviewVueProps>();
|
||||
|
||||
const el = ref<HTMLElement | null>(null);
|
||||
const instance = ref<DockviewComponent | null>(null);
|
||||
|
||||
|
||||
PROPERTY_KEYS.forEach((coreOptionKey) => {
|
||||
watch(
|
||||
() => props[coreOptionKey],
|
||||
(newValue, oldValue) => {
|
||||
if (instance.value) {
|
||||
instance.value.updateOptions({ [coreOptionKey]: newValue });
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.components,
|
||||
(newValue, oldValue) => {
|
||||
if (instance.value) {
|
||||
instance.value.updateOptions({ frameworkComponents: newValue });
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => [props.tabComponents, props.defaultTabComponent],
|
||||
([newTabComponents, newDefaultTabComponent], oldValue) => {
|
||||
if (instance.value) {
|
||||
const frameworkTabComponents = newTabComponents ?? {};
|
||||
|
||||
if (newDefaultTabComponent) {
|
||||
frameworkTabComponents[DEFAULT_REACT_TAB] =
|
||||
newDefaultTabComponent;
|
||||
}
|
||||
|
||||
instance.value.updateOptions({
|
||||
defaultTabComponent: newDefaultTabComponent
|
||||
? DEFAULT_REACT_TAB
|
||||
: undefined,
|
||||
frameworkTabComponents,
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.watermarkComponent,
|
||||
(newValue, oldValue) => {
|
||||
if (instance.value) {
|
||||
instance.value.updateOptions({
|
||||
watermarkFrameworkComponent: newValue,
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.leftHeaderActionsComponent,
|
||||
(newValue, oldValue) => {
|
||||
if (instance.value) {
|
||||
instance.value.updateOptions({
|
||||
headerLeftActionComponent: newValue
|
||||
? (group) => {
|
||||
return new VueHeaderActionsRenderer(
|
||||
newValue as VueComponent,
|
||||
getCurrentInstance()!,
|
||||
group
|
||||
);
|
||||
}
|
||||
: undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.rightHeaderActionsComponent,
|
||||
(newValue, oldValue) => {
|
||||
if (instance.value) {
|
||||
instance.value.updateOptions({
|
||||
headerRightActionComponent: newValue
|
||||
? (group) => {
|
||||
return new VueHeaderActionsRenderer(
|
||||
newValue as VueComponent,
|
||||
getCurrentInstance()!,
|
||||
group
|
||||
);
|
||||
}
|
||||
: undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.prefixHeaderActionsComponent,
|
||||
(newValue, oldValue) => {
|
||||
if (instance.value) {
|
||||
instance.value.updateOptions({
|
||||
headerPrefixActionComponent: newValue
|
||||
? (group) => {
|
||||
return new VueHeaderActionsRenderer(
|
||||
newValue as VueComponent,getCurrentInstance()!,
|
||||
group
|
||||
);
|
||||
}
|
||||
: undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
if (!el.value) {
|
||||
throw new Error('element is not mounted');
|
||||
}
|
||||
|
||||
const frameworkTabComponents = props.tabComponents ?? {};
|
||||
|
||||
if (props.defaultTabComponent) {
|
||||
frameworkTabComponents[DEFAULT_REACT_TAB] = props.defaultTabComponent;
|
||||
}
|
||||
|
||||
const frameworkOptions: DockviewFrameworkOptions = {
|
||||
parentElement: el.value,
|
||||
frameworkComponentFactory: {
|
||||
content: {
|
||||
createComponent: (
|
||||
id: string,
|
||||
componentId: string,
|
||||
component: any
|
||||
): IContentRenderer => {
|
||||
return new VueContentRenderer(component,getCurrentInstance()!);
|
||||
},
|
||||
},
|
||||
tab: {
|
||||
createComponent: (
|
||||
id: string,
|
||||
componentId: string,
|
||||
component: any
|
||||
): ITabRenderer => {
|
||||
return new VueTabRenderer(component,getCurrentInstance()!);
|
||||
},
|
||||
},
|
||||
watermark: {
|
||||
createComponent: (
|
||||
id: string,
|
||||
componentId: string,
|
||||
component: any
|
||||
): IWatermarkRenderer => {
|
||||
return new VueWatermarkRenderer(component,getCurrentInstance()!);
|
||||
},
|
||||
},
|
||||
// action: {
|
||||
// createComponent: (id: string, componentId: string, component: any): IWatermarkRenderer => {
|
||||
// return new VueHeaderActionRenderer(component)
|
||||
// }
|
||||
// }
|
||||
},
|
||||
frameworkComponents: props.components,
|
||||
frameworkTabComponents,
|
||||
headerLeftActionComponent: props.leftHeaderActionsComponent
|
||||
? (group) => {
|
||||
return new VueHeaderActionsRenderer(
|
||||
props.leftHeaderActionsComponent as VueComponent,getCurrentInstance()!,
|
||||
group
|
||||
);
|
||||
}
|
||||
: undefined,
|
||||
headerPrefixActionComponent: props.prefixHeaderActionsComponent
|
||||
? (group) => {
|
||||
return new VueHeaderActionsRenderer(
|
||||
props.prefixHeaderActionsComponent as VueComponent,getCurrentInstance()!,
|
||||
group
|
||||
);
|
||||
}
|
||||
: undefined,
|
||||
headerRightActionComponent: props.rightHeaderActionsComponent
|
||||
? (group) => {
|
||||
return new VueHeaderActionsRenderer(
|
||||
props.rightHeaderActionsComponent as VueComponent,getCurrentInstance()!,
|
||||
group
|
||||
);
|
||||
}
|
||||
: undefined,
|
||||
defaultTabComponent: props.defaultTabComponent
|
||||
? DEFAULT_REACT_TAB
|
||||
: undefined,
|
||||
watermarkFrameworkComponent:props.watermarkComponent
|
||||
};
|
||||
|
||||
const dockview = new DockviewComponent({
|
||||
...extractCoreOptions(props),
|
||||
...frameworkOptions,
|
||||
});
|
||||
|
||||
const { clientWidth, clientHeight } = el.value;
|
||||
dockview.layout(clientWidth, clientHeight);
|
||||
|
||||
/**
|
||||
* !!! THIS IS VERY IMPORTANT
|
||||
*
|
||||
* Since we store a reference to `DockviewComponent` within the Vue.js world Vue.js will 'deeply Proxyify' the object
|
||||
* since this is how Vue.js does its reactivity magic.
|
||||
*
|
||||
* We do not want Vue.js to touch the `DockviewComponent` reference since it does not need to be reactive in accordance
|
||||
* to the Vue.js reactivity model and since `DockviewComponent` is written in plain TypeScript allowing Vue.js
|
||||
* to proxify the reference will cause all kinds of unexpected issues
|
||||
*
|
||||
* @see https://vuejs.org/guide/extras/reactivity-in-depth.html
|
||||
* @see https://vuejs.org/api/reactivity-advanced.html#markraw
|
||||
*/
|
||||
instance.value = markRaw(dockview);
|
||||
|
||||
|
||||
emit('ready', { api: new DockviewApi(dockview) });
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (instance.value) {
|
||||
instance.value.dispose();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="el" />
|
||||
</template>
|
5
packages/dockview-vue/src/index.ts
Normal file
5
packages/dockview-vue/src/index.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export * from 'dockview-core';
|
||||
|
||||
import DockviewVue from './dockview/dockview.vue';
|
||||
export { DockviewVue };
|
||||
export * from './dockview/dockview.vue';
|
255
packages/dockview-vue/src/utils.ts
Normal file
255
packages/dockview-vue/src/utils.ts
Normal file
@ -0,0 +1,255 @@
|
||||
import type {
|
||||
DockviewGroupPanel,
|
||||
GroupPanelPartInitParameters,
|
||||
IContentRenderer,
|
||||
IGroupHeaderProps,
|
||||
IHeaderActionsRenderer,
|
||||
ITabRenderer,
|
||||
IWatermarkRenderer,
|
||||
PanelUpdateEvent,
|
||||
Parameters,
|
||||
WatermarkRendererInitParameters,
|
||||
} from 'dockview-core';
|
||||
import {
|
||||
createVNode,
|
||||
type ComponentOptionsBase,
|
||||
render,
|
||||
cloneVNode,
|
||||
mergeProps,
|
||||
type DefineComponent,
|
||||
type ComponentInternalInstance,
|
||||
} from 'vue';
|
||||
|
||||
export type ComponentInterface = ComponentOptionsBase<
|
||||
any,
|
||||
any,
|
||||
any,
|
||||
any,
|
||||
any,
|
||||
any,
|
||||
any,
|
||||
any
|
||||
>;
|
||||
|
||||
export type VueComponent<T = any> = DefineComponent<T>;
|
||||
|
||||
/**
|
||||
* TODO List
|
||||
*
|
||||
* 1. handle vue context-ish stuff (appContext? provides?)
|
||||
*
|
||||
*
|
||||
*
|
||||
* @see https://vuejs.org/api/render-function.html#clonevnode
|
||||
* @see https://vuejs.org/api/render-function.html#mergeprops
|
||||
*/
|
||||
export function mountVueComponent<T extends Record<string, any>>(
|
||||
component: VueComponent<T>,
|
||||
parent: ComponentInternalInstance,
|
||||
props: T,
|
||||
element: HTMLElement
|
||||
) {
|
||||
let vNode = createVNode(component, Object.freeze(props));
|
||||
|
||||
vNode.appContext = parent.appContext;
|
||||
|
||||
render(vNode, element);
|
||||
|
||||
let runningProps = props;
|
||||
|
||||
return {
|
||||
update: (newProps: any) => {
|
||||
runningProps = { ...props, newProps };
|
||||
vNode = cloneVNode(vNode, Object.freeze(runningProps));
|
||||
render(vNode, element);
|
||||
},
|
||||
dispose: () => {
|
||||
render(null, element);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export class VueContentRenderer implements IContentRenderer {
|
||||
private _element: HTMLElement;
|
||||
private _renderDisposable:
|
||||
| { update: (props: any) => void; dispose: () => void }
|
||||
| undefined;
|
||||
|
||||
get element(): HTMLElement {
|
||||
return this._element;
|
||||
}
|
||||
|
||||
constructor(
|
||||
private readonly component: VueComponent,
|
||||
private readonly parent: ComponentInternalInstance
|
||||
) {
|
||||
this._element = document.createElement('div');
|
||||
this.element.className = 'dv-vue-part';
|
||||
this.element.style.height = '100%';
|
||||
this.element.style.width = '100%';
|
||||
}
|
||||
|
||||
init(parameters: GroupPanelPartInitParameters): void {
|
||||
const props = {
|
||||
params: parameters.params,
|
||||
api: parameters.api,
|
||||
containerApi: parameters.containerApi,
|
||||
};
|
||||
|
||||
this._renderDisposable?.dispose();
|
||||
this._renderDisposable = mountVueComponent(
|
||||
this.component,
|
||||
this.parent,
|
||||
props,
|
||||
this.element
|
||||
);
|
||||
}
|
||||
|
||||
update(event: PanelUpdateEvent<Parameters>): void {
|
||||
const params = event.params;
|
||||
// TODO: handle prop updates somehow?
|
||||
this._renderDisposable?.update(params);
|
||||
}
|
||||
|
||||
focus(): void {
|
||||
// TODO: make optional on interface
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._renderDisposable?.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
export class VueTabRenderer implements ITabRenderer {
|
||||
private _element: HTMLElement;
|
||||
private _renderDisposable:
|
||||
| { update: (props: any) => void; dispose: () => void }
|
||||
| undefined;
|
||||
|
||||
get element(): HTMLElement {
|
||||
return this._element;
|
||||
}
|
||||
|
||||
constructor(
|
||||
private readonly component: VueComponent,
|
||||
private readonly parent: ComponentInternalInstance
|
||||
) {
|
||||
this._element = document.createElement('div');
|
||||
this.element.className = 'dv-vue-part';
|
||||
this.element.style.height = '100%';
|
||||
this.element.style.width = '100%';
|
||||
}
|
||||
|
||||
init(parameters: GroupPanelPartInitParameters): void {
|
||||
const props = {
|
||||
params: parameters.params,
|
||||
api: parameters.api,
|
||||
containerApi: parameters.containerApi,
|
||||
};
|
||||
|
||||
this._renderDisposable?.dispose();
|
||||
this._renderDisposable = mountVueComponent(
|
||||
this.component,
|
||||
this.parent,
|
||||
props,
|
||||
this.element
|
||||
);
|
||||
}
|
||||
|
||||
update(event: PanelUpdateEvent<Parameters>): void {
|
||||
const params = event.params;
|
||||
// TODO: handle prop updates somehow?
|
||||
this._renderDisposable?.update(params);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._renderDisposable?.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
export class VueWatermarkRenderer implements IWatermarkRenderer {
|
||||
private _element: HTMLElement;
|
||||
private _renderDisposable:
|
||||
| { update: (props: any) => void; dispose: () => void }
|
||||
| undefined;
|
||||
|
||||
get element(): HTMLElement {
|
||||
return this._element;
|
||||
}
|
||||
|
||||
constructor(
|
||||
private readonly component: VueComponent,
|
||||
private readonly parent: ComponentInternalInstance
|
||||
) {
|
||||
this._element = document.createElement('div');
|
||||
this.element.className = 'dv-vue-part';
|
||||
this.element.style.height = '100%';
|
||||
this.element.style.width = '100%';
|
||||
}
|
||||
|
||||
init(parameters: WatermarkRendererInitParameters): void {
|
||||
const props = {
|
||||
group: parameters.group,
|
||||
containerApi: parameters.containerApi,
|
||||
};
|
||||
|
||||
this._renderDisposable?.dispose();
|
||||
this._renderDisposable = mountVueComponent(
|
||||
this.component,
|
||||
this.parent,
|
||||
props,
|
||||
this.element
|
||||
);
|
||||
}
|
||||
|
||||
updateParentGroup(group: DockviewGroupPanel, visible: boolean): void {
|
||||
// TODO: make optional on interface
|
||||
}
|
||||
|
||||
update(event: PanelUpdateEvent<Parameters>): void {
|
||||
const params = event.params;
|
||||
// TODO: handle prop updates somehow?
|
||||
this._renderDisposable?.update(params);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._renderDisposable?.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
export class VueHeaderActionsRenderer implements IHeaderActionsRenderer {
|
||||
private _element: HTMLElement;
|
||||
private _renderDisposable:
|
||||
| { update: (props: any) => void; dispose: () => void }
|
||||
| undefined;
|
||||
|
||||
get element(): HTMLElement {
|
||||
return this._element;
|
||||
}
|
||||
|
||||
constructor(
|
||||
private readonly component: VueComponent,
|
||||
private readonly parent: ComponentInternalInstance,
|
||||
group: DockviewGroupPanel
|
||||
) {
|
||||
this._element = document.createElement('div');
|
||||
this.element.className = 'dv-vue-header-action-part';
|
||||
this._element.style.width = '100%';
|
||||
this._element.style.height = '100%';
|
||||
}
|
||||
|
||||
init(params: IGroupHeaderProps): void {
|
||||
console.log(params);
|
||||
this._renderDisposable?.dispose();
|
||||
this._renderDisposable = mountVueComponent(
|
||||
this.component,
|
||||
this.parent,
|
||||
{ ...params },
|
||||
this.element
|
||||
);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._renderDisposable?.dispose();
|
||||
}
|
||||
}
|
10
packages/dockview-vue/tsconfig.app.json
Normal file
10
packages/dockview-vue/tsconfig.app.json
Normal file
@ -0,0 +1,10 @@
|
||||
// tsconfig.app.json
|
||||
{
|
||||
"extends": "@vue/tsconfig/tsconfig.json",
|
||||
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
|
||||
"exclude": ["src/**/__tests__/*", "src/**/*.cy.ts"],
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"baseUrl": "."
|
||||
}
|
||||
}
|
10
packages/dockview-vue/tsconfig.build-types.json
Normal file
10
packages/dockview-vue/tsconfig.build-types.json
Normal file
@ -0,0 +1,10 @@
|
||||
// tsconfig.build-types.json
|
||||
{
|
||||
"include": ["src/**/*"],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"**/*.cy.ts",
|
||||
"**/*.spec.ts",
|
||||
"**/__tests__/**/*"
|
||||
]
|
||||
}
|
9
packages/dockview-vue/tsconfig.config.json
Normal file
9
packages/dockview-vue/tsconfig.config.json
Normal file
@ -0,0 +1,9 @@
|
||||
// tsconfig.config.json
|
||||
{
|
||||
"extends": "@vue/tsconfig/tsconfig.json",
|
||||
"include": ["vite.config.*", "vitest.config.*", "cypress.config.*"],
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"types": ["node"]
|
||||
}
|
||||
}
|
5
packages/dockview-vue/tsconfig.json
Normal file
5
packages/dockview-vue/tsconfig.json
Normal file
@ -0,0 +1,5 @@
|
||||
// tsconfig.json
|
||||
{
|
||||
"files": [],
|
||||
"references": [{ "path": "./tsconfig.config.json" }, { "path": "./tsconfig.app.json" }]
|
||||
}
|
5
packages/dockview-vue/typedoc.json
Normal file
5
packages/dockview-vue/typedoc.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": ["../../typedoc.base.json"],
|
||||
"entryPoints": ["src/index.ts"],
|
||||
"exclude": ["**/dist/**"]
|
||||
}
|
30
packages/dockview-vue/vite.config.ts
Normal file
30
packages/dockview-vue/vite.config.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import { defineConfig } from 'vite';
|
||||
import { resolve } from 'path';
|
||||
import vue from '@vitejs/plugin-vue';
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [vue()],
|
||||
build: {
|
||||
lib: {
|
||||
// src/indext.ts is where we have exported the component(s)
|
||||
entry: resolve(__dirname, 'src/index.ts'),
|
||||
name: 'dockview-vue',
|
||||
// the name of the output files when the build is run
|
||||
fileName: (format) => `dockview-vue.${format}.js`,
|
||||
},
|
||||
rollupOptions: {
|
||||
// make sure to externalize deps that shouldn't be bundled
|
||||
// into your library
|
||||
external: ['vue', 'dockview-core'],
|
||||
output: {
|
||||
// Provide global variables to use in the UMD build
|
||||
// for externalized deps
|
||||
globals: {
|
||||
vue: 'Vue',
|
||||
['dockview-core']: 'DockviewCore',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "dockview",
|
||||
"version": "1.12.0",
|
||||
"description": "Zero dependency layout manager supporting tabs, grids and splitviews with ReactJS support",
|
||||
"description": "Zero dependency layout manager supporting tabs, grids and splitviews",
|
||||
"keywords": [
|
||||
"splitview",
|
||||
"split-view",
|
||||
@ -56,4 +56,4 @@
|
||||
"dependencies": {
|
||||
"dockview-core": "^1.12.0"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,16 +1,19 @@
|
||||
import React from 'react';
|
||||
import { act, render, waitFor } from '@testing-library/react';
|
||||
import { DockviewApi, IDockviewPanel } from 'dockview-core';
|
||||
import {
|
||||
IDockviewPanelProps,
|
||||
DockviewReact,
|
||||
DockviewApi,
|
||||
DockviewReadyEvent,
|
||||
} from '../../dockview/dockview';
|
||||
import { PanelCollection } from '../../types';
|
||||
IDockviewPanel,
|
||||
IDockviewPanelProps,
|
||||
} from 'dockview-core';
|
||||
import { DockviewReact } from '../../dockview/dockview';
|
||||
import { setMockRefElement } from '../__test_utils__/utils';
|
||||
|
||||
describe('gridview react', () => {
|
||||
let components: PanelCollection<IDockviewPanelProps>;
|
||||
let components: Record<
|
||||
string,
|
||||
React.FunctionComponent<IDockviewPanelProps>
|
||||
>;
|
||||
|
||||
beforeEach(() => {
|
||||
components = {
|
||||
|
@ -6,11 +6,13 @@ import {
|
||||
GridviewReact,
|
||||
GridviewReadyEvent,
|
||||
} from '../../gridview/gridview';
|
||||
import { PanelCollection } from '../../types';
|
||||
import { setMockRefElement } from '../__test_utils__/utils';
|
||||
|
||||
describe('gridview react', () => {
|
||||
let components: PanelCollection<IGridviewPanelProps>;
|
||||
let components: Record<
|
||||
string,
|
||||
React.FunctionComponent<IGridviewPanelProps>
|
||||
>
|
||||
|
||||
beforeEach(() => {
|
||||
components = {
|
||||
|
@ -6,11 +6,13 @@ import {
|
||||
PaneviewReact,
|
||||
PaneviewReadyEvent,
|
||||
} from '../../paneview/paneview';
|
||||
import { PanelCollection } from '../../types';
|
||||
import { setMockRefElement } from '../__test_utils__/utils';
|
||||
|
||||
describe('gridview react', () => {
|
||||
let components: PanelCollection<IPaneviewPanelProps>;
|
||||
let components: Record<
|
||||
string,
|
||||
React.FunctionComponent<IPaneviewPanelProps>
|
||||
>;
|
||||
|
||||
beforeEach(() => {
|
||||
components = {
|
||||
|
@ -6,11 +6,13 @@ import {
|
||||
SplitviewReact,
|
||||
SplitviewReadyEvent,
|
||||
} from '../../splitview/splitview';
|
||||
import { PanelCollection } from '../../types';
|
||||
import { setMockRefElement } from '../__test_utils__/utils';
|
||||
|
||||
describe('splitview react', () => {
|
||||
let components: PanelCollection<ISplitviewPanelProps>;
|
||||
let components: Record<
|
||||
string,
|
||||
React.FunctionComponent<ISplitviewPanelProps>
|
||||
>;
|
||||
|
||||
beforeEach(() => {
|
||||
components = {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import { IDockviewPanelHeaderProps } from './dockview';
|
||||
import { CloseButton } from '../svg';
|
||||
import { IDockviewPanelHeaderProps } from 'dockview-core';
|
||||
|
||||
export type IDockviewDefaultTabProps = IDockviewPanelHeaderProps &
|
||||
React.DOMAttributes<HTMLDivElement> & {
|
||||
|
@ -2,28 +2,31 @@ import React from 'react';
|
||||
import {
|
||||
DockviewComponent,
|
||||
DockviewWillDropEvent,
|
||||
DockviewDndOverlayEvent,
|
||||
GroupPanelFrameworkComponentFactory,
|
||||
DockviewPanelApi,
|
||||
DockviewApi,
|
||||
IContentRenderer,
|
||||
ITabRenderer,
|
||||
DockviewGroupPanel,
|
||||
IHeaderActionsRenderer,
|
||||
DockviewPanelRenderer,
|
||||
DroptargetOverlayModel,
|
||||
DockviewDidDropEvent,
|
||||
IWatermarkPanelProps,
|
||||
IDockviewHeaderActionsProps,
|
||||
IDockviewPanelHeaderProps,
|
||||
IDockviewPanelProps,
|
||||
DockviewOptions,
|
||||
PROPERTY_KEYS,
|
||||
DockviewComponentOptions,
|
||||
DockviewFrameworkOptions,
|
||||
IDockviewDisposable,
|
||||
DockviewDndOverlayEvent,
|
||||
DockviewReadyEvent,
|
||||
} from 'dockview-core';
|
||||
import { ReactPanelContentPart } from './reactContentPart';
|
||||
import { ReactPanelHeaderPart } from './reactHeaderPart';
|
||||
|
||||
import { ReactPortalStore, usePortalsLifecycle } from '../react';
|
||||
import { IWatermarkPanelProps, ReactWatermarkPart } from './reactWatermarkPart';
|
||||
import { PanelCollection, PanelParameters } from '../types';
|
||||
import {
|
||||
IDockviewHeaderActionsProps,
|
||||
ReactHeaderActionsRendererPart,
|
||||
} from './headerActionsRenderer';
|
||||
import { ReactWatermarkPart } from './reactWatermarkPart';
|
||||
import { ReactHeaderActionsRendererPart } from './headerActionsRenderer';
|
||||
|
||||
function createGroupControlElement(
|
||||
component: React.FunctionComponent<IDockviewHeaderActionsProps> | undefined,
|
||||
@ -40,54 +43,81 @@ function createGroupControlElement(
|
||||
: undefined;
|
||||
}
|
||||
|
||||
export interface IGroupPanelBaseProps<T extends { [index: string]: any } = any>
|
||||
extends PanelParameters<T> {
|
||||
api: DockviewPanelApi;
|
||||
containerApi: DockviewApi;
|
||||
}
|
||||
const DEFAULT_REACT_TAB = 'props.defaultTabComponent';
|
||||
|
||||
export type IDockviewPanelHeaderProps<
|
||||
T extends { [index: string]: any } = any
|
||||
> = IGroupPanelBaseProps<T>;
|
||||
|
||||
export type IDockviewPanelProps<T extends { [index: string]: any } = any> =
|
||||
IGroupPanelBaseProps<T>;
|
||||
|
||||
export interface DockviewReadyEvent {
|
||||
api: DockviewApi;
|
||||
}
|
||||
|
||||
export interface IDockviewReactProps {
|
||||
onReady: (event: DockviewReadyEvent) => void;
|
||||
components: PanelCollection<IDockviewPanelProps>;
|
||||
tabComponents?: PanelCollection<IDockviewPanelHeaderProps>;
|
||||
watermarkComponent?: React.FunctionComponent<IWatermarkPanelProps>;
|
||||
onDidDrop?: (event: DockviewDidDropEvent) => void;
|
||||
onWillDrop?: (event: DockviewWillDropEvent) => void;
|
||||
showDndOverlay?: (event: DockviewDndOverlayEvent) => boolean;
|
||||
hideBorders?: boolean;
|
||||
export interface IDockviewReactProps extends DockviewOptions {
|
||||
className?: string;
|
||||
disableAutoResizing?: boolean;
|
||||
tabComponents?: Record<
|
||||
string,
|
||||
React.FunctionComponent<IDockviewPanelHeaderProps>
|
||||
>;
|
||||
components: Record<string, React.FunctionComponent<IDockviewPanelProps>>;
|
||||
watermarkComponent?: React.FunctionComponent<IWatermarkPanelProps>;
|
||||
defaultTabComponent?: React.FunctionComponent<IDockviewPanelHeaderProps>;
|
||||
rightHeaderActionsComponent?: React.FunctionComponent<IDockviewHeaderActionsProps>;
|
||||
leftHeaderActionsComponent?: React.FunctionComponent<IDockviewHeaderActionsProps>;
|
||||
prefixHeaderActionsComponent?: React.FunctionComponent<IDockviewHeaderActionsProps>;
|
||||
singleTabMode?: 'fullwidth' | 'default';
|
||||
disableFloatingGroups?: boolean;
|
||||
floatingGroupBounds?:
|
||||
| 'boundedWithinViewport'
|
||||
| {
|
||||
minimumHeightWithinViewport?: number;
|
||||
minimumWidthWithinViewport?: number;
|
||||
};
|
||||
debug?: boolean;
|
||||
defaultRenderer?: DockviewPanelRenderer;
|
||||
rootOverlayModel?: DroptargetOverlayModel;
|
||||
locked?: boolean;
|
||||
disableDnd?: boolean;
|
||||
//
|
||||
onReady: (event: DockviewReadyEvent) => void;
|
||||
onDidDrop?: (event: DockviewDidDropEvent) => void;
|
||||
onWillDrop?: (event: DockviewWillDropEvent) => void;
|
||||
/**
|
||||
* @deprecated use `api.onUnhandledDragOverEvent` instead. This will be removed in the next release.
|
||||
*/
|
||||
showDndOverlay?: (event: DockviewDndOverlayEvent) => boolean;
|
||||
}
|
||||
|
||||
const DEFAULT_REACT_TAB = 'props.defaultTabComponent';
|
||||
function extractCoreOptions(props: IDockviewReactProps): DockviewOptions {
|
||||
const coreOptions = (PROPERTY_KEYS as (keyof DockviewOptions)[]).reduce(
|
||||
(obj, key) => {
|
||||
obj[key] = props[key] as any;
|
||||
return obj;
|
||||
},
|
||||
{} as Partial<DockviewComponentOptions>
|
||||
);
|
||||
|
||||
return coreOptions as DockviewOptions;
|
||||
}
|
||||
|
||||
function createFrameworkFactory(
|
||||
addPortal: (portal: React.ReactPortal) => IDockviewDisposable
|
||||
): GroupPanelFrameworkComponentFactory {
|
||||
return {
|
||||
content: {
|
||||
createComponent: (
|
||||
_id: string,
|
||||
componentId: string,
|
||||
component: React.FunctionComponent<IDockviewPanelProps>
|
||||
): IContentRenderer => {
|
||||
return new ReactPanelContentPart(componentId, component, {
|
||||
addPortal,
|
||||
});
|
||||
},
|
||||
},
|
||||
tab: {
|
||||
createComponent: (
|
||||
_id: string,
|
||||
componentId: string,
|
||||
component: React.FunctionComponent<IDockviewPanelHeaderProps>
|
||||
): ITabRenderer => {
|
||||
return new ReactPanelHeaderPart(componentId, component, {
|
||||
addPortal,
|
||||
});
|
||||
},
|
||||
},
|
||||
watermark: {
|
||||
createComponent: (
|
||||
_id: string,
|
||||
componentId: string,
|
||||
component: React.FunctionComponent<{}>
|
||||
) => {
|
||||
return new ReactWatermarkPart(componentId, component, {
|
||||
addPortal,
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export const DockviewReact = React.forwardRef(
|
||||
(props: IDockviewReactProps, ref: React.ForwardedRef<HTMLDivElement>) => {
|
||||
@ -97,57 +127,37 @@ export const DockviewReact = React.forwardRef(
|
||||
|
||||
React.useImperativeHandle(ref, () => domRef.current!, []);
|
||||
|
||||
const prevProps = React.useRef<Partial<IDockviewReactProps>>({});
|
||||
|
||||
React.useEffect(
|
||||
() => {
|
||||
const changes: Partial<DockviewOptions> = {};
|
||||
|
||||
PROPERTY_KEYS.forEach((propKey) => {
|
||||
const key = propKey as keyof DockviewOptions;
|
||||
const propValue = props[key];
|
||||
|
||||
if (propValue !== prevProps.current[key]) {
|
||||
changes[key] = propValue as any;
|
||||
}
|
||||
});
|
||||
|
||||
if (dockviewRef.current) {
|
||||
dockviewRef.current.updateOptions(changes);
|
||||
} else {
|
||||
// not yet fully initialized
|
||||
}
|
||||
|
||||
prevProps.current = props;
|
||||
},
|
||||
PROPERTY_KEYS.map((key) => props[key])
|
||||
);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!domRef.current) {
|
||||
return () => {
|
||||
// noop
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
const factory: GroupPanelFrameworkComponentFactory = {
|
||||
content: {
|
||||
createComponent: (
|
||||
_id: string,
|
||||
componentId: string,
|
||||
component: React.FunctionComponent<IDockviewPanelProps>
|
||||
): IContentRenderer => {
|
||||
return new ReactPanelContentPart(
|
||||
componentId,
|
||||
component,
|
||||
{
|
||||
addPortal,
|
||||
}
|
||||
);
|
||||
},
|
||||
},
|
||||
tab: {
|
||||
createComponent: (
|
||||
_id: string,
|
||||
componentId: string,
|
||||
component: React.FunctionComponent<IDockviewPanelHeaderProps>
|
||||
): ITabRenderer => {
|
||||
return new ReactPanelHeaderPart(
|
||||
componentId,
|
||||
component,
|
||||
{
|
||||
addPortal,
|
||||
}
|
||||
);
|
||||
},
|
||||
},
|
||||
watermark: {
|
||||
createComponent: (
|
||||
_id: string,
|
||||
componentId: string,
|
||||
component: React.FunctionComponent<{}>
|
||||
) => {
|
||||
return new ReactWatermarkPart(componentId, component, {
|
||||
addPortal,
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const frameworkTabComponents = props.tabComponents ?? {};
|
||||
|
||||
if (props.defaultTabComponent) {
|
||||
@ -155,40 +165,32 @@ export const DockviewReact = React.forwardRef(
|
||||
props.defaultTabComponent;
|
||||
}
|
||||
|
||||
const dockview = new DockviewComponent({
|
||||
parentElement: domRef.current,
|
||||
frameworkComponentFactory: factory,
|
||||
frameworkComponents: props.components,
|
||||
disableAutoResizing: props.disableAutoResizing,
|
||||
frameworkTabComponents,
|
||||
watermarkFrameworkComponent: props.watermarkComponent,
|
||||
defaultTabComponent: props.defaultTabComponent
|
||||
? DEFAULT_REACT_TAB
|
||||
: undefined,
|
||||
styles: props.hideBorders
|
||||
? { separatorBorder: 'transparent' }
|
||||
: undefined,
|
||||
showDndOverlay: props.showDndOverlay,
|
||||
createLeftHeaderActionsElement: createGroupControlElement(
|
||||
const frameworkOptions: DockviewFrameworkOptions = {
|
||||
headerLeftActionComponent: createGroupControlElement(
|
||||
props.leftHeaderActionsComponent,
|
||||
{ addPortal }
|
||||
),
|
||||
createRightHeaderActionsElement: createGroupControlElement(
|
||||
headerRightActionComponent: createGroupControlElement(
|
||||
props.rightHeaderActionsComponent,
|
||||
{ addPortal }
|
||||
),
|
||||
createPrefixHeaderActionsElement: createGroupControlElement(
|
||||
headerPrefixActionComponent: createGroupControlElement(
|
||||
props.prefixHeaderActionsComponent,
|
||||
{ addPortal }
|
||||
),
|
||||
singleTabMode: props.singleTabMode,
|
||||
disableFloatingGroups: props.disableFloatingGroups,
|
||||
floatingGroupBounds: props.floatingGroupBounds,
|
||||
defaultRenderer: props.defaultRenderer,
|
||||
debug: props.debug,
|
||||
rootOverlayModel: props.rootOverlayModel,
|
||||
locked: props.locked,
|
||||
disableDnd: props.disableDnd,
|
||||
frameworkTabComponents,
|
||||
frameworkComponents: props.components,
|
||||
frameworkComponentFactory: createFrameworkFactory(addPortal),
|
||||
parentElement: domRef.current,
|
||||
defaultTabComponent: props.defaultTabComponent
|
||||
? DEFAULT_REACT_TAB
|
||||
: undefined,
|
||||
watermarkFrameworkComponent: props.watermarkComponent,
|
||||
};
|
||||
|
||||
const dockview = new DockviewComponent({
|
||||
...extractCoreOptions(props),
|
||||
...frameworkOptions,
|
||||
});
|
||||
|
||||
const { clientWidth, clientHeight } = domRef.current;
|
||||
@ -205,24 +207,6 @@ export const DockviewReact = React.forwardRef(
|
||||
};
|
||||
}, []);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!dockviewRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
dockviewRef.current.locked = !!props.locked;
|
||||
}, [props.locked]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!dockviewRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
dockviewRef.current.updateOptions({
|
||||
disableDnd: props.disableDnd,
|
||||
});
|
||||
}, [props.disableDnd]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!dockviewRef.current) {
|
||||
return () => {
|
||||
@ -241,6 +225,26 @@ export const DockviewReact = React.forwardRef(
|
||||
};
|
||||
}, [props.onDidDrop]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!dockviewRef.current) {
|
||||
return () => {
|
||||
// noop
|
||||
};
|
||||
}
|
||||
|
||||
const disposable = dockviewRef.current.onUnhandledDragOverEvent(
|
||||
(event) => {
|
||||
if (props.showDndOverlay?.(event)) {
|
||||
event.accept();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return () => {
|
||||
disposable.dispose();
|
||||
};
|
||||
}, [props.showDndOverlay]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!dockviewRef.current) {
|
||||
return () => {
|
||||
@ -268,15 +272,6 @@ export const DockviewReact = React.forwardRef(
|
||||
});
|
||||
}, [props.components]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!dockviewRef.current) {
|
||||
return;
|
||||
}
|
||||
dockviewRef.current.updateOptions({
|
||||
floatingGroupBounds: props.floatingGroupBounds,
|
||||
});
|
||||
}, [props.floatingGroupBounds]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!dockviewRef.current) {
|
||||
return;
|
||||
@ -286,33 +281,6 @@ export const DockviewReact = React.forwardRef(
|
||||
});
|
||||
}, [props.watermarkComponent]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!dockviewRef.current) {
|
||||
return;
|
||||
}
|
||||
dockviewRef.current.updateOptions({
|
||||
showDndOverlay: props.showDndOverlay,
|
||||
});
|
||||
}, [props.showDndOverlay]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!dockviewRef.current) {
|
||||
return;
|
||||
}
|
||||
dockviewRef.current.updateOptions({
|
||||
frameworkTabComponents: props.tabComponents,
|
||||
});
|
||||
}, [props.tabComponents]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!dockviewRef.current) {
|
||||
return;
|
||||
}
|
||||
dockviewRef.current.updateOptions({
|
||||
disableFloatingGroups: props.disableFloatingGroups,
|
||||
});
|
||||
}, [props.disableFloatingGroups]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!dockviewRef.current) {
|
||||
return;
|
||||
@ -331,14 +299,14 @@ export const DockviewReact = React.forwardRef(
|
||||
: undefined,
|
||||
frameworkTabComponents,
|
||||
});
|
||||
}, [props.defaultTabComponent]);
|
||||
}, [props.tabComponents, props.defaultTabComponent]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!dockviewRef.current) {
|
||||
return;
|
||||
}
|
||||
dockviewRef.current.updateOptions({
|
||||
createRightHeaderActionsElement: createGroupControlElement(
|
||||
headerRightActionComponent: createGroupControlElement(
|
||||
props.rightHeaderActionsComponent,
|
||||
{ addPortal }
|
||||
),
|
||||
@ -350,7 +318,7 @@ export const DockviewReact = React.forwardRef(
|
||||
return;
|
||||
}
|
||||
dockviewRef.current.updateOptions({
|
||||
createLeftHeaderActionsElement: createGroupControlElement(
|
||||
headerLeftActionComponent: createGroupControlElement(
|
||||
props.leftHeaderActionsComponent,
|
||||
{ addPortal }
|
||||
),
|
||||
@ -362,16 +330,7 @@ export const DockviewReact = React.forwardRef(
|
||||
return;
|
||||
}
|
||||
dockviewRef.current.updateOptions({
|
||||
rootOverlayModel: props.rootOverlayModel,
|
||||
});
|
||||
}, [props.rootOverlayModel]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!dockviewRef.current) {
|
||||
return;
|
||||
}
|
||||
dockviewRef.current.updateOptions({
|
||||
createPrefixHeaderActionsElement: createGroupControlElement(
|
||||
headerRightActionComponent: createGroupControlElement(
|
||||
props.prefixHeaderActionsComponent,
|
||||
{ addPortal }
|
||||
),
|
||||
|
@ -1,25 +1,17 @@
|
||||
import React from 'react';
|
||||
import { ReactPart, ReactPortalStore } from '../react';
|
||||
import {
|
||||
IDockviewPanel,
|
||||
DockviewCompositeDisposable,
|
||||
DockviewMutableDisposable,
|
||||
DockviewApi,
|
||||
DockviewGroupPanel,
|
||||
DockviewGroupPanelApi,
|
||||
PanelUpdateEvent,
|
||||
IHeaderActionsRenderer,
|
||||
IDockviewHeaderActionsProps,
|
||||
} from 'dockview-core';
|
||||
|
||||
export interface IDockviewHeaderActionsProps {
|
||||
api: DockviewGroupPanelApi;
|
||||
containerApi: DockviewApi;
|
||||
panels: IDockviewPanel[];
|
||||
activePanel: IDockviewPanel | undefined;
|
||||
isGroupActive: boolean;
|
||||
group: DockviewGroupPanel;
|
||||
}
|
||||
|
||||
export class ReactHeaderActionsRendererPart {
|
||||
export class ReactHeaderActionsRendererPart implements IHeaderActionsRenderer {
|
||||
private mutableDisposable = new DockviewMutableDisposable();
|
||||
private _element: HTMLElement;
|
||||
private _part?: ReactPart<IDockviewHeaderActionsProps>;
|
||||
@ -32,10 +24,6 @@ export class ReactHeaderActionsRendererPart {
|
||||
return this._part;
|
||||
}
|
||||
|
||||
get group(): DockviewGroupPanel {
|
||||
return this._group;
|
||||
}
|
||||
|
||||
constructor(
|
||||
private readonly component: React.FunctionComponent<IDockviewHeaderActionsProps>,
|
||||
private readonly reactPortalStore: ReactPortalStore,
|
||||
@ -47,11 +35,7 @@ export class ReactHeaderActionsRendererPart {
|
||||
this._element.style.width = '100%';
|
||||
}
|
||||
|
||||
focus(): void {
|
||||
// TODO
|
||||
}
|
||||
|
||||
public init(parameters: {
|
||||
init(parameters: {
|
||||
containerApi: DockviewApi;
|
||||
api: DockviewGroupPanelApi;
|
||||
}): void {
|
||||
@ -85,15 +69,15 @@ export class ReactHeaderActionsRendererPart {
|
||||
);
|
||||
}
|
||||
|
||||
public update(event: PanelUpdateEvent): void {
|
||||
this._part?.update(event.params);
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
dispose(): void {
|
||||
this.mutableDisposable.dispose();
|
||||
this._part?.dispose();
|
||||
}
|
||||
|
||||
update(event: PanelUpdateEvent): void {
|
||||
this._part?.update(event.params);
|
||||
}
|
||||
|
||||
private updatePanels(): void {
|
||||
this.update({ params: { panels: this._group.model.panels } });
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
import React from 'react';
|
||||
import { ReactPart, ReactPortalStore } from '../react';
|
||||
import { IDockviewPanelProps } from '../dockview/dockview';
|
||||
import {
|
||||
DockviewEmitter,
|
||||
DockviewEvent,
|
||||
PanelUpdateEvent,
|
||||
IContentRenderer,
|
||||
GroupPanelContentPartInitParameters,
|
||||
GroupPanelPartInitParameters,
|
||||
IDockviewPanelProps,
|
||||
} from 'dockview-core';
|
||||
|
||||
export class ReactPanelContentPart implements IContentRenderer {
|
||||
@ -38,7 +38,7 @@ export class ReactPanelContentPart implements IContentRenderer {
|
||||
// TODO
|
||||
}
|
||||
|
||||
public init(parameters: GroupPanelContentPartInitParameters): void {
|
||||
public init(parameters: GroupPanelPartInitParameters): void {
|
||||
this.part = new ReactPart(
|
||||
this.element,
|
||||
this.reactPortalStore,
|
||||
|
@ -1,10 +1,10 @@
|
||||
import React from 'react';
|
||||
import { ReactPart, ReactPortalStore } from '../react';
|
||||
import { IGroupPanelBaseProps } from './dockview';
|
||||
import {
|
||||
PanelUpdateEvent,
|
||||
ITabRenderer,
|
||||
GroupPanelPartInitParameters,
|
||||
IGroupPanelBaseProps,
|
||||
} from 'dockview-core';
|
||||
|
||||
export class ReactPanelHeaderPart implements ITabRenderer {
|
||||
|
@ -6,16 +6,9 @@ import {
|
||||
GroupPanelPartInitParameters,
|
||||
IWatermarkRenderer,
|
||||
WatermarkRendererInitParameters,
|
||||
DockviewApi,
|
||||
IDockviewGroupPanel,
|
||||
IWatermarkPanelProps,
|
||||
} from 'dockview-core';
|
||||
|
||||
export interface IWatermarkPanelProps {
|
||||
containerApi: DockviewApi;
|
||||
group?: IDockviewGroupPanel;
|
||||
close: () => void;
|
||||
}
|
||||
|
||||
export class ReactWatermarkPart implements IWatermarkRenderer {
|
||||
private _element: HTMLElement;
|
||||
private part?: ReactPart<IWatermarkPanelProps>;
|
||||
@ -44,11 +37,6 @@ export class ReactWatermarkPart implements IWatermarkRenderer {
|
||||
{
|
||||
group: parameters.group,
|
||||
containerApi: parameters.containerApi,
|
||||
close: () => {
|
||||
if (parameters.group) {
|
||||
parameters.containerApi.removeGroup(parameters.group);
|
||||
}
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -8,8 +8,7 @@ import {
|
||||
} from 'dockview-core';
|
||||
import { ReactGridPanelView } from './view';
|
||||
import { usePortalsLifecycle } from '../react';
|
||||
import { PanelCollection, PanelParameters } from '../types';
|
||||
|
||||
import { PanelParameters } from '../types';
|
||||
export interface GridviewReadyEvent {
|
||||
api: GridviewApi;
|
||||
}
|
||||
@ -23,7 +22,7 @@ export interface IGridviewPanelProps<T extends { [index: string]: any } = any>
|
||||
export interface IGridviewReactProps {
|
||||
orientation?: Orientation;
|
||||
onReady: (event: GridviewReadyEvent) => void;
|
||||
components: PanelCollection<IGridviewPanelProps>;
|
||||
components: Record<string, React.FunctionComponent<IGridviewPanelProps>>;
|
||||
hideBorders?: boolean;
|
||||
className?: string;
|
||||
proportionalLayout?: boolean;
|
||||
|
@ -4,8 +4,6 @@ export * from './dockview/dockview';
|
||||
export * from './dockview/defaultTab';
|
||||
export * from './splitview/splitview';
|
||||
export * from './gridview/gridview';
|
||||
export { IDockviewHeaderActionsProps } from './dockview/headerActionsRenderer';
|
||||
export { IWatermarkPanelProps } from './dockview/reactWatermarkPart';
|
||||
export * from './paneview/paneview';
|
||||
export * from './types';
|
||||
export * from './react';
|
||||
|
@ -9,7 +9,7 @@ import {
|
||||
} from 'dockview-core';
|
||||
import { usePortalsLifecycle } from '../react';
|
||||
import { PanePanelSection } from './view';
|
||||
import { PanelCollection, PanelParameters } from '../types';
|
||||
import { PanelParameters } from '../types';
|
||||
|
||||
export interface PaneviewReadyEvent {
|
||||
api: PaneviewApi;
|
||||
@ -24,8 +24,11 @@ export interface IPaneviewPanelProps<T extends { [index: string]: any } = any>
|
||||
|
||||
export interface IPaneviewReactProps {
|
||||
onReady: (event: PaneviewReadyEvent) => void;
|
||||
components: PanelCollection<IPaneviewPanelProps>;
|
||||
headerComponents?: PanelCollection<IPaneviewPanelProps>;
|
||||
components: Record<string, React.FunctionComponent<IPaneviewPanelProps>>;
|
||||
headerComponents?: Record<
|
||||
string,
|
||||
React.FunctionComponent<IPaneviewPanelProps>
|
||||
>;
|
||||
className?: string;
|
||||
disableAutoResizing?: boolean;
|
||||
disableDnd?: boolean;
|
||||
|
@ -7,7 +7,7 @@ import {
|
||||
Orientation,
|
||||
} from 'dockview-core';
|
||||
import { usePortalsLifecycle } from '../react';
|
||||
import { PanelCollection, PanelParameters } from '../types';
|
||||
import { PanelParameters } from '../types';
|
||||
import { ReactPanelView } from './view';
|
||||
|
||||
export interface SplitviewReadyEvent {
|
||||
@ -23,7 +23,7 @@ export interface ISplitviewPanelProps<T extends { [index: string]: any } = any>
|
||||
export interface ISplitviewReactProps {
|
||||
orientation?: Orientation;
|
||||
onReady: (event: SplitviewReadyEvent) => void;
|
||||
components: PanelCollection<ISplitviewPanelProps>;
|
||||
components: Record<string, React.FunctionComponent<ISplitviewPanelProps>>;
|
||||
proportionalLayout?: boolean;
|
||||
hideBorders?: boolean;
|
||||
className?: string;
|
||||
|
@ -1,10 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import { Parameters } from 'dockview-core';
|
||||
|
||||
export interface PanelCollection<T extends object> {
|
||||
[name: string]: React.FunctionComponent<T>;
|
||||
}
|
||||
|
||||
export interface PanelParameters<T extends {} = Parameters> {
|
||||
params: T;
|
||||
}
|
||||
|
2
packages/docs/.gitignore
vendored
2
packages/docs/.gitignore
vendored
@ -18,3 +18,5 @@
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
/static/templates
|
||||
|
41
packages/docs/blog/2024-04-19-dockview-1.13.0.md
Normal file
41
packages/docs/blog/2024-04-19-dockview-1.13.0.md
Normal file
@ -0,0 +1,41 @@
|
||||
---
|
||||
slug: dockview-1.13.0-release
|
||||
title: Dockview 1.13.0
|
||||
tags: [release]
|
||||
---
|
||||
|
||||
# Release Notes
|
||||
|
||||
Please reference docs @ [dockview.dev](https://dockview.dev).
|
||||
|
||||
## 🚀 Features
|
||||
|
||||
- Add `onDidActivePanelChange` event to group api [#541](https://github.com/mathuo/dockview/pull/541)
|
||||
|
||||
## 🛠 Miscs
|
||||
|
||||
- Create framework packages in preperation for multiple framework support [#541](https://github.com/mathuo/dockview/pull/541)
|
||||
These are still in active development and will be offically support soon.
|
||||
|
||||
- Create `dockview-react` package
|
||||
- Create `dockview-angular` package
|
||||
- Create `dockview-vue` package
|
||||
|
||||
- Move various type definitions from `dockview` to `dockview-core` in preperation for multiple framework support [#541](https://github.com/mathuo/dockview/pull/541)
|
||||
|
||||
- Move `IGroupPanelBaseProps` from `dockview` to `dockview-core`
|
||||
- Move `IDockviewPanelHeaderProps` from `dockview` to `dockview-core`
|
||||
- Move `IDockviewPanelProps` from `dockview` to `dockview-core`
|
||||
- Move `IDockviewHeaderActionsProps ` from `dockview` to `dockview-core`
|
||||
- Move `IGroupHeaderProps` from `dockview` to `dockview-core`
|
||||
- Move `IWatermarkPanelProps` from `dockview` to `dockview-core`
|
||||
- Move `DockviewReadyEvent` from `dockview` to `dockview-core`
|
||||
|
||||
- [dockview] Depreciate `canDisplayOverlay` in favour of the `onUnhandledDragOverEvent` api event [#541](https://github.com/mathuo/dockview/pull/541)
|
||||
|
||||
## 🔥 Breaking changes
|
||||
|
||||
- [dockview-core] Replace DockviewComponent `canDisplayOverlay` option with `onUnhandledDragOverEvent` event [#541](https://github.com/mathuo/dockview/pull/541)
|
||||
- [dockview-core] Rename `createRightHeaderActionsElement` to `headerRightActionComponent` [#541](https://github.com/mathuo/dockview/pull/541)
|
||||
- [dockview-core] Rename `createLeftHeaderActionsElement` to `headerLeftActionComponent` [#541](https://github.com/mathuo/dockview/pull/541)
|
||||
- [dockview-core] Rename `createPrefixHeaderActionsElement` to `headerPrefixActionComponent` [#541](https://github.com/mathuo/dockview/pull/541)
|
@ -3,12 +3,11 @@ title: Nested Instances
|
||||
---
|
||||
|
||||
|
||||
import { MultiFrameworkContainer } from '@site/src/components/ui/container';
|
||||
import NestedDockview from '@site/sandboxes/nested-dockview/src/app';
|
||||
import { CodeRunner } from '@site/src/components/ui/codeRunner';
|
||||
|
||||
# Nested Dockviews
|
||||
|
||||
You can safely create multiple dockview instances within one page and nest dockviews within other dockviews.
|
||||
If you wish to interact with the drop event from one dockview instance in another dockview instance you can implement the `showDndOverlay` and `onDidDrop` props on `DockviewReact`.
|
||||
|
||||
<MultiFrameworkContainer sandboxId="nested-dockview" react={NestedDockview} />
|
||||
<CodeRunner id="dockview/nested" />
|
||||
|
@ -2,7 +2,6 @@
|
||||
title: Constraints
|
||||
---
|
||||
|
||||
import LiveExample from '@site/src/components/ui/exampleFrame';
|
||||
import { DocRef } from '@site/src/components/ui/reference/docRef'
|
||||
|
||||
:::warning
|
||||
@ -13,5 +12,5 @@ Constraints come with several caveats. They are not serialized with layouts and
|
||||
|
||||
## Live Example
|
||||
|
||||
<LiveExample framework="react" id="dockview/constraints"/>
|
||||
<CodeRunner id="dockview/constraints"/>
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
title: Group Controls
|
||||
---
|
||||
|
||||
import LiveExample from '@site/src/components/ui/exampleFrame';
|
||||
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||
|
||||
This section describes how you can customize the header component of each group.
|
||||
@ -39,5 +38,5 @@ return <DockviewReact
|
||||
|
||||
## Live Example
|
||||
|
||||
<LiveExample framework="react" id="dockview/group-actions"/>
|
||||
<CodeRunner id="dockview/group-actions"/>
|
||||
|
||||
|
@ -3,7 +3,6 @@ title: Floating Groups
|
||||
---
|
||||
|
||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||
import LiveExample from '@site/src/components/ui/exampleFrame';
|
||||
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||
|
||||
This section describes floating groups.
|
||||
@ -76,4 +75,4 @@ You can check whether a group is floating via the `group.api.location` property.
|
||||
|
||||
## Live Example
|
||||
|
||||
<LiveExample framework="react" id="dockview/floating-groups"/>
|
||||
<CodeRunner id="dockview/floating-groups"/>
|
||||
|
@ -3,7 +3,6 @@ title: Hidden Header
|
||||
---
|
||||
|
||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||
import LiveExample from '@site/src/components/ui/exampleFrame';
|
||||
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||
|
||||
You may wish to hide the header section of a group. This can achieved through the `hidden` variable on `panel.group.header`.
|
||||
|
@ -2,8 +2,7 @@
|
||||
title: Locked Groups
|
||||
---
|
||||
|
||||
import { MultiFrameworkContainer } from '@site/src/components/ui/container';
|
||||
import DockviewLockedGroup from '@site/sandboxes/lockedgroup-dockview/src/app';
|
||||
import { CodeRunner } from '@site/src/components/ui/codeRunner';
|
||||
|
||||
## Locked group
|
||||
|
||||
@ -21,7 +20,4 @@ panel.group.locked = 'no-drop-target';
|
||||
Use `true` to keep drop zones top, right, bottom, left for the group. Use `no-drop-target` to disable all drop zones. For you to get a
|
||||
better understanding of what this means, try and drag the panels in the example below to the locked groups.
|
||||
|
||||
<MultiFrameworkContainer
|
||||
sandboxId="lockedgroup-dockview"
|
||||
react={DockviewLockedGroup}
|
||||
/>
|
||||
<CodeRunner id="dockview/locked"/>
|
||||
|
@ -3,7 +3,6 @@ title: Maximized Groups
|
||||
---
|
||||
|
||||
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||
import LiveExample from '@site/src/components/ui/exampleFrame';
|
||||
|
||||
This section described how to maxmimize groups.
|
||||
|
||||
@ -51,7 +50,7 @@ The methods exist on the panel `api` object for convenience.
|
||||
|
||||
## Live Examples
|
||||
|
||||
<LiveExample framework="react" id="dockview/maximize-group"/>
|
||||
<CodeRunner id="dockview/maximize-group"/>
|
||||
|
||||
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
title: Popout Windows
|
||||
---
|
||||
|
||||
import LiveExample from '@site/src/components/ui/exampleFrame';
|
||||
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||
|
||||
This section describes have to create popout windows.
|
||||
@ -57,4 +56,4 @@ in it's original location within the grid. If the dock cannot determine the orig
|
||||
choose a new location.
|
||||
|
||||
|
||||
<LiveExample framework="react" id="dockview/popout-group"/>
|
||||
<CodeRunner id="dockview/popout-group"/>
|
||||
|
@ -2,7 +2,6 @@
|
||||
title: Resizing
|
||||
---
|
||||
|
||||
import LiveExample from '@site/src/components/ui/exampleFrame';
|
||||
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||
|
||||
<DocRef declaration="DockviewGroupPanelApi" methods={['height', 'width', 'setSize', 'onDidDimensionsChange']} />
|
||||
@ -34,4 +33,4 @@ props.api.group.api.setSize({
|
||||
You can see an example invoking both approaches below.
|
||||
|
||||
|
||||
<LiveExample framework="react" id="dockview/resize"/>
|
||||
<CodeRunner framework="react" id="dockview/resize"/>
|
||||
|
@ -5,7 +5,6 @@ title: Locked
|
||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||
|
||||
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||
import LiveExample from '@site/src/components/ui/exampleFrame';
|
||||
|
||||
This section describes how to lock the dock to prevent movement.
|
||||
|
||||
@ -13,4 +12,4 @@ This section describes how to lock the dock to prevent movement.
|
||||
You may want to combine this with `disableDnd={true}` to provide a locked grid with no dnd funtionality. See [Disable Dnd](/docs/core/dnd/disable) for more.
|
||||
:::
|
||||
|
||||
<LiveExample framework='react' id='dockview/locked'/>
|
||||
<CodeRunner id='dockview/locked'/>
|
||||
|
@ -3,8 +3,6 @@ title: Overview
|
||||
sidebar_position: 0
|
||||
---
|
||||
|
||||
import LiveExample from '@site/src/components/ui/exampleFrame';
|
||||
|
||||
This section provided a core overview.
|
||||
|
||||
The component takes a collection of [Options](/docs/api/dockview/options) as inputs and
|
||||
@ -33,10 +31,3 @@ const component = new DockviewComponent({
|
||||
```
|
||||
</FrameworkSpecific>
|
||||
|
||||
## Container Resizing
|
||||
|
||||
The component will automatically resize to it's container.
|
||||
|
||||
<LiveExample framework="react" id="dockview/resize-container"/>
|
||||
|
||||
# Disposal Pattern
|
||||
|
@ -4,7 +4,7 @@ sidebar_position: 1
|
||||
---
|
||||
|
||||
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||
import LiveExample from '@site/src/components/ui/exampleFrame';
|
||||
import { CodeRunner } from '@site/src/components/ui/codeRunner';
|
||||
|
||||
This section describes how to add a new panel and the options you can provide.
|
||||
|
||||
@ -48,7 +48,7 @@ api.addPanel({
|
||||
api.setTitle('my_new_custom_title');
|
||||
```
|
||||
|
||||
<LiveExample framework="react" id="dockview/update-title" height={250}/>
|
||||
<CodeRunner id="dockview/update-title" height={250}/>
|
||||
|
||||
## Provide a custom Tab renderer
|
||||
|
||||
|
@ -4,11 +4,9 @@ sidebar_postiion: 5
|
||||
---
|
||||
|
||||
import { MultiFrameworkContainer } from '@site/src/components/ui/container';
|
||||
import { CodeRunner } from '@site/src/components/ui/codeRunner';
|
||||
import RenderingDockview from '@site/sandboxes/rendering-dockview/src/app';
|
||||
|
||||
import LiveExample from '@site/src/components/ui/exampleFrame';
|
||||
|
||||
|
||||
Rendering type is an important consideration when creating your application and whether your panels should be destroyed when hidden.
|
||||
|
||||
:::info
|
||||
@ -70,7 +68,7 @@ api.addPanel({
|
||||
|
||||
## Live Example
|
||||
|
||||
<LiveExample framework="react" id="dockview/render-mode"/>
|
||||
<CodeRunner id="dockview/render-mode"/>
|
||||
|
||||
|
||||
By default `DockviewReact` only adds to the DOM those panels that are visible,
|
||||
@ -130,3 +128,4 @@ Toggling the checkbox you can see that when you only render those panels which a
|
||||
sandboxId="rendering-dockview"
|
||||
react={RenderingDockview}
|
||||
/>
|
||||
|
||||
|
@ -4,7 +4,7 @@ title: Resizing
|
||||
|
||||
This section describes how to programatically resize a panel.
|
||||
|
||||
import LiveExample from '@site/src/components/ui/exampleFrame';
|
||||
import { CodeRunner } from '@site/src/components/ui/codeRunner';
|
||||
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||
|
||||
<DocRef declaration="DockviewPanelApi" methods={['height', 'width', 'setSize', 'onDidDimensionsChange']} />
|
||||
@ -37,4 +37,4 @@ props.api.group.api.setSize({
|
||||
|
||||
You can see an example invoking both approaches below.
|
||||
|
||||
<LiveExample framework="react" id="dockview/resize"/>
|
||||
<CodeRunner id="dockview/resize"/>
|
||||
|
@ -4,7 +4,7 @@ sidebar_position: 2
|
||||
---
|
||||
|
||||
import { MultiFrameworkContainer } from '@site/src/components/ui/container';
|
||||
import CustomHeadersDockview from '@site/sandboxes/customheader-dockview/src/app';
|
||||
import { CodeRunner } from '@site/src/components/ui/codeRunner';
|
||||
import DockviewNative from '@site/sandboxes/fullwidthtab-dockview/src/app';
|
||||
import { attach as attachNativeDockview } from '@site/sandboxes/javascript/fullwidthtab-dockview/src/app';
|
||||
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||
@ -99,10 +99,7 @@ As a simple example the below attaches a custom event handler for the context me
|
||||
The below example uses a custom tab renderer to reigster a popover when the user right clicked on a tab.
|
||||
This still makes use of the `DockviewDefaultTab` since it's only a minor change.
|
||||
|
||||
<MultiFrameworkContainer
|
||||
sandboxId="customheader-dockview"
|
||||
react={CustomHeadersDockview}
|
||||
/>
|
||||
<CodeRunner id="dockview/custom-header"/>
|
||||
|
||||
## Full Width Tab
|
||||
|
||||
@ -126,15 +123,7 @@ return <DockviewReactComponent singleTabMode="fullwidth" />
|
||||
typescript={attachNativeDockview}
|
||||
/>
|
||||
|
||||
import DockviewTabheight from '@site/sandboxes/tabheight-dockview/src/app';
|
||||
import { attach as attachTabHeightDockview } from '@site/sandboxes/javascript/tabheight-dockview/src/app';
|
||||
|
||||
## Tab Height
|
||||
|
||||
Tab height can be controlled through CSS.
|
||||
|
||||
<MultiFrameworkContainer
|
||||
sandboxId="tabheight-dockview"
|
||||
react={DockviewTabheight}
|
||||
typescript={attachTabHeightDockview}
|
||||
/>
|
||||
|
@ -43,4 +43,4 @@ panel.api.updateParameters({
|
||||
|
||||
## Live Example
|
||||
|
||||
<LiveExample framework="react" id="dockview/update-parameters"/>
|
||||
<CodeRunner id="dockview/update-parameters"/>
|
||||
|
@ -2,8 +2,6 @@
|
||||
title: Scrolling
|
||||
---
|
||||
|
||||
import LiveExample from '@site/src/components/ui/exampleFrame';
|
||||
|
||||
It's important to understand how to configure the scrollbar within a panel.
|
||||
|
||||
A panel will appear with a scrollbar if the the contents of your view has a fixed height.
|
||||
@ -17,4 +15,4 @@ The following example contains three views:
|
||||
- **Panel 2** (`height: 2000px`): A scrollbar does appear since a fixed height has been used.
|
||||
- **Panel 3**: `height: 100%` and a child component with `overflow: auto` which will enable scrollbars.
|
||||
|
||||
<LiveExample framework="react" id="dockview/scrollbars"/>
|
||||
<CodeRunner id="dockview/scrollbars"/>
|
||||
|
@ -2,8 +2,7 @@
|
||||
title: Loading State
|
||||
---
|
||||
|
||||
import { MultiFrameworkContainer } from '@site/src/components/ui/container';
|
||||
import LiveExample from '@site/src/components/ui/exampleFrame';
|
||||
import { CodeRunner } from '@site/src/components/ui/codeRunner';
|
||||
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||
|
||||
This section described loading a dock layout.
|
||||
@ -43,5 +42,6 @@ return <DockviewComponent onReady={onReady}/>;
|
||||
|
||||
# Live Example
|
||||
|
||||
<LiveExample framework="react" id="dockview/layout"/>
|
||||
<CodeRunner id="dockview/layout"/>
|
||||
|
||||
|
||||
|
@ -2,9 +2,7 @@
|
||||
title: Saving State
|
||||
---
|
||||
|
||||
|
||||
import { MultiFrameworkContainer } from '@site/src/components/ui/container';
|
||||
import LiveExample from '@site/src/components/ui/exampleFrame';
|
||||
import { CodeRunner } from '@site/src/components/ui/codeRunner';
|
||||
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||
|
||||
This section describes how to serialize a dockview instance.
|
||||
@ -39,5 +37,4 @@ return <DockviewComponent onReady={onReady}/>
|
||||
|
||||
# Live Example
|
||||
|
||||
<LiveExample framework="react" id="dockview/layout"/>
|
||||
|
||||
<CodeRunner id="dockview/layout"/>
|
||||
|
@ -5,7 +5,6 @@ title: Watermark
|
||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||
|
||||
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||
import LiveExample from '@site/src/components/ui/exampleFrame';
|
||||
|
||||
When there is nothing else to display.
|
||||
|
||||
@ -28,4 +27,4 @@ The following properties can be set to configure the behaviours of floating grou
|
||||
|
||||
## Live Examples
|
||||
|
||||
<LiveExample framework="react" id="dockview/watermark"/>
|
||||
<CodeRunner id="dockview/watermark"/>
|
||||
|
@ -5,6 +5,4 @@ sidebar_position: 3
|
||||
|
||||
A *tabview* can be created using a dock and preventing some default behaviours.
|
||||
|
||||
import LiveExample from '@site/src/components/ui/exampleFrame';
|
||||
|
||||
<LiveExample framework='react' id='dockview/tabview' />
|
||||
<CodeRunner id='dockview/tabview' />
|
||||
|
@ -7,7 +7,7 @@ sidebar_position: 0
|
||||
Learn how to install Dockview for a selection of frameworks.
|
||||
|
||||
<FrameworkSpecific framework='JavaScript'>
|
||||
Firstly, install the `dockvire-core` library:
|
||||
Firstly, install the `dockview-core` library:
|
||||
|
||||
```sh
|
||||
npm install dockview-core
|
||||
@ -21,3 +21,4 @@ Firstly, install the `dockview` library:
|
||||
npm install dockview
|
||||
```
|
||||
</FrameworkSpecific>
|
||||
|
||||
|
@ -5,9 +5,7 @@ description: Gridview Documentation
|
||||
import { MultiFrameworkContainer } from '@site/src/components/ui/container';
|
||||
import SimpleGridview from '@site/sandboxes/simple-gridview/src/app';
|
||||
import EditorGridview from '@site/sandboxes/editor-gridview/src/app';
|
||||
// import SimpleGridview from '@site/sandboxes/simple-gridview/src/app';
|
||||
import { EventsGridview } from '@site/src/components/gridview/events';
|
||||
// import IDEExample from '@site/sandboxes/ide-example/src/app';
|
||||
import Link from '@docusaurus/Link';
|
||||
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||
|
||||
|
@ -4,10 +4,9 @@ sidebar_position: 0
|
||||
---
|
||||
|
||||
import { MultiFrameworkContainer } from '@site/src/components/ui/container';
|
||||
import { CodeRunner } from '@site/src/components/ui/codeRunner';
|
||||
|
||||
import SimpleDockview from '@site/sandboxes/simple-dockview/src/app';
|
||||
import DockviewExampleApp from '@site/sandboxes/example-app-dockview/src/app';
|
||||
import { attach as attachSimpleDockview } from '@site/sandboxes/javascript/simple-dockview/src/app';
|
||||
|
||||
|
||||
<MultiFrameworkContainer
|
||||
@ -20,11 +19,7 @@ import { attach as attachSimpleDockview } from '@site/sandboxes/javascript/simpl
|
||||
|
||||
Dockview is an abstraction built on top of [Gridviews](./gridview) where each view is a container of many tabbed panels.
|
||||
|
||||
<MultiFrameworkContainer
|
||||
sandboxId="simple-dockview"
|
||||
react={SimpleDockview}
|
||||
typescript={attachSimpleDockview}
|
||||
/>
|
||||
<CodeRunner id="dockview/basic"/>
|
||||
|
||||
<br />
|
||||
|
||||
@ -60,19 +55,3 @@ const MyComponent = (props: IDockviewPanelProps<{ title: string }>) => {
|
||||
return <div>{`My first panel has the title: ${props.params.title}`}</div>;
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user