mirror of
https://github.com/mathuo/dockview
synced 2025-02-15 12:55:44 +00:00
Merge pull request #174 from mathuo/172-zero-dependency-vanilla-js
refactor: expose a vanillajs export
This commit is contained in:
commit
a43ee59bc2
@ -13,8 +13,8 @@
|
|||||||
"test": "jest",
|
"test": "jest",
|
||||||
"lint": "eslint packages/**/src/** --ext .ts,.tsx,.js,.jsx",
|
"lint": "eslint packages/**/src/** --ext .ts,.tsx,.js,.jsx",
|
||||||
"package": "node scripts/package.js",
|
"package": "node scripts/package.js",
|
||||||
"package-all": "lerna run docs --scope dockview && node scripts/package.js",
|
"package-all": "lerna run docs --scope '{dockview-core,dockview}' && node scripts/package.js",
|
||||||
"build": "lerna run build --scope dockview",
|
"build": "lerna run build --scope '{dockview-core,dockview}'",
|
||||||
"clean": "lerna run clean",
|
"clean": "lerna run clean",
|
||||||
"bootstrap": "lerna bootstrap",
|
"bootstrap": "lerna bootstrap",
|
||||||
"test:cov": "jest --coverage",
|
"test:cov": "jest --coverage",
|
||||||
|
52
packages/dockview-core/README.md
Normal file
52
packages/dockview-core/README.md
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<div align="center">
|
||||||
|
<h1>dockview</h1>
|
||||||
|
|
||||||
|
<p>Zero dependency layout manager supporting tabs, 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)
|
||||||
|
[![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
|
||||||
|
|
||||||
|
Want to inspect the latest deployment? Go to https://unpkg.com/browse/dockview@latest/
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Simple splitviews, nested splitviews (i.e. gridviews) supporting full layout managment with
|
||||||
|
dockable and tabular views
|
||||||
|
- Extensive API support at the component level and view level
|
||||||
|
- Themable and customizable
|
||||||
|
- Serialization / deserialization support
|
||||||
|
- Tabular docking and Drag and Drop support
|
||||||
|
- Documentation and examples
|
||||||
|
|
||||||
|
This project was inspired by many popular IDE editors. Some parts of the core resizable panelling are inspired by code found in the VSCode codebase, [splitview](https://github.com/microsoft/vscode/tree/main/src/vs/base/browser/ui/splitview) and [gridview](https://github.com/microsoft/vscode/tree/main/src/vs/base/browser/ui/grid).
|
||||||
|
|
||||||
|
## 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). Please see the [Getting Started Guide](https://mathuo.github.io/dockview/docs/).
|
||||||
|
|
||||||
|
```
|
||||||
|
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-core/gulpfile.js
Normal file
6
packages/dockview-core/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']));
|
27
packages/dockview-core/jest.config.js
Normal file
27
packages/dockview-core/jest.config.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
const { name } = require('./package');
|
||||||
|
|
||||||
|
const baseConfig = require('../../jest.config.base');
|
||||||
|
|
||||||
|
console.log('loaded');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
...baseConfig,
|
||||||
|
roots: ['<rootDir>/packages/dockview-core'],
|
||||||
|
modulePaths: ['<rootDir>/packages/dockview-core/src'],
|
||||||
|
displayName: { name, color: 'blue' },
|
||||||
|
rootDir: '../../',
|
||||||
|
collectCoverageFrom: [
|
||||||
|
'<rootDir>/packages/dockview-core/src/**/*.{js,jsx,ts,tsx}',
|
||||||
|
],
|
||||||
|
setupFiles: [
|
||||||
|
'<rootDir>/packages/dockview-core/src/__tests__/__mocks__/resizeObserver.js',
|
||||||
|
],
|
||||||
|
coveragePathIgnorePatterns: ['/node_modules/'],
|
||||||
|
modulePathIgnorePatterns: [
|
||||||
|
'<rootDir>/packages/dockview-core/src/__tests__/__mocks__',
|
||||||
|
'<rootDir>/packages/dockview-core/src/__tests__/__test_utils__',
|
||||||
|
],
|
||||||
|
coverageDirectory: '<rootDir>/packages/dockview-core/coverage/',
|
||||||
|
testResultsProcessor: 'jest-sonar-reporter',
|
||||||
|
testEnvironment: 'jsdom',
|
||||||
|
};
|
68
packages/dockview-core/package.json
Normal file
68
packages/dockview-core/package.json
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
{
|
||||||
|
"name": "dockview-core",
|
||||||
|
"version": "1.6.0",
|
||||||
|
"description": "Zero dependency layout manager supporting tabs, grids and splitviews with ReactJS support",
|
||||||
|
"main": "./dist/cjs/index.js",
|
||||||
|
"types": "./dist/cjs/index.d.ts",
|
||||||
|
"module": "./dist/esm/index.js",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/mathuo/dockview.git"
|
||||||
|
},
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/mathuo/dockview/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/mathuo/dockview",
|
||||||
|
"scripts": {
|
||||||
|
"build:ci": "npm run build:cjs && npm run build:esm && npm run build:css",
|
||||||
|
"build:cjs": "cross-env ../../node_modules/.bin/tsc --project ./tsconfig.json --extendedDiagnostics",
|
||||||
|
"build:css": "gulp sass",
|
||||||
|
"build:esm": "cross-env ../../node_modules/.bin/tsc --project ./tsconfig.esm.json --extendedDiagnostics",
|
||||||
|
"build:modulefiles": "rollup -c",
|
||||||
|
"build": "npm run build:ci && npm run build:modulefiles",
|
||||||
|
"clean": "rimraf dist/ .build/",
|
||||||
|
"docs": "typedoc",
|
||||||
|
"prepack": "npm run rebuild && npm run test",
|
||||||
|
"rebuild": "npm run clean && npm run build",
|
||||||
|
"test": "cross-env ../../node_modules/.bin/jest --selectProjects dockview-core",
|
||||||
|
"test:cov": "cross-env ../../node_modules/.bin/jest --selectProjects dockview-core --coverage",
|
||||||
|
"dev-publish": "node ./scripts/publishExperimental.js"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"dist",
|
||||||
|
"README.md"
|
||||||
|
],
|
||||||
|
"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"
|
||||||
|
],
|
||||||
|
"author": "https://github.com/mathuo",
|
||||||
|
"license": "MIT",
|
||||||
|
"devDependencies": {
|
||||||
|
"@rollup/plugin-typescript": "^11.0.0",
|
||||||
|
"cross-env": "^7.0.3",
|
||||||
|
"postcss": "^8.4.21",
|
||||||
|
"rimraf": "^4.1.2",
|
||||||
|
"rollup": "^3.15.0",
|
||||||
|
"rollup-plugin-postcss": "^4.0.2",
|
||||||
|
"rollup-plugin-terser": "^7.0.2",
|
||||||
|
"typedoc": "^0.23.25"
|
||||||
|
}
|
||||||
|
}
|
105
packages/dockview-core/rollup.config.js
Normal file
105
packages/dockview-core/rollup.config.js
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
/* 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 { 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, isReact } = options;
|
||||||
|
const input = getInput(options);
|
||||||
|
const file = outputFile(format, isMinified, withStyles, isReact);
|
||||||
|
|
||||||
|
const external = [];
|
||||||
|
|
||||||
|
const output = {
|
||||||
|
file,
|
||||||
|
format,
|
||||||
|
globals: {},
|
||||||
|
banner: [
|
||||||
|
`/**`,
|
||||||
|
` * ${name}`,
|
||||||
|
` * @version ${version}`,
|
||||||
|
` * @link ${homepage}`,
|
||||||
|
` * @license ${license}`,
|
||||||
|
` */`,
|
||||||
|
].join('\n'),
|
||||||
|
};
|
||||||
|
|
||||||
|
const plugins = [
|
||||||
|
typescript({
|
||||||
|
tsconfig: 'tsconfig.esm.json',
|
||||||
|
incremental: false,
|
||||||
|
tsBuildInfoFile: undefined,
|
||||||
|
outDir: undefined,
|
||||||
|
declaration: false,
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
|
if (isMinified) {
|
||||||
|
plugins.push(terser());
|
||||||
|
}
|
||||||
|
if (withStyles) {
|
||||||
|
plugins.push(postcss());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (format === 'umd') {
|
||||||
|
output['name'] = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 }),
|
||||||
|
];
|
63
packages/dockview-core/scripts/publishExperimental.js
Normal file
63
packages/dockview-core/scripts/publishExperimental.js
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
const cp = require('child_process');
|
||||||
|
const fs = require('fs-extra');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const rootDir = path.join(__dirname, '..');
|
||||||
|
const publishDir = path.join(rootDir, '__publish__');
|
||||||
|
|
||||||
|
cp.execSync('npm run clean', { cwd: rootDir, stdio: 'inherit' });
|
||||||
|
cp.execSync('npm run test', { cwd: __dirname, stdio: 'inherit' });
|
||||||
|
cp.execSync('npm run build', { cwd: rootDir, stdio: 'inherit' });
|
||||||
|
|
||||||
|
if (fs.existsSync(publishDir)) {
|
||||||
|
fs.removeSync(publishDir);
|
||||||
|
}
|
||||||
|
fs.mkdirSync(publishDir);
|
||||||
|
|
||||||
|
if (!fs.existsSync(path.join(publishDir, 'dist'))) {
|
||||||
|
fs.mkdirSync(path.join(publishDir, 'dist'));
|
||||||
|
}
|
||||||
|
|
||||||
|
const package = JSON.parse(
|
||||||
|
fs.readFileSync(path.join(rootDir, 'package.json')).toString()
|
||||||
|
);
|
||||||
|
|
||||||
|
for (const file of package.files) {
|
||||||
|
fs.copySync(path.join(rootDir, file), path.join(publishDir, file));
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = cp
|
||||||
|
.execSync('git rev-parse --short HEAD', {
|
||||||
|
cwd: rootDir,
|
||||||
|
})
|
||||||
|
.toString()
|
||||||
|
.replace(/\n/g, '');
|
||||||
|
|
||||||
|
function formatDate() {
|
||||||
|
const date = new Date();
|
||||||
|
|
||||||
|
function pad(value) {
|
||||||
|
if (value.toString().length === 1) {
|
||||||
|
return `0${value}`;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${date.getFullYear()}${pad(date.getMonth() + 1)}${pad(
|
||||||
|
date.getDate()
|
||||||
|
)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
package.version = `0.0.0-experimental-${result}-${formatDate()}`;
|
||||||
|
package.scripts = {};
|
||||||
|
|
||||||
|
fs.writeFileSync(
|
||||||
|
path.join(publishDir, 'package.json'),
|
||||||
|
JSON.stringify(package, null, 4)
|
||||||
|
);
|
||||||
|
|
||||||
|
const command = 'npm publish --tag experimental';
|
||||||
|
|
||||||
|
cp.execSync(command, { cwd: publishDir, stdio: 'inherit' });
|
||||||
|
|
||||||
|
fs.removeSync(publishDir);
|
2
packages/dockview-core/scripts/rollupEntryTarget.ts
Normal file
2
packages/dockview-core/scripts/rollupEntryTarget.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
import '../dist/styles/dockview.css';
|
||||||
|
export * from '../src/index';
|
@ -0,0 +1,13 @@
|
|||||||
|
class ResizeObserver {
|
||||||
|
observe() {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
unobserve() {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
disconnect() {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.ResizeObserver = ResizeObserver;
|
14
packages/dockview-core/src/__tests__/__test_utils__/utils.ts
Normal file
14
packages/dockview-core/src/__tests__/__test_utils__/utils.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
|
export function setMockRefElement(node: Partial<HTMLElement>): void {
|
||||||
|
const mockRef = {
|
||||||
|
get current() {
|
||||||
|
return node;
|
||||||
|
},
|
||||||
|
set current(_value) {
|
||||||
|
//noop
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
jest.spyOn(React, 'useRef').mockReturnValueOnce(mockRef);
|
||||||
|
}
|
@ -6,7 +6,6 @@ import {
|
|||||||
} from '../../groupview/types';
|
} from '../../groupview/types';
|
||||||
import { PanelUpdateEvent } from '../../panel/types';
|
import { PanelUpdateEvent } from '../../panel/types';
|
||||||
import { Orientation } from '../../splitview/core/splitview';
|
import { Orientation } from '../../splitview/core/splitview';
|
||||||
import { ReactPanelDeserialzier } from '../../react/deserializer';
|
|
||||||
import { GroupPanel } from '../../groupview/groupviewPanel';
|
import { GroupPanel } from '../../groupview/groupviewPanel';
|
||||||
import { CompositeDisposable } from '../../lifecycle';
|
import { CompositeDisposable } from '../../lifecycle';
|
||||||
import {
|
import {
|
||||||
@ -22,6 +21,7 @@ import {
|
|||||||
DockviewPanelApi,
|
DockviewPanelApi,
|
||||||
DockviewPanelApiImpl,
|
DockviewPanelApiImpl,
|
||||||
} from '../../api/dockviewPanelApi';
|
} from '../../api/dockviewPanelApi';
|
||||||
|
import { DefaultDockviewDeserialzier } from '../../dockview/deserializer';
|
||||||
|
|
||||||
class PanelContentPartTest implements IContentRenderer {
|
class PanelContentPartTest implements IContentRenderer {
|
||||||
element: HTMLElement = document.createElement('div');
|
element: HTMLElement = document.createElement('div');
|
||||||
@ -512,7 +512,7 @@ describe('dockviewComponent', () => {
|
|||||||
test('serialization', () => {
|
test('serialization', () => {
|
||||||
dockview.layout(1000, 1000);
|
dockview.layout(1000, 1000);
|
||||||
|
|
||||||
dockview.deserializer = new ReactPanelDeserialzier(dockview);
|
dockview.deserializer = new DefaultDockviewDeserialzier(dockview);
|
||||||
dockview.fromJSON({
|
dockview.fromJSON({
|
||||||
activeGroup: 'group-1',
|
activeGroup: 'group-1',
|
||||||
grid: {
|
grid: {
|
||||||
@ -1038,7 +1038,7 @@ describe('dockviewComponent', () => {
|
|||||||
fromJSON: (panelData: GroupviewPanelState): IDockviewPanel => {
|
fromJSON: (panelData: GroupviewPanelState): IDockviewPanel => {
|
||||||
return new TestGroupPanel(
|
return new TestGroupPanel(
|
||||||
panelData.id,
|
panelData.id,
|
||||||
panelData.title,
|
panelData.title || '',
|
||||||
dockview
|
dockview
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -1427,7 +1427,7 @@ describe('dockviewComponent', () => {
|
|||||||
default: PanelContentPartTest,
|
default: PanelContentPartTest,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
dockview.deserializer = new ReactPanelDeserialzier(dockview);
|
dockview.deserializer = new DefaultDockviewDeserialzier(dockview);
|
||||||
|
|
||||||
dockview.layout(500, 1000);
|
dockview.layout(500, 1000);
|
||||||
|
|
||||||
@ -1552,7 +1552,7 @@ describe('dockviewComponent', () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
dockview.deserializer = new ReactPanelDeserialzier(dockview);
|
dockview.deserializer = new DefaultDockviewDeserialzier(dockview);
|
||||||
dockview.fromJSON({
|
dockview.fromJSON({
|
||||||
activeGroup: 'group-1',
|
activeGroup: 'group-1',
|
||||||
grid: {
|
grid: {
|
||||||
@ -1686,7 +1686,7 @@ describe('dockviewComponent', () => {
|
|||||||
default: PanelContentPartTest,
|
default: PanelContentPartTest,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
dockview.deserializer = new ReactPanelDeserialzier(dockview);
|
dockview.deserializer = new DefaultDockviewDeserialzier(dockview);
|
||||||
dockview.fromJSON({
|
dockview.fromJSON({
|
||||||
activeGroup: 'group-1',
|
activeGroup: 'group-1',
|
||||||
grid: {
|
grid: {
|
||||||
@ -1778,7 +1778,7 @@ describe('dockviewComponent', () => {
|
|||||||
test_tab_id: PanelTabPartTest,
|
test_tab_id: PanelTabPartTest,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
dockview.deserializer = new ReactPanelDeserialzier(dockview);
|
dockview.deserializer = new DefaultDockviewDeserialzier(dockview);
|
||||||
dockview.fromJSON({
|
dockview.fromJSON({
|
||||||
activeGroup: 'group-1',
|
activeGroup: 'group-1',
|
||||||
grid: {
|
grid: {
|
||||||
@ -1890,7 +1890,7 @@ describe('dockviewComponent', () => {
|
|||||||
test_tab_id: PanelTabPartTest,
|
test_tab_id: PanelTabPartTest,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
dockview.deserializer = new ReactPanelDeserialzier(dockview);
|
dockview.deserializer = new DefaultDockviewDeserialzier(dockview);
|
||||||
dockview.fromJSON({
|
dockview.fromJSON({
|
||||||
activeGroup: 'group-1',
|
activeGroup: 'group-1',
|
||||||
grid: {
|
grid: {
|
||||||
@ -1980,7 +1980,7 @@ describe('dockviewComponent', () => {
|
|||||||
},
|
},
|
||||||
orientation: Orientation.HORIZONTAL,
|
orientation: Orientation.HORIZONTAL,
|
||||||
});
|
});
|
||||||
dockview.deserializer = new ReactPanelDeserialzier(dockview);
|
dockview.deserializer = new DefaultDockviewDeserialzier(dockview);
|
||||||
|
|
||||||
expect(dockview.orientation).toBe(Orientation.HORIZONTAL);
|
expect(dockview.orientation).toBe(Orientation.HORIZONTAL);
|
||||||
|
|
||||||
@ -2086,7 +2086,7 @@ describe('dockviewComponent', () => {
|
|||||||
},
|
},
|
||||||
orientation: Orientation.HORIZONTAL,
|
orientation: Orientation.HORIZONTAL,
|
||||||
});
|
});
|
||||||
dockview.deserializer = new ReactPanelDeserialzier(dockview);
|
dockview.deserializer = new DefaultDockviewDeserialzier(dockview);
|
||||||
|
|
||||||
expect(dockview.orientation).toBe(Orientation.HORIZONTAL);
|
expect(dockview.orientation).toBe(Orientation.HORIZONTAL);
|
||||||
|
|
||||||
@ -2227,7 +2227,7 @@ describe('dockviewComponent', () => {
|
|||||||
},
|
},
|
||||||
orientation: Orientation.HORIZONTAL,
|
orientation: Orientation.HORIZONTAL,
|
||||||
});
|
});
|
||||||
dockview.deserializer = new ReactPanelDeserialzier(dockview);
|
dockview.deserializer = new DefaultDockviewDeserialzier(dockview);
|
||||||
|
|
||||||
expect(dockview.orientation).toBe(Orientation.HORIZONTAL);
|
expect(dockview.orientation).toBe(Orientation.HORIZONTAL);
|
||||||
|
|
||||||
@ -2355,7 +2355,7 @@ describe('dockviewComponent', () => {
|
|||||||
},
|
},
|
||||||
orientation: Orientation.HORIZONTAL,
|
orientation: Orientation.HORIZONTAL,
|
||||||
});
|
});
|
||||||
dockview.deserializer = new ReactPanelDeserialzier(dockview);
|
dockview.deserializer = new DefaultDockviewDeserialzier(dockview);
|
||||||
|
|
||||||
expect(dockview.groups.length).toBe(0);
|
expect(dockview.groups.length).toBe(0);
|
||||||
});
|
});
|
||||||
@ -2372,7 +2372,7 @@ describe('dockviewComponent', () => {
|
|||||||
},
|
},
|
||||||
orientation: Orientation.HORIZONTAL,
|
orientation: Orientation.HORIZONTAL,
|
||||||
});
|
});
|
||||||
dockview.deserializer = new ReactPanelDeserialzier(dockview);
|
dockview.deserializer = new DefaultDockviewDeserialzier(dockview);
|
||||||
|
|
||||||
expect(dockview.groups.length).toBe(0);
|
expect(dockview.groups.length).toBe(0);
|
||||||
|
|
||||||
@ -2412,7 +2412,7 @@ describe('dockviewComponent', () => {
|
|||||||
},
|
},
|
||||||
orientation: Orientation.HORIZONTAL,
|
orientation: Orientation.HORIZONTAL,
|
||||||
});
|
});
|
||||||
dockview.deserializer = new ReactPanelDeserialzier(dockview);
|
dockview.deserializer = new DefaultDockviewDeserialzier(dockview);
|
||||||
|
|
||||||
expect(JSON.parse(JSON.stringify(dockview.toJSON()))).toEqual({
|
expect(JSON.parse(JSON.stringify(dockview.toJSON()))).toEqual({
|
||||||
grid: {
|
grid: {
|
@ -1,4 +1,3 @@
|
|||||||
import { GridviewPanelApiImpl } from '../../api/gridviewPanelApi';
|
|
||||||
import { GridviewComponent } from '../../gridview/gridviewComponent';
|
import { GridviewComponent } from '../../gridview/gridviewComponent';
|
||||||
import { GridviewPanel } from '../../gridview/gridviewPanel';
|
import { GridviewPanel } from '../../gridview/gridviewPanel';
|
||||||
import { CompositeDisposable } from '../../lifecycle';
|
import { CompositeDisposable } from '../../lifecycle';
|
||||||
@ -7,7 +6,7 @@ import { Orientation } from '../../splitview/core/splitview';
|
|||||||
|
|
||||||
class TestGridview extends GridviewPanel {
|
class TestGridview extends GridviewPanel {
|
||||||
constructor(id: string, componentName: string) {
|
constructor(id: string, componentName: string) {
|
||||||
super(id, componentName, new GridviewPanelApiImpl(id));
|
super(id, componentName);
|
||||||
|
|
||||||
this.api.initialize(this);
|
this.api.initialize(this);
|
||||||
|
|
@ -32,8 +32,8 @@ import { IView, Orientation, Sizing } from '../splitview/core/splitview';
|
|||||||
import { ISplitviewPanel } from '../splitview/splitviewPanel';
|
import { ISplitviewPanel } from '../splitview/splitviewPanel';
|
||||||
import { GroupPanel, IGroupviewPanel } from '../groupview/groupviewPanel';
|
import { GroupPanel, IGroupviewPanel } from '../groupview/groupviewPanel';
|
||||||
import { Emitter, Event } from '../events';
|
import { Emitter, Event } from '../events';
|
||||||
import { PaneviewDropEvent } from '../react';
|
|
||||||
import { IDockviewPanel } from '../dockview/dockviewPanel';
|
import { IDockviewPanel } from '../dockview/dockviewPanel';
|
||||||
|
import { PaneviewDropEvent } from '../paneview/draggablePaneviewPanel';
|
||||||
|
|
||||||
export interface CommonApi<T = any> {
|
export interface CommonApi<T = any> {
|
||||||
readonly height: number;
|
readonly height: number;
|
@ -3,10 +3,10 @@ import {
|
|||||||
GroupPanelPartInitParameters,
|
GroupPanelPartInitParameters,
|
||||||
IContentRenderer,
|
IContentRenderer,
|
||||||
ITabRenderer,
|
ITabRenderer,
|
||||||
|
GroupPanelUpdateEvent,
|
||||||
} from '../groupview/types';
|
} from '../groupview/types';
|
||||||
import { GroupPanel } from '../groupview/groupviewPanel';
|
import { GroupPanel } from '../groupview/groupviewPanel';
|
||||||
import { IDisposable } from '../lifecycle';
|
import { IDisposable } from '../lifecycle';
|
||||||
import { GroupPanelUpdateEvent } from '../groupview/types';
|
|
||||||
|
|
||||||
export interface IGroupPanelView extends IDisposable {
|
export interface IGroupPanelView extends IDisposable {
|
||||||
readonly content: IContentRenderer;
|
readonly content: IContentRenderer;
|
@ -1,15 +1,17 @@
|
|||||||
import { DockviewComponent } from '../dockview/dockviewComponent';
|
import { GroupviewPanelState, ITabRenderer } from '../groupview/types';
|
||||||
import { GroupviewPanelState } from '../groupview/types';
|
|
||||||
import { DockviewPanel, IDockviewPanel } from '../dockview/dockviewPanel';
|
|
||||||
import { IPanelDeserializer } from '../dockview/deserializer';
|
|
||||||
import { createComponent } from '../panel/componentFactory';
|
|
||||||
import { DockviewApi } from '../api/component.api';
|
|
||||||
import { DefaultTab } from '../dockview/components/tab/defaultTab';
|
|
||||||
import { DefaultGroupPanelView } from '../dockview/defaultGroupPanelView';
|
|
||||||
import { GroupPanel } from '../groupview/groupviewPanel';
|
import { GroupPanel } from '../groupview/groupviewPanel';
|
||||||
import { ITabRenderer } from '../groupview/types';
|
import { DockviewPanel, IDockviewPanel } from './dockviewPanel';
|
||||||
|
import { DockviewComponent } from './dockviewComponent';
|
||||||
|
import { createComponent } from '../panel/componentFactory';
|
||||||
|
import { DefaultTab } from './components/tab/defaultTab';
|
||||||
|
import { DefaultGroupPanelView } from './defaultGroupPanelView';
|
||||||
|
import { DockviewApi } from '../api/component.api';
|
||||||
|
|
||||||
export class ReactPanelDeserialzier implements IPanelDeserializer {
|
export interface IPanelDeserializer {
|
||||||
|
fromJSON(panelData: GroupviewPanelState, group: GroupPanel): IDockviewPanel;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DefaultDockviewDeserialzier implements IPanelDeserializer {
|
||||||
constructor(private readonly layout: DockviewComponent) {}
|
constructor(private readonly layout: DockviewComponent) {}
|
||||||
|
|
||||||
public fromJSON(
|
public fromJSON(
|
@ -6,7 +6,6 @@ import {
|
|||||||
} from '../gridview/gridview';
|
} from '../gridview/gridview';
|
||||||
import { directionToPosition, Droptarget, Position } from '../dnd/droptarget';
|
import { directionToPosition, Droptarget, Position } from '../dnd/droptarget';
|
||||||
import { tail, sequenceEquals } from '../array';
|
import { tail, sequenceEquals } from '../array';
|
||||||
import { GroupviewPanelState } from '../groupview/types';
|
|
||||||
import { DockviewPanel, IDockviewPanel } from './dockviewPanel';
|
import { DockviewPanel, IDockviewPanel } from './dockviewPanel';
|
||||||
import { CompositeDisposable } from '../lifecycle';
|
import { CompositeDisposable } from '../lifecycle';
|
||||||
import { Event, Emitter } from '../events';
|
import { Event, Emitter } from '../events';
|
||||||
@ -15,6 +14,7 @@ import {
|
|||||||
IContentRenderer,
|
IContentRenderer,
|
||||||
ITabRenderer,
|
ITabRenderer,
|
||||||
IWatermarkRenderer,
|
IWatermarkRenderer,
|
||||||
|
GroupviewPanelState,
|
||||||
} from '../groupview/types';
|
} from '../groupview/types';
|
||||||
import { sequentialNumberGenerator } from '../math';
|
import { sequentialNumberGenerator } from '../math';
|
||||||
import { IPanelDeserializer } from './deserializer';
|
import { IPanelDeserializer } from './deserializer';
|
@ -7,15 +7,20 @@ import {
|
|||||||
WatermarkConstructor,
|
WatermarkConstructor,
|
||||||
IWatermarkRenderer,
|
IWatermarkRenderer,
|
||||||
} from '../groupview/types';
|
} from '../groupview/types';
|
||||||
import { GroupPanel } from '../groupview/groupviewPanel';
|
import { GroupPanel, GroupviewPanelApi } from '../groupview/groupviewPanel';
|
||||||
import { ISplitviewStyles, Orientation } from '../splitview/core/splitview';
|
import { ISplitviewStyles, Orientation } from '../splitview/core/splitview';
|
||||||
import { FrameworkFactory } from '../types';
|
import { FrameworkFactory } from '../types';
|
||||||
import { DockviewDropTargets } from '../groupview/dnd';
|
import { DockviewDropTargets } from '../groupview/dnd';
|
||||||
import { PanelTransfer } from '../dnd/dataTransfer';
|
import { PanelTransfer } from '../dnd/dataTransfer';
|
||||||
import { IGroupControlRenderer } from '../react/dockview/groupControlsRenderer';
|
import { IDisposable } from '../lifecycle';
|
||||||
import { Position } from '../dnd/droptarget';
|
import { Position } from '../dnd/droptarget';
|
||||||
import { IDockviewPanel } from './dockviewPanel';
|
import { IDockviewPanel } from './dockviewPanel';
|
||||||
|
|
||||||
|
export interface IGroupControlRenderer extends IDisposable {
|
||||||
|
readonly element: HTMLElement;
|
||||||
|
init(params: { containerApi: DockviewApi; api: GroupviewPanelApi }): void;
|
||||||
|
}
|
||||||
|
|
||||||
export interface GroupPanelFrameworkComponentFactory {
|
export interface GroupPanelFrameworkComponentFactory {
|
||||||
content: FrameworkFactory<IContentRenderer>;
|
content: FrameworkFactory<IContentRenderer>;
|
||||||
tab: FrameworkFactory<ITabRenderer>;
|
tab: FrameworkFactory<ITabRenderer>;
|
@ -126,8 +126,8 @@ export abstract class GridviewPanel
|
|||||||
return this.api.isActive;
|
return this.api.isActive;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(id: string, component: string, api: GridviewPanelApiImpl) {
|
constructor(id: string, component: string) {
|
||||||
super(id, component, api);
|
super(id, component, new GridviewPanelApiImpl(id));
|
||||||
|
|
||||||
this.api.initialize(this); // TODO: required to by-pass 'super before this' requirement
|
this.api.initialize(this); // TODO: required to by-pass 'super before this' requirement
|
||||||
|
|
@ -13,8 +13,8 @@ import { ITabsContainer, TabsContainer } from './titlebar/tabsContainer';
|
|||||||
import { IWatermarkRenderer } from './types';
|
import { IWatermarkRenderer } from './types';
|
||||||
import { GroupPanel } from './groupviewPanel';
|
import { GroupPanel } from './groupviewPanel';
|
||||||
import { DockviewDropTargets } from './dnd';
|
import { DockviewDropTargets } from './dnd';
|
||||||
import { IGroupControlRenderer } from '../react/dockview/groupControlsRenderer';
|
|
||||||
import { IDockviewPanel } from '../dockview/dockviewPanel';
|
import { IDockviewPanel } from '../dockview/dockviewPanel';
|
||||||
|
import { IGroupControlRenderer } from '../dockview/options';
|
||||||
|
|
||||||
export interface DndService {
|
export interface DndService {
|
||||||
canDisplayOverlay(
|
canDisplayOverlay(
|
@ -74,7 +74,7 @@ export class GroupPanel extends GridviewPanel implements IGroupviewPanel {
|
|||||||
id: string,
|
id: string,
|
||||||
options: GroupOptions
|
options: GroupOptions
|
||||||
) {
|
) {
|
||||||
super(id, 'groupview_default', new GroupviewApi(id));
|
super(id, 'groupview_default');
|
||||||
|
|
||||||
this._model = new Groupview(this.element, accessor, id, options, this);
|
this._model = new Groupview(this.element, accessor, id, options, this);
|
||||||
}
|
}
|
@ -53,6 +53,7 @@ export interface IContentRenderer extends IPanel {
|
|||||||
readonly onDidBlur?: Event<void>;
|
readonly onDidBlur?: Event<void>;
|
||||||
updateParentGroup(group: GroupPanel, isPanelVisible: boolean): void;
|
updateParentGroup(group: GroupPanel, isPanelVisible: boolean): void;
|
||||||
init(parameters: GroupPanelContentPartInitParameters): void;
|
init(parameters: GroupPanelContentPartInitParameters): void;
|
||||||
|
layout(width: number, height: number): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
// watermark component
|
// watermark component
|
84
packages/dockview-core/src/index.ts
Normal file
84
packages/dockview-core/src/index.ts
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
export * from './hostedContainer';
|
||||||
|
|
||||||
|
export * from './dnd/dataTransfer';
|
||||||
|
|
||||||
|
export { watchElementResize } from './dom';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Events, Emitters and Disposables are very common concepts that most codebases will contain.
|
||||||
|
* We export them with a 'Dockview' prefix here to prevent accidental use by others.
|
||||||
|
*/
|
||||||
|
export { Emitter as DockviewEmitter, Event as DockviewEvent } from './events';
|
||||||
|
export {
|
||||||
|
IDisposable as IDockviewDisposable,
|
||||||
|
MutableDisposable as DockviewMutableDisposable,
|
||||||
|
CompositeDisposable as DockviewCompositeDisposable,
|
||||||
|
} from './lifecycle';
|
||||||
|
|
||||||
|
export * from './panel/types';
|
||||||
|
export * from './panel/componentFactory';
|
||||||
|
|
||||||
|
export * from './splitview/core/splitview';
|
||||||
|
export * from './splitview/core/options';
|
||||||
|
|
||||||
|
export * from './paneview/paneview';
|
||||||
|
export * from './gridview/gridview';
|
||||||
|
export * from './groupview/groupview';
|
||||||
|
export * from './gridview/baseComponentGridview';
|
||||||
|
|
||||||
|
export * from './paneview/draggablePaneviewPanel';
|
||||||
|
|
||||||
|
export * from './groupview/panel/content';
|
||||||
|
export * from './groupview/tab';
|
||||||
|
export * from './groupview/dnd';
|
||||||
|
export * from './groupview/types';
|
||||||
|
export * from './groupview/groupviewPanel';
|
||||||
|
|
||||||
|
export * from './dockview/options';
|
||||||
|
export * from './dockview/dockviewPanel';
|
||||||
|
export * from './dockview/components/tab/defaultTab';
|
||||||
|
export * from './dockview/deserializer';
|
||||||
|
|
||||||
|
export * from './dockview/dockviewComponent';
|
||||||
|
export * from './gridview/gridviewComponent';
|
||||||
|
export * from './splitview/splitviewComponent';
|
||||||
|
export * from './paneview/paneviewComponent';
|
||||||
|
export { PaneviewComponentOptions } from './paneview/options';
|
||||||
|
|
||||||
|
export * from './gridview/gridviewPanel';
|
||||||
|
export * from './splitview/splitviewPanel';
|
||||||
|
export * from './paneview/paneviewPanel';
|
||||||
|
export * from './groupview/types';
|
||||||
|
|
||||||
|
export { Event } from './events';
|
||||||
|
export {
|
||||||
|
Position,
|
||||||
|
positionToDirection,
|
||||||
|
directionToPosition,
|
||||||
|
} from './dnd/droptarget';
|
||||||
|
export {
|
||||||
|
FocusEvent,
|
||||||
|
PanelDimensionChangeEvent,
|
||||||
|
VisibilityEvent,
|
||||||
|
ActiveEvent,
|
||||||
|
PanelApi,
|
||||||
|
} from './api/panelApi';
|
||||||
|
export {
|
||||||
|
SizeEvent,
|
||||||
|
GridviewPanelApi,
|
||||||
|
GridConstraintChangeEvent,
|
||||||
|
} from './api/gridviewPanelApi';
|
||||||
|
export { TitleEvent, DockviewPanelApi } from './api/dockviewPanelApi';
|
||||||
|
export {
|
||||||
|
PanelSizeEvent,
|
||||||
|
PanelConstraintChangeEvent,
|
||||||
|
SplitviewPanelApi,
|
||||||
|
} from './api/splitviewPanelApi';
|
||||||
|
export { ExpansionEvent, PaneviewPanelApi } from './api/paneviewPanelApi';
|
||||||
|
export {
|
||||||
|
CommonApi,
|
||||||
|
SplitviewApi,
|
||||||
|
PaneviewApi,
|
||||||
|
GridviewApi,
|
||||||
|
DockviewApi,
|
||||||
|
} from './api/component.api';
|
@ -1,3 +1,4 @@
|
|||||||
|
import { PaneviewApi } from '../api/component.api';
|
||||||
import { DragHandler } from '../dnd/abstractDragHandler';
|
import { DragHandler } from '../dnd/abstractDragHandler';
|
||||||
import {
|
import {
|
||||||
getPaneData,
|
getPaneData,
|
||||||
@ -15,16 +16,17 @@ import {
|
|||||||
PaneviewPanel,
|
PaneviewPanel,
|
||||||
} from './paneviewPanel';
|
} from './paneviewPanel';
|
||||||
|
|
||||||
export interface PaneviewDropEvent2 extends DroptargetEvent {
|
export interface PaneviewDropEvent extends DroptargetEvent {
|
||||||
panel: IPaneviewPanel;
|
panel: IPaneviewPanel;
|
||||||
getData: () => PaneTransfer | undefined;
|
getData: () => PaneTransfer | undefined;
|
||||||
|
api: PaneviewApi;
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class DraggablePaneviewPanel extends PaneviewPanel {
|
export abstract class DraggablePaneviewPanel extends PaneviewPanel {
|
||||||
private handler: DragHandler | undefined;
|
private handler: DragHandler | undefined;
|
||||||
private target: Droptarget | undefined;
|
private target: Droptarget | undefined;
|
||||||
|
|
||||||
private readonly _onDidDrop = new Emitter<PaneviewDropEvent2>();
|
private readonly _onDidDrop = new Emitter<PaneviewDropEvent>();
|
||||||
readonly onDidDrop = this._onDidDrop.event;
|
readonly onDidDrop = this._onDidDrop.event;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@ -117,6 +119,7 @@ export abstract class DraggablePaneviewPanel extends PaneviewPanel {
|
|||||||
this._onDidDrop.fire({
|
this._onDidDrop.fire({
|
||||||
...event,
|
...event,
|
||||||
panel: this,
|
panel: this,
|
||||||
|
api: new PaneviewApi(this.accessor),
|
||||||
getData: getPaneData,
|
getData: getPaneData,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
@ -133,6 +136,7 @@ export abstract class DraggablePaneviewPanel extends PaneviewPanel {
|
|||||||
...event,
|
...event,
|
||||||
panel: this,
|
panel: this,
|
||||||
getData: getPaneData,
|
getData: getPaneData,
|
||||||
|
api: new PaneviewApi(this.accessor),
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
@ -21,7 +21,7 @@ import {
|
|||||||
} from './paneviewPanel';
|
} from './paneviewPanel';
|
||||||
import {
|
import {
|
||||||
DraggablePaneviewPanel,
|
DraggablePaneviewPanel,
|
||||||
PaneviewDropEvent2,
|
PaneviewDropEvent,
|
||||||
} from './draggablePaneviewPanel';
|
} from './draggablePaneviewPanel';
|
||||||
import { DefaultHeader } from './defaultPaneviewHeader';
|
import { DefaultHeader } from './defaultPaneviewHeader';
|
||||||
import { sequentialNumberGenerator } from '../math';
|
import { sequentialNumberGenerator } from '../math';
|
||||||
@ -115,7 +115,7 @@ export interface IPaneviewComponent extends IDisposable {
|
|||||||
readonly options: PaneviewComponentOptions;
|
readonly options: PaneviewComponentOptions;
|
||||||
readonly onDidAddView: Event<PaneviewPanel>;
|
readonly onDidAddView: Event<PaneviewPanel>;
|
||||||
readonly onDidRemoveView: Event<PaneviewPanel>;
|
readonly onDidRemoveView: Event<PaneviewPanel>;
|
||||||
readonly onDidDrop: Event<PaneviewDropEvent2>;
|
readonly onDidDrop: Event<PaneviewDropEvent>;
|
||||||
readonly onDidLayoutChange: Event<void>;
|
readonly onDidLayoutChange: Event<void>;
|
||||||
readonly onDidLayoutFromJSON: Event<void>;
|
readonly onDidLayoutFromJSON: Event<void>;
|
||||||
addPanel(options: AddPaneviewComponentOptions): IPaneviewPanel;
|
addPanel(options: AddPaneviewComponentOptions): IPaneviewPanel;
|
||||||
@ -146,8 +146,8 @@ export class PaneviewComponent
|
|||||||
private readonly _onDidLayoutChange = new Emitter<void>();
|
private readonly _onDidLayoutChange = new Emitter<void>();
|
||||||
readonly onDidLayoutChange: Event<void> = this._onDidLayoutChange.event;
|
readonly onDidLayoutChange: Event<void> = this._onDidLayoutChange.event;
|
||||||
|
|
||||||
private readonly _onDidDrop = new Emitter<PaneviewDropEvent2>();
|
private readonly _onDidDrop = new Emitter<PaneviewDropEvent>();
|
||||||
readonly onDidDrop: Event<PaneviewDropEvent2> = this._onDidDrop.event;
|
readonly onDidDrop: Event<PaneviewDropEvent> = this._onDidDrop.event;
|
||||||
|
|
||||||
private readonly _onDidAddView = new Emitter<PaneviewPanel>();
|
private readonly _onDidAddView = new Emitter<PaneviewPanel>();
|
||||||
readonly onDidAddView = this._onDidAddView.event;
|
readonly onDidAddView = this._onDidAddView.event;
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user