Merge branch 'master' of https://github.com/mathuo/dockview into 84-add-ability-to-have-fixed-panel-with-no-tab-in-dockviewreact

This commit is contained in:
mathuo 2022-05-04 19:54:29 +01:00
commit 6ebd185f0a
No known key found for this signature in database
GPG Key ID: C6EEDEFD6CA07281
51 changed files with 19890 additions and 87162 deletions

View File

@ -3,60 +3,60 @@
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
name: "CodeQL"
name: 'CodeQL'
on:
# push:
# branches: [master]
# pull_request:
# # The branches below must be a subset of the branches above
# branches: [master]
schedule:
- cron: "0 4 * * *"
# push:
# branches: [master]
# pull_request:
# # The branches below must be a subset of the branches above
# branches: [master]
schedule:
- cron: '0 4 * * *'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
analyze:
name: Analyze
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
# Override automatic language detection by changing the below list
# Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
language: ["javascript"]
# Learn more...
# https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
strategy:
fail-fast: false
matrix:
# Override automatic language detection by changing the below list
# Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
language: ['javascript']
# Learn more...
# https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
steps:
- name: Checkout repository
uses: actions/checkout@v2
steps:
- name: Checkout repository
uses: actions/checkout@v2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

42
.github/workflows/deploy-docs.yml vendored Normal file
View File

@ -0,0 +1,42 @@
name: Deploy Docs
# on:
# schedule:
# - cron: '0 3 * * *' # every day at 3 am UTC
on: [push]
jobs:
deploy-nightly-demo-app:
runs-on: ubuntu-latest
steps:
- name: Checkout 🛎️
uses: actions/checkout@v2.3.1 # If you're using actions/checkout@v2 you must set persist-credentials to false in most cases for the deployment to work correctly.
with:
persist-credentials: false
- name: Use Node.js
uses: actions/setup-node@v1
with:
node-version: '16.x'
- uses: actions/cache@v2
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-node-
- run: yarn
- run: npm run bootstrap-no-hoist
- run: npm run build
- run: npm run test
- run: npm run deploy-docs
- name: Deploy 🚀
uses: JamesIves/github-pages-deploy-action@3.7.1
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BRANCH: gh-pages # The branch the action should deploy to.
FOLDER: docs # The folder the action should deploy.
TARGET_FOLDER: docs
CLEAN: true # Automatically remove deleted files from the deploy branch

View File

@ -1,40 +1,40 @@
name: Deploy Nightly Demo App
on:
schedule:
- cron: '0 3 * * *' # every day at 3 am UTC
schedule:
- cron: '0 3 * * *' # every day at 3 am UTC
jobs:
deploy-nightly-demo-app:
runs-on: ubuntu-latest
steps:
- name: Checkout 🛎️
uses: actions/checkout@v2.3.1 # If you're using actions/checkout@v2 you must set persist-credentials to false in most cases for the deployment to work correctly.
with:
persist-credentials: false
deploy-nightly-demo-app:
runs-on: ubuntu-latest
steps:
- name: Checkout 🛎️
uses: actions/checkout@v2.3.1 # If you're using actions/checkout@v2 you must set persist-credentials to false in most cases for the deployment to work correctly.
with:
persist-credentials: false
- name: Use Node.js
uses: actions/setup-node@v1
with:
node-version: '12.x'
- name: Use Node.js
uses: actions/setup-node@v1
with:
node-version: '16.x'
- uses: actions/cache@v2
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- run: npm ci
- run: npm run bootstrap-no-hoist
- run: npm run build
- run: npm run test
- run: npm run package-all
- name: Deploy 🚀
uses: JamesIves/github-pages-deploy-action@3.7.1
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BRANCH: gh-pages # The branch the action should deploy to.
FOLDER: output # The folder the action should deploy.
TARGET_FOLDER: output
CLEAN: true # Automatically remove deleted files from the deploy branch
- uses: actions/cache@v2
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-node-
- run: yarn
- run: npm run bootstrap-no-hoist
- run: npm run build
- run: npm run test
- run: npm run package-all
- name: Deploy 🚀
uses: JamesIves/github-pages-deploy-action@3.7.1
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BRANCH: gh-pages # The branch the action should deploy to.
FOLDER: output # The folder the action should deploy.
TARGET_FOLDER: output
CLEAN: true # Automatically remove deleted files from the deploy branch

View File

@ -3,32 +3,32 @@ name: CI
on: [push]
jobs:
build:
runs-on: ubuntu-latest
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
# might be required for sonar to work correctly
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- name: Use Node.js
uses: actions/setup-node@v1
with:
node-version: "16.x"
steps:
- uses: actions/checkout@v2
# might be required for sonar to work correctly
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- name: Use Node.js
uses: actions/setup-node@v1
with:
node-version: '16.x'
- uses: actions/cache@v2
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- uses: actions/cache@v2
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-node-
- run: npm ci
- run: npm run bootstrap
- run: npm run build
- run: npm run test:cov
- name: SonarCloud Scan
uses: SonarSource/sonarcloud-github-action@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
- run: yarn
- run: npm run bootstrap
- run: npm run build
- run: npm run test:cov
- name: SonarCloud Scan
uses: SonarSource/sonarcloud-github-action@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

View File

@ -1,11 +1,13 @@
{
"packages": [
"packages/*"
],
"version": "1.3.1",
"command": {
"publish": {
"message": "chore(release): publish %s"
}
"packages": [
"packages/*"
],
"npmClient": "yarn",
"useWorkspaces": true,
"version": "1.3.1",
"command": {
"publish": {
"message": "chore(release): publish %s"
}
}
}

33187
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,60 +1,64 @@
{
"name": "dockview-monorepo-root",
"private": true,
"description": "Monorepo for https://github.com/mathuo/dockview",
"scripts": {
"test": "jest",
"lint": "eslint packages/**/src/** --ext .ts,.tsx,.js,.jsx",
"package": "node scripts/package.js",
"package-all": "npm run build-demo && npm run docs && node scripts/package.js",
"build": "lerna run build --ignore dockview-demo",
"build-demo": "lerna run build --scope dockview-demo",
"docs": "lerna run docs --scope dockview",
"clean": "lerna run clean",
"bootstrap": "lerna bootstrap",
"bootstrap-no-hoist": "lerna bootstrap",
"test:cov": "jest --coverage",
"version-beta-build": "lerna version prerelease --preid beta",
"publish-app": "lerna publish"
},
"repository": {
"type": "git",
"url": "git+https://github.com/mathuo/dockview.git"
},
"author": "https://github.com/mathuo",
"license": "MIT",
"bugs": {
"url": "https://github.com/mathuo/dockview/issues"
},
"homepage": "https://github.com/mathuo/dockview#readme",
"devDependencies": {
"@testing-library/dom": "^8.13.0",
"@types/jest": "^27.4.1",
"@typescript-eslint/eslint-plugin": "^5.19.0",
"@typescript-eslint/parser": "^5.19.0",
"codecov": "^3.8.3",
"cross-env": "^7.0.3",
"css-loader": "^6.7.1",
"eslint": "^8.13.0",
"fs-extra": "^10.0.1",
"gulp": "^4.0.2",
"gulp-concat": "^2.6.1",
"gulp-dart-sass": "^1.0.2",
"jest": "^27.5.1",
"jest-sonar-reporter": "^2.0.0",
"jsdom": "^19.0.0",
"lerna": "^4.0.0",
"merge2": "^1.4.1",
"rimraf": "^3.0.2",
"sass": "^1.50.0",
"sass-loader": "^12.6.0",
"style-loader": "^3.3.1",
"ts-jest": "^27.1.4",
"ts-loader": "^9.2.8",
"tslib": "^2.3.1",
"typescript": "^4.6.3",
"webpack": "^5.72.0",
"webpack-cli": "^4.9.2",
"webpack-dev-server": "^4.8.1"
}
"name": "dockview-monorepo-root",
"private": true,
"description": "Monorepo for https://github.com/mathuo/dockview",
"workspaces": [
"packages/*"
],
"scripts": {
"test": "jest",
"lint": "eslint packages/**/src/** --ext .ts,.tsx,.js,.jsx",
"package": "node scripts/package.js",
"package-all": "npm run build-demo && npm run docs && node scripts/package.js",
"deploy-docs": "lerna run build --scope dockview-docs && lerna run export --scope dockview-docs && node scripts/package-docs.js",
"build": "lerna run build --scope dockview",
"build-demo": "lerna run build --scope dockview-demo",
"docs": "lerna run docs --scope dockview",
"clean": "lerna run clean",
"bootstrap": "lerna bootstrap",
"bootstrap-no-hoist": "lerna bootstrap",
"test:cov": "jest --coverage",
"version-beta-build": "lerna version prerelease --preid beta",
"publish-app": "lerna publish"
},
"repository": {
"type": "git",
"url": "git+https://github.com/mathuo/dockview.git"
},
"author": "https://github.com/mathuo",
"license": "MIT",
"bugs": {
"url": "https://github.com/mathuo/dockview/issues"
},
"homepage": "https://github.com/mathuo/dockview#readme",
"devDependencies": {
"@testing-library/dom": "^8.13.0",
"@types/jest": "^27.4.1",
"@typescript-eslint/eslint-plugin": "^5.19.0",
"@typescript-eslint/parser": "^5.19.0",
"codecov": "^3.8.3",
"cross-env": "^7.0.3",
"css-loader": "^6.7.1",
"eslint": "^8.13.0",
"fs-extra": "^10.0.1",
"gulp": "^4.0.2",
"gulp-concat": "^2.6.1",
"gulp-dart-sass": "^1.0.2",
"jest": "^27.5.1",
"jest-sonar-reporter": "^2.0.0",
"jsdom": "^19.0.0",
"lerna": "^4.0.0",
"merge2": "^1.4.1",
"rimraf": "^3.0.2",
"sass": "^1.50.0",
"sass-loader": "^12.6.0",
"style-loader": "^3.3.1",
"ts-jest": "^27.1.4",
"ts-loader": "^9.2.8",
"tslib": "^2.3.1",
"typescript": "^4.6.3",
"webpack": "^5.72.0",
"webpack-cli": "^4.9.2",
"webpack-dev-server": "^4.8.1"
}
}

File diff suppressed because it is too large Load Diff

View File

@ -74,7 +74,7 @@ export const Application = () => {
id: 'sidebar',
component: 'sidebar',
snap: true,
position: { reference: 'editor', direction: 'left' },
position: { referencePanel: 'editor', direction: 'left' },
minimumWidth: 170,
size: 100,
});
@ -82,7 +82,7 @@ export const Application = () => {
event.api.addPanel({
id: 'panel',
component: 'panel',
position: { reference: 'editor', direction: 'below' },
position: { referencePanel: 'editor', direction: 'below' },
size: 200,
snap: true,
});

View File

@ -119,7 +119,6 @@ const components: PanelCollection<IDockviewPanelProps> = {
components={components}
watermarkComponent={WatermarkComponent}
tabHeight={20}
debug={true}
/>
</div>
);
@ -271,7 +270,6 @@ export const TestGrid = (props: IGridviewPanelProps) => {
onReady={onReady}
components={components}
tabComponents={tabComponents}
debug={false}
onTabContextMenu={onTabContextMenu}
watermarkComponent={Watermark}
showDndOverlay={(ev, target) => {

View File

@ -110,7 +110,7 @@ export const SplitPanel = (props: IDockviewPanelProps) => {
};
const onRemove = () => {
const panels = api.current.getPanels();
const panels = api.current.panels;
if (panels.length === 0) {
return;
}

View File

@ -172,9 +172,9 @@ export const Common = (
maximumSize,
minimumSize,
length,
visibility: api.current
.getPanels()
.map((_) => _.api.isVisible),
visibility: api.current.panels.map(
(_) => _.api.isVisible
),
});
}
),
@ -226,19 +226,19 @@ export const Common = (
};
const toggleVisibility = (i: number) => () => {
const panel = api.current.getPanels()[i];
const panel = api.current.panels[i];
api.current.setVisible(panel, !panel.api.isVisible);
setDimensions((dimensions) => ({
...dimensions,
visibility: api.current.getPanels().map((_) => _.api.isVisible),
visibility: api.current.panels.map((_) => _.api.isVisible),
}));
};
const move = () => {
api.current.movePanel(api.current.getPanels().length - 1, 0);
api.current.movePanel(api.current.panels.length - 1, 0);
setDimensions((dimensions) => ({
...dimensions,
visibility: api.current.getPanels().map((_) => _.api.isVisible),
visibility: api.current.panels.map((_) => _.api.isVisible),
}));
};

View File

@ -151,56 +151,54 @@ export const Activitybar = (props: IGridviewPanelProps) => {
};
}, []);
const onClick = (container: ViewContainer, alwaysOpen = false) => (
event: React.MouseEvent
) => {
const api = registry.get<GridviewApi>('gridview');
const onClick =
(container: ViewContainer, alwaysOpen = false) =>
(event: React.MouseEvent) => {
const api = registry.get<GridviewApi>('gridview');
const selectedActive = container.id === activeContainerid;
const selectedActive = container.id === activeContainerid;
const sidebarPanel = api.getPanel('sidebar');
if (sidebarPanel.api.isVisible) {
if (!alwaysOpen && selectedActive) {
api.setVisible(sidebarPanel, false);
}
} else {
event.preventDefault(); // prevent focus
api.setVisible(sidebarPanel, true);
sidebarPanel.focus();
}
viewService.model.setActiveViewContainer(container.id);
};
const onContainerDrop = (targetContainer: ViewContainer) => (
event: React.DragEvent,
direction: 'top' | 'bottom'
) => {
const data = event.dataTransfer.getData('application/json');
if (data) {
const { container } = JSON.parse(data);
const sourceContainer = viewService.model.getViewContainer(
container
);
switch (direction) {
case 'bottom':
viewService.model.insertContainerAfter(
sourceContainer,
targetContainer
);
break;
case 'top':
viewService.model.insertContainerBefore(
sourceContainer,
targetContainer
);
break;
const sidebarPanel = api.getPanel('sidebar');
if (sidebarPanel.api.isVisible) {
if (!alwaysOpen && selectedActive) {
api.setVisible(sidebarPanel, false);
}
} else {
event.preventDefault(); // prevent focus
api.setVisible(sidebarPanel, true);
sidebarPanel.focus();
}
viewService.model.setActiveViewContainer(sourceContainer.id);
}
};
viewService.model.setActiveViewContainer(container.id);
};
const onContainerDrop =
(targetContainer: ViewContainer) =>
(event: React.DragEvent, direction: 'top' | 'bottom') => {
const data = event.dataTransfer.getData('application/json');
if (data) {
const { container } = JSON.parse(data);
const sourceContainer =
viewService.model.getViewContainer(container);
switch (direction) {
case 'bottom':
viewService.model.insertContainerAfter(
sourceContainer,
targetContainer
);
break;
case 'top':
viewService.model.insertContainerBefore(
sourceContainer,
targetContainer
);
break;
}
viewService.model.setActiveViewContainer(sourceContainer.id);
}
};
const onNewContainer = (event: React.DragEvent) => {
const data = getPaneData();
@ -371,7 +369,7 @@ export const SidebarPart = (props: { id: string }) => {
if (schema) {
api.fromJSON(schema);
} else {
api.getPanels().forEach((p) => {
api.panels.forEach((p) => {
api.removePanel(p);
});
viewContainer.views.forEach((view) => {
@ -400,9 +398,8 @@ export const SidebarPart = (props: { id: string }) => {
const onDidDrop = (event: PaneviewDropEvent) => {
const data = event.getData();
const containerData = event.nativeEvent.dataTransfer.getData(
'application/json'
);
const containerData =
event.nativeEvent.dataTransfer.getData('application/json');
if (containerData) {
const { container } = JSON.parse(containerData);
@ -411,9 +408,8 @@ export const SidebarPart = (props: { id: string }) => {
return;
}
const sourceContainer = viewService.model.getViewContainer(
container
);
const sourceContainer =
viewService.model.getViewContainer(container);
const targetContainer = viewService.model.getViewContainer(
props.id
);
@ -439,7 +435,7 @@ export const SidebarPart = (props: { id: string }) => {
}
const targetPanel = event.panel;
const allPanels = event.api.getPanels();
const allPanels = event.api.panels;
let toIndex = allPanels.indexOf(targetPanel);
if (

View File

@ -0,0 +1,3 @@
{
"extends": "next/core-web-vitals"
}

35
packages/dockview-docs/.gitignore vendored Normal file
View File

@ -0,0 +1,35 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
# local env files
.env*.local
# vercel
.vercel
# typescript
*.tsbuildinfo

View File

@ -0,0 +1,34 @@
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
## Getting Started
First, run the development server:
```bash
npm run dev
# or
yarn dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file.
[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`.
The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
## Learn More
To learn more about Next.js, take a look at the following resources:
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
## Deploy on Vercel
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.

View File

@ -0,0 +1,27 @@
<!-- <!DOCTYPE html> -->
<html>
<head>
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<script crossorigin src="https://unpkg.com/dockview@latest/dist/dockview.js"></script>
<link rel="stylesheet" href="https://unpkg.com/browse/dockview@latest/dist/styles/dockview.css">
<style>
body {
margin: 0;
}
#root {
height: 100vh;
width: 100vw;
background-color: grey;
}
</style>
</head>
<body>
<div id="root"></div>
<script>
const root = document.getElementById("root")
const dockviewComponent = new dockview.DockviewComponent(root, {})
</script>
</body>
</html>

5
packages/dockview-docs/next-env.d.ts vendored Normal file
View File

@ -0,0 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.

View File

@ -0,0 +1,62 @@
import transpile from 'next-transpile-modules';
import slugs from 'rehype-slug';
import autoLinkHeadings from 'rehype-autolink-headings';
import mdx from '@next/mdx';
import remarkGfm from 'remark-gfm';
const withTM = transpile(['dockview', 'dockview-demo'], {
resolveSymlinks: true,
});
const withMDX = mdx({
extension: /\.mdx$/,
options: {
remarkPlugins: [remarkGfm],
rehypePlugins: [
slugs,
[
autoLinkHeadings,
{
behavior: 'append',
},
],
],
providerImportSource: '@mdx-js/react',
},
});
export default withTM(
withMDX({
basePath: '/dockview/docs',
assetPrefix: '/dockview/docs/',
//
reactStrictMode: true,
pageExtensions: ['ts', 'tsx', 'js', 'jsx', 'md', 'mdx'],
experimental: {
externalDir: true,
},
webpack(config, options) {
if (options.isServer) {
config.externals = ['react', 'react-dom', ...config.externals];
}
config.module.rules.push({
test: /\.tsx?|\.ts?$/,
use: [options.defaultLoaders.babel],
});
// config.resolve.alias['react'] = path.resolve(
// __dirname,
// '.',
// 'node_modules',
// 'react-dom'
// );
// config.resolve.alias['react-dom'] = path.resolve(
// __dirname,
// '.',
// 'node_modules',
// 'react-dom'
// );
return config;
},
})
);

View File

@ -0,0 +1,34 @@
{
"name": "dockview-docs",
"version": "1.3.1",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"export": "next export"
},
"dependencies": {
"@mdx-js/loader": "^2.1.1",
"@mdx-js/react": "^2.1.1",
"@next/mdx": "^12.1.5",
"dockview": "^1.3.1",
"next": "12.1.5",
"prism-react-renderer": "^1.3.1",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"rehype-autolink-headings": "^6.1.1",
"rehype-slug": "^5.0.1",
"remark-gfm": "^3.0.1"
},
"devDependencies": {
"@types/node": "17.0.28",
"@types/react": "^18.0.8",
"@types/react-dom": "^18.0.2",
"eslint": "8.14.0",
"eslint-config-next": "12.1.5",
"next-transpile-modules": "^9.0.0",
"typescript": "4.6.3"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z"/></svg>

After

Width:  |  Height:  |  Size: 350 B

View File

@ -0,0 +1,4 @@
<svg width="283" height="64" viewBox="0 0 283 64" fill="none"
xmlns="http://www.w3.org/2000/svg">
<path d="M141.04 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.46 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM248.72 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.45 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM200.24 34c0 6 3.92 10 10 10 4.12 0 7.21-1.87 8.8-4.92l7.68 4.43c-3.18 5.3-9.14 8.49-16.48 8.49-11.05 0-19-7.2-19-18s7.96-18 19-18c7.34 0 13.29 3.19 16.48 8.49l-7.68 4.43c-1.59-3.05-4.68-4.92-8.8-4.92-6.07 0-10 4-10 10zm82.48-29v46h-9V5h9zM36.95 0L73.9 64H0L36.95 0zm92.38 5l-27.71 48L73.91 5H84.3l17.32 30 17.32-30h10.39zm58.91 12v9.69c-1-.29-2.06-.49-3.2-.49-5.81 0-10 4-10 10V51h-9V17h9v9.2c0-5.08 5.91-9.2 13.2-9.2z" fill="#000"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,70 @@
import React from 'react';
import Highlight, { defaultProps, Language } from 'prism-react-renderer';
import theme from 'prism-react-renderer/themes/palenight';
interface CodeBlockProps {
children: string;
className?: string;
live?: boolean | string;
render?: boolean | string;
url: string;
code?: boolean | string;
center?: boolean | string;
edit?: boolean | string;
}
export const CodeBlock = ({
children,
className = '',
live,
render,
url,
code = true,
center = true,
edit = false,
}: CodeBlockProps) => {
if (!className) {
return (
<code
style={{
backgroundColor: 'rgba(27, 31, 35, 0.05)',
fontSize: '85%',
padding: '0.2em 0.4em',
margin: '0px',
borderRadius: '5px',
}}
>
{children}
</code>
);
}
const language = className.replace(/language-/, '');
return (
<Highlight
{...defaultProps}
theme={theme}
code={children.trim()}
language={language as Language}
>
{({ className, style, tokens, getLineProps, getTokenProps }) => (
<pre
className={className}
style={{ ...style, padding: '20px' }}
>
{tokens.map((line, i) => (
<div key={i} {...getLineProps({ line, key: i })}>
{line.map((token, key) => (
<span
key={key}
{...getTokenProps({ token, key })}
/>
))}
</div>
))}
</pre>
)}
</Highlight>
);
};

View File

@ -0,0 +1,24 @@
import { PAGES } from '../references/pages';
import { Navigation } from './navigation';
export const Container = (props: { children: React.ReactNode }) => {
return (
<main
style={{
flexGrow: 1,
display: 'flex',
flexDirection: 'row',
}}
>
<div style={{ padding: '20px' }}>
<Navigation pages={PAGES} />
</div>
<div
style={{ flexGrow: 1, padding: '20px' }}
className="markdown-body"
>
{props.children}
</div>
</main>
);
};

View File

@ -0,0 +1,7 @@
export const Footer = (props: {}) => {
return (
<div style={{ height: '100px', backgroundColor: 'rgb(30,30,30)' }}>
footer
</div>
);
};

View File

@ -0,0 +1,46 @@
import { DockviewReact, DockviewReadyEvent } from 'dockview';
const components = {
default: () => {
return <div>Hello World</div>;
},
};
export const Header = (props: {}) => {
const onReady = (event: DockviewReadyEvent) => {
event.api.addPanel({
id: 'panel1',
component: 'default',
});
event.api.addPanel({
id: 'panel2',
component: 'default',
});
event.api.addPanel({
id: 'panel3',
component: 'default',
position: {
referencePanel: 'panel2',
direction: 'right',
},
});
};
return (
<div
style={{
height: '0px',
backgroundColor: '#0070f3',
padding: '5vw',
}}
>
<DockviewReact
onReady={onReady}
components={components}
className="dockview-theme-dark"
/>
</div>
);
};

View File

@ -0,0 +1,88 @@
import * as React from 'react';
import { Page } from '../references/pages';
import Link from 'next/link';
const LinkHeader = (props: { url: string; title: string }) => {
return (
<Link href={props.url}>
<a>{props.title}</a>
</Link>
);
};
export const CollapsibleNode = (props: {
page: Page;
children: React.ReactNode;
depth: number;
}) => {
const [expanded, setExpaned] = React.useState<boolean>(false);
const onClick = () => {
setExpaned(!expanded);
};
const cn = React.useMemo(() => {
return ['node', expanded ? 'expanded' : 'collapsed'].join(' ');
}, [expanded]);
return (
<>
<div className={cn} onClick={onClick}>
{props.page.url ? (
<LinkHeader url={props.page.url} title={props.page.title} />
) : (
props.page.title
)}
</div>
<div
className="node"
style={{
display: expanded ? '' : 'none',
overflow: 'hidden',
marginLeft: `${props.depth * 8}px`,
}}
>
{props.children}
</div>
</>
);
};
export const Node = (props: { page: Page; depth: number }) => {
if (props.page.routes) {
return (
<CollapsibleNode page={props.page} depth={props.depth + 1}>
{props.page.routes.map((page) => (
<Node
key={page.title}
page={page}
depth={props.depth + 1}
/>
))}
</CollapsibleNode>
);
}
return (
<div className="node">
{props.page.url ? (
<LinkHeader url={props.page.url} title={props.page.title} />
) : (
props.page.title
)}
</div>
);
};
export const Navigation = (props: { pages: Page[] }) => {
return (
<div
className="navigation"
style={{ position: 'sticky', top: '20px', left: '20px' }}
>
{props.pages.map((page) => (
<Node key={page.title} page={page} depth={0} />
))}
</div>
);
};

View File

@ -0,0 +1,100 @@
import {
DockviewReact,
DockviewReadyEvent,
IDockviewPanelProps,
} from 'dockview';
const components = {
default: (props: IDockviewPanelProps<{ title: string }>) => {
return <div style={{ padding: '20px' }}>{props.params.title}</div>;
},
};
export const SimpleDockview = () => {
const onReady = (event: DockviewReadyEvent) => {
event.api.onDidLayoutChange(() => {
localStorage.setItem(
'dockview_test',
JSON.stringify(event.api.toJSON())
);
});
const layout = localStorage.getItem('dockview_test');
if (layout) {
event.api.fromJSON(JSON.parse(layout));
return;
}
event.api.addPanel({
id: 'panel_1',
component: 'default',
params: {
title: 'Panel 1',
},
});
event.api.addPanel({
id: 'panel_2',
component: 'default',
params: {
title: 'Panel 2',
},
});
event.api.addPanel({
id: 'panel_3',
component: 'default',
params: {
title: 'Panel 3',
},
});
event.api.addPanel({
id: 'panel_4',
component: 'default',
params: {
title: 'Panel 4',
},
position: { referencePanel: 'panel_1', direction: 'right' },
});
const panel5 = event.api.addPanel({
id: 'panel_5',
component: 'default',
params: {
title: 'Panel 5',
},
position: { referencePanel: 'panel_3', direction: 'right' },
});
// panel5.group!.model.header.hidden = true;
// panel5.group!.model.locked = true;
event.api.addPanel({
id: 'panel_6',
component: 'default',
params: {
title: 'Panel 6',
},
position: { referencePanel: 'panel_5', direction: 'below' },
});
event.api.addPanel({
id: 'panel_7',
component: 'default',
params: {
title: 'Panel 7',
},
position: { referencePanel: 'panel_6', direction: 'right' },
});
};
return (
<DockviewReact
components={components}
onReady={onReady}
className="dockview-theme-dark"
/>
);
};

View File

@ -0,0 +1,85 @@
import {
IGridviewPanelProps,
Orientation,
GridviewReact,
GridviewReadyEvent,
} from 'dockview';
const components = {
default: (props: IGridviewPanelProps<{ title: string }>) => {
return <div style={{ padding: '20px' }}>{props.params.title}</div>;
},
};
export const SimpleGridview = () => {
const onReady = (event: GridviewReadyEvent) => {
event.api.addPanel({
id: 'panel_1',
component: 'default',
params: {
title: 'Panel 1',
},
});
event.api.addPanel({
id: 'panel_2',
component: 'default',
params: {
title: 'Panel 2',
},
});
event.api.addPanel({
id: 'panel_3',
component: 'default',
params: {
title: 'Panel 3',
},
});
event.api.addPanel({
id: 'panel_4',
component: 'default',
params: {
title: 'Panel 4',
},
position: { referencePanel: 'panel_1', direction: 'right' },
});
event.api.addPanel({
id: 'panel_5',
component: 'default',
params: {
title: 'Panel 5',
},
position: { referencePanel: 'panel_3', direction: 'right' },
});
event.api.addPanel({
id: 'panel_6',
component: 'default',
params: {
title: 'Panel 6',
},
position: { referencePanel: 'panel_5', direction: 'below' },
});
event.api.addPanel({
id: 'panel_7',
component: 'default',
params: {
title: 'Panel 7',
},
position: { referencePanel: 'panel_6', direction: 'right' },
});
};
return (
<GridviewReact
components={components}
onReady={onReady}
orientation={Orientation.VERTICAL}
className="dockview-theme-dark"
/>
);
};

View File

@ -0,0 +1,50 @@
import {
IPaneviewPanelProps,
PaneviewReact,
PaneviewReadyEvent,
} from 'dockview';
const components = {
default: (props: IPaneviewPanelProps<{ title: string }>) => {
return <div style={{ padding: '20px' }}>{props.params.title}</div>;
},
};
export const SimplePaneview = () => {
const onReady = (event: PaneviewReadyEvent) => {
event.api.addPanel({
id: 'panel_1',
component: 'default',
params: {
title: 'Panel 1',
},
title: 'Panel 1',
});
event.api.addPanel({
id: 'panel_2',
component: 'default',
params: {
title: 'Panel 2',
},
title: 'Panel 2',
});
event.api.addPanel({
id: 'panel_3',
component: 'default',
params: {
title: 'Panel 3',
},
title: 'Panel 3',
});
};
return (
<PaneviewReact
components={components}
onReady={onReady}
className="dockview-theme-dark"
/>
);
};

View File

@ -0,0 +1,53 @@
import {
ISplitviewPanelProps,
Orientation,
SplitviewReact,
SplitviewReadyEvent,
} from 'dockview';
const components = {
default: (props: ISplitviewPanelProps<{ title: string }>) => {
return <div style={{ padding: '20px' }}>{props.params.title}</div>;
},
};
export const SimpleSplitview = (props: { proportional?: boolean }) => {
const onReady = (event: SplitviewReadyEvent) => {
event.api.addPanel({
id: 'panel_1',
component: 'default',
params: {
title: 'Panel 1',
},
minimumSize: 100,
});
event.api.addPanel({
id: 'panel_2',
component: 'default',
params: {
title: 'Panel 2',
},
minimumSize: 100,
});
event.api.addPanel({
id: 'panel_3',
component: 'default',
params: {
title: 'Panel 3',
},
minimumSize: 100,
});
};
return (
<SplitviewReact
components={components}
proportionalLayout={props.proportional}
onReady={onReady}
orientation={Orientation.HORIZONTAL}
className="dockview-theme-dark"
/>
);
};

View File

@ -0,0 +1,5 @@
import * as React from 'react';
export const Test = () => {
return <div>this is a test component</div>;
};

View File

@ -0,0 +1,33 @@
import { Header } from '../components/header';
import { Footer } from '../components/footer';
import { Container } from '../components/container';
import { AppProps } from 'next/app';
import '../styles/globals.css';
import { CodeBlock } from '../components/code';
import { MDXProvider } from '@mdx-js/react';
const components = {
code: CodeBlock,
} as any;
const MyApp = (props: AppProps) => {
return (
<div
style={{
minHeight: '100vh',
display: 'flex',
flexDirection: 'column',
}}
>
<MDXProvider components={components}>
<Header />
<Container>
<props.Component {...props.pageProps} />
</Container>
<Footer />
</MDXProvider>
</div>
);
};
export default MyApp;

View File

@ -0,0 +1,28 @@
import { Html, Head, Main, NextScript } from 'next/document';
export default function Document() {
return (
<Html lang="en">
<Head>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link
rel="preconnect"
href="https://fonts.gstatic.com"
crossOrigin="true"
/>
<link
href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap"
rel="stylesheet"
/>
{/* <link
rel="stylesheet"
href="https://unpkg.com/dracula-prism/dist/css/dracula-prism.css"
/> */}
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}

View File

@ -0,0 +1,12 @@
import * as React from 'react';
import { Test } from '../test';
const Component = () => {
return (
<div style={{ height: '50vh', width: '50vw' }}>
<Test />
</div>
);
};
export default Component;

View File

@ -0,0 +1,100 @@
import { SimpleSplitview } from '../components/simpleSplitview';
## Auto resizing
`SplitviewReact`, `GridviewReact`, `PaneviewReact` and `DockviewReact` will all automatically resize to fill the size of their parent element.
Internally this is achieved using a [ResizeObserver](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver).
You can disable this by settings the `disableAutoResizing` prop to be `true`.
You can manually resize a component using the API method `layout(width: number, height: number): void`.
You can force a component to resize without providing any measurements using the API method `resizeToFit(): void`.
This method will evaluate the width and height of the parent `HTMLElement` container and use these values to relayout.
## Proportional layout
<div
style={{
height: '100px',
backgroundColor: 'rgb(30,30,30)',
color: 'white',
margin: '20px 0px',
}}
>
<SimpleSplitview proportional={false} />
</div>
<div
style={{
height: '100px',
backgroundColor: 'rgb(30,30,30)',
color: 'white',
margin: '20px 0px',
}}
>
<SimpleSplitview proportional={true} />
</div>
## Panels
The below examples use `ReactSplitview` but the logic holds for `ReactPaneview`, `ReactGridview` and `ReactDockview` using their respective implementations and interfaces.
### Adding a panel with parameters
You can pass parameters to a panel through the `params` object
```tsx
const onReady = (event: SplitviewReadyEvent) => {
event.api.addPanel({
id: 'panel_1',
component: 'myComponent',
params: {
title: 'My Title',
},
});
};
```
and you can access those properties through the `props.params` object. The TypeScript interface accepts an optional generic type `T` that corresponds to the params objects type.
```tsx
const MyComponent = (props: ISplitviewPanelProps<{ title: string }>) => {
return <div>{`My first panel has the title: ${props.params.title}`}</div>;
};
```
### Accessing the panel API
You can access an extensive set of functions in the panel via both the panel `api` and `containerApi`. The `api` is specific to that particular panel and the `containerApi` corresponds to that api which you access during the `onReady` event.
```tsx
const MyComponent = (props: ISplitviewPanelProps<{ title: string }>) => {
React.useEffect(() => {
const disposable = props.api.onDidActiveChange((event) => {
console.log(`is panel active: ${event.isActive}`);
});
return () => {
disposable.dispose(); // remember to dispose of any subscriptions
};
}, [props.api]);
const addAnotherPanel = React.useCallback(() => {
props.containerApi.addPanel({
id: 'another_id',
component: 'anotherComponent',
});
}, [props.containerApi]);
return (
<div>
<span>{`My first panel has the title: ${props.params.title}`}</span>
<button onClick={addAnotherPanel}>Add Panel</button>
</div>
);
};
```
### Serialization
All components support `toJSON(): T` which returns a Typed object representation of the components state. This same Typed object can be used to deserialize a view using `fromJSON(object: T): void`.

View File

@ -0,0 +1,110 @@
## Component Props
```tsx
import { ReactDockview } from 'dockview';
```
| Property | Type | Optional | Default | Description |
| ------------------- | ------------------------------------ | -------- | ------- | ------------------------------------------- |
| onReady | (event: SplitviewReadyEvent) => void | No | | |
| components | object | No | | |
| tabComponents | object | Yes | | |
| watermarkComponent | object | Yes | | |
| hideBorders | boolean | Yes | false | |
| className | string | Yes | '' | |
| disableAutoResizing | boolean | Yes | false | See [Auto resizing](/basics/#auto-resizing) |
| onTabContextMenu | Event | Yes | false | |
| onDidDrop | Event | Yes | false | |
| showDndOverlay | Event | Yes | false | |
## Dockview API
```tsx
const MyComponent = (props: IDockviewPanelProps<{ title: string }>) => {
// props.containerApi...
return <div>{`My first panel has the title: ${props.params.title}`}</div>;
};
```
```tsx
const onReady = (event: DockviewReadyEvent) => {
// event.api...
};
```
| Property | Type | Description |
| ---------------------- | ------------------------------------------------- | ------------------------------------------- |
| height | `number` | Component pixel height |
| width | `number` | Component pixel width |
| minimumHeight | `number` | |
| maximumHeight | `number` | |
| maximumWidth | `number` | |
| maximumWidth | `number` | |
| length | `number` | Number of panels |
| size | `number` | Number of Groups |
| panels | `IGroupPanel[]` | |
| groups | `IGroupviewPanel[]` | |
| activePanel | `IGroupPanel \| undefined` | |
| activeGroup | `IGroupviewPanel \| undefined` | |
| | | |
| onDidLayoutChange | `Event<void>` | |
| onDidLayoutFromJSON | `Event<void>` | |
| onDidAddGroup | `Event<IGroupviewPanel>` | |
| onDidRemoveGroup | `Event<IGroupviewPanel>` | |
| onDidActiveGroupChange | `Event<IGroupviewPanel \| undefined>` | |
| onDidAddPanel | `Event<IGroupPanel>` | |
| onDidRemovePanel | `Event<IGroupPanel>` | |
| onDidActivePanelChange | `Event<IGroupPanel \| undefined>` | |
| onDidDrop | `Event<DockviewDropEvent` | |
| | | |
| addPanel | `addPanel(options: AddPanelOptions): IGroupPanel` | |
| getPanel | `(id: string) \| IGroupPanel \| undefined` | |
| addEmptyGroup | `(options? AddGroupOptions): void` | |
| closeAllGroups | `(): void` | |
| removeGroup | `(group: IGroupviewPanel): void` | |
| getGroup | `(id: string): IGroupviewPanel \| undefined` | |
| | | |
| getTabHeight | `(): number \| undefined` | |
| setTabHeight | `(hegiht: number \| undefined): void` | |
| updateOptions | `(options:SplitviewComponentUpdateOptions): void` | |
| focus | `(): void` | |
| layout | `(width: number, height:number): void` | See [Auto resizing](/basics/#auto-resizing) |
| resizeToFit | `(): void` | See [Auto resizing](/basics/#auto-resizing) |
| fromJSON | `(data: SerializedDockview): void` | See [Serialization](/basics/#serialization) |
| toJSON | `(): SerializedDockview` | See [Serialization](/basics/#serialization) |
## Dockview Panel API
```tsx
const MyComponent = (props: IDockviewPanelProps<{ title: string }>) => {
// props.api...
return <div>{`My first panel has the title: ${props.params.title}`}</div>;
};
```
| Property | Type | Description |
| ---------------------- | ----------------------------------------------------------- | --------------- |
| id | `string` | Panel id |
| isFocused | `boolean` | Is panel focsed |
| isActive | `boolean` | Is panel active |
| width | `number` | Panel width |
| height | `number` | Panel height |
| onDidDimensionsChange | `Event<PanelDimensionChangeEvent>` | |
| onDidFocusChange | `Event<FocusEvent>` | |
| onDidVisibilityChange | `Event<VisibilityEvent>` | |
| onDidActiveChange | `Event<ActiveEvent>` | |
| onFocusEvent | `Event<void>` | |
| setActive | `(): void` | |
| | | |
| onDidConstraintsChange | `onDidConstraintsChange: Event<PanelConstraintChangeEvent>` | |
| setConstraints | `(value: PanelConstraintChangeEvent2): void;` | |
| setSize | `(event: SizeEvent): void` | |
| | | |
| group | `GroupviewPanel | undefined` |
| isGroupActive | `boolean` | |
| title | `string` | |
| suppressClosable | `boolean` | |
| close | `(): void` | |
| setTitle | `(title: string): void` | |

View File

@ -0,0 +1,95 @@
## Component Props
```tsx
import { ReactGridview } from 'dockview';
```
| Property | Type | Optional | Default | Description |
| ------------------- | ------------------------------------ | -------- | ---------------------- | ------------------------------------------- |
| onReady | (event: SplitviewReadyEvent) => void | No | | |
| components | object | No | | |
| orientation | Orientation | Yes | Orientation.HORIZONTAL | |
| proportionalLayout | boolean | Yes | true | |
| hideBorders | boolean | Yes | false | |
| className | string | Yes | '' | |
| disableAutoResizing | boolean | Yes | false | See [Auto resizing](/basics/#auto-resizing) |
## Gridview API
```tsx
const MyComponent = (props: IGridviewPanelProps<{ title: string }>) => {
// props.containerApi...
return <div>{`My first panel has the title: ${props.params.title}`}</div>;
};
```
```tsx
const onReady = (event: GridviewReadyEvent) => {
// event.api...
};
```
| Property | Type | Description |
| ---------------------- | ------------------------------------------------------------------------------------------------- | ------------------------------------------- |
| height | `number` | Component pixel height |
| width | `number` | Component pixel width |
| minimumHeight | `number` | |
| maximumHeight | `number` | |
| maximumWidth | `number` | |
| maximumWidth | `number` | |
| length | `number` | Number of panels |
| panels | `ISplitviewPanel[]` | |
| orientation | `Orientation` | |
| | | |
| onDidLayoutChange | `Event<void>` | |
| onDidLayoutFromJSON | `Event<void>` | |
| onDidAddGroup | `Event<IGridviewPanel>` | |
| onDidRemoveGroup | `Event<IGridviewPanel>` | |
| onDidActiveGroupChange | `Event<IGridviewPanel \| undefined>` | |
| | | |
| addPanel | `addPanel(options: AddComponentOptions): IGridviewPanel` | |
| removePanel | `(panel: IGridviewPanel, sizing?: Sizing): void` | |
| movePanel | `(panel: IGridviewPanel, options: {direction: Direction, refernece:string, size?: number}): void` | |
| getPanel | `(id: string) \| IGridviewPanel \| undefined` | |
| | | |
| updateOptions | `(options:SplitviewComponentUpdateOptions): void` | |
| setVisible | `(panel: IGridviewPanel, isVisible: boolean): void` | |
| focus | `(): void` | |
| setActive | `(panel: IGridviewPanel): void` | |
| toggleVisiblity | `(panel: IGridviewPanel): void` | |
| layout | `(width: number, height:number): void` | See [Auto resizing](/basics/#auto-resizing) |
| resizeToFit | `(): void` | See [Auto resizing](/basics/#auto-resizing) |
| fromJSON | `(data: SerializedGridview): void` | See [Serialization](/basics/#serialization) |
| toJSON | `(): SerializedGridview` | See [Serialization](/basics/#serialization) |
## Gridview Panel API
```tsx
const MyComponent = (props: IGridviewPanelProps<{ title: string }>) => {
// props.api...
return <div>{`My first panel has the title: ${props.params.title}`}</div>;
};
```
| Property | Type | Description |
| ---------------------- | ----------------------------------------------------------- | ---------------- |
| id | `string` | Panel id |
| isFocused | `boolean` | Is panel focsed |
| isActive | `boolean` | Is panel active |
| isVisible | `boolean` | Is panel visible |
| width | `number` | Panel width |
| height | `number` | Panel height |
| | | |
| onDidDimensionsChange | `Event<PanelDimensionChangeEvent>` | |
| onDidFocusChange | `Event<FocusEvent>` | |
| onDidVisibilityChange | `Event<VisibilityEvent>` | |
| onDidActiveChange | `Event<ActiveEvent>` | |
| onFocusEvent | `Event<void>` | |
| onDidConstraintsChange | `onDidConstraintsChange: Event<PanelConstraintChangeEvent>` | |
| | | |
| setVisible | `(isVisible: boolean): void` | |
| setActive | `(): void` | |
| setConstraints | `(value: PanelConstraintChangeEvent2): void;` | |
| setSize | `(event: SizeEvent): void` | |

View File

@ -0,0 +1,167 @@
import { SimpleSplitview } from '../components/simpleSplitview';
import { SimpleGridview } from '../components/simpleGridview';
import { SimplePaneview } from '../components/simplePaneview';
import { SimpleDockview } from '../components/simpleDockview';
# Introduction
**dockview** is a zero dependency layout manager that supports tab, grids and splitviews.
## Features
- Themable and customizable
- Support for the serialization and deserialization of layouts
- Drag and drop support
# Quick start
`dockview` has a peer dependency on `react >= 16.8.0` and `react-dom >= 16.8.0`. To install `dockview` you can run:
```shell
npm install dockview
```
You must also import the dockview stylesheet found under [`dockview/dict/styles/dockview.css`](https://unpkg.com/browse/dockview@latest/dist/styles/dockview.css),
depending on your solution this might be:
```css
@import './node_modules/dockview/dist/styles/dockview.css';
```
A dark and light theme are provided, one of these classes (or a custom theme) must be attached at any point above your components in the HTML tree. To cover the entire web page you might attach the class to the `body` component:
```html
<body classname="dockview-theme-dark">
...
</body>
<body classname="dockview-theme-light">
...
</body>
```
There are 4 components you may want to use:
Splitview
<div
style={{
height: '100px',
backgroundColor: 'rgb(30,30,30)',
color: 'white',
margin: '20px 0px',
}}
>
<SimpleSplitview />
</div>
<div
style={{
height: '300px',
backgroundColor: 'rgb(30,30,30)',
color: 'white',
margin: '20px 0px',
}}
>
<SimpleGridview />
</div>
<div
style={{
height: '300px',
backgroundColor: 'rgb(30,30,30)',
color: 'white',
margin: '20px 0px',
}}
>
<SimplePaneview />
</div>
<div
style={{
height: '300px',
backgroundColor: 'rgb(30,30,30)',
color: 'white',
margin: '20px 0px',
}}
>
<SimpleDockview />
</div>
```tsx
import {
DockviewReact,
DockviewReadyEvent,
PanelCollection,
IDockviewPanelProps,
IDockviewPanelHeaderProps,
} from 'dockview';
const components: PanelCollection<IDockviewPanelProps> = {
default: (props: IDockviewPanelProps<{ someProps: string }>) => {
return <div>{props.params.someProps}</div>;
},
};
const headers: PanelCollection<IDockviewPanelHeaderProps> = {
customTab: (props: IDockviewPanelHeaderProps) => {
return (
<div>
<span>{props.api.title}</span>
<span onClick={() => props.api.close()}>{'[x]'}</span>
</div>
);
},
};
const Component = () => {
const onReady = (event: DockviewReadyEvent) => {
event.api.addPanel({
id: 'panel1',
component: 'default',
tabComponent: 'customTab', // optional custom header
params: {
someProps: 'Hello',
},
});
event.api.addPanel({
id: 'panel2',
component: 'default',
params: {
someProps: 'World',
},
position: { referencePanel: 'panel1', direction: 'below' },
});
};
return (
<DockviewReact
components={components}
tabComponents={headers} // optional headers renderer
onReady={onReady}
/>
);
};
```
```tsx
const components: PanelCollection<IDockviewPanelProps> = {
default: (props: IDockviewPanelProps<{ someProps: string }>) => {
return <div>{props.params.someProps}</div>;
},
fancy: (props: IDockviewPanelProps) => {
return (
<DockviewComponents.Panel>
<DockviewComponents.Tab>
<div>
<span>{props.api.title}</span>
<span onClick={() => props.api.close()}>{'Close'}</span>
</div>
</DockviewComponents.Tab>
<DockviewComponents.Content>
<div>{'Hello world'}</div>
</DockviewComponents.Content>
</DockviewComponents.Panel>
);
},
};
```

View File

@ -0,0 +1,88 @@
## Component Props
```tsx
import { ReactPaneview } from 'dockview';
```
| Property | Type | Optional | Default | Description |
| ------------------- | ------------------------------------ | -------- | ------- | ------------------------------------------- |
| onReady | (event: SplitviewReadyEvent) => void | No | | |
| components | object | No | | |
| headerComponents | object | Yes | | |
| className | string | Yes | '' | |
| disableAutoResizing | boolean | Yes | false | See [Auto resizing](/basics/#auto-resizing) |
| disableDnd | boolean | Yes | false | |
| onDidDrop | Event | Yes | | |
## Gridview API
```tsx
const MyComponent = (props: IGridviewPanelProps<{ title: string }>) => {
// props.containerApi...
return <div>{`My first panel has the title: ${props.params.title}`}</div>;
};
```
```tsx
const onReady = (event: GridviewReadyEvent) => {
// event.api...
};
```
| Property | Type | Description |
| ------------------- | ---------------------------------------------------------------- | ------------------------------------------- |
| height | `number` | Component pixel height |
| width | `number` | Component pixel width |
| minimumSize | `number` | |
| maximumSize | `number` | |
| length | `number` | Number of panels |
| panels | `IPaneviewPanel[]` | |
| | | |
| onDidLayoutChange | `Event<void>` | |
| onDidLayoutFromJSON | `Event<void>` | |
| onDidAddView | `Event<IPaneviewPanel>` | |
| onDidRemoveView | `Event<IPaneviewPanel>` | |
| onDidDrop | `Event<PaneviewDropEvent` | |
| | | |
| addPanel | `addPanel(options: AddPaneviewComponentOptions): IPaneviewPanel` | |
| removePanel | `(panel: IPaneviewPanel): void` | |
| movePanel | `(from: number, to: number): void` | |
| getPanel | `(id:string): IPaneviewPanel \| undefined` | |
| | | |
| focus | `(): void` | |
| layout | `(width: number, height:number): void` | See [Auto resizing](/basics/#auto-resizing) |
| resizeToFit | `(): void` | See [Auto resizing](/basics/#auto-resizing) |
| fromJSON | `(data: SerializedPaneview): void` | See [Serialization](/basics/#serialization) |
| toJSON | `(): SerializedPaneview` | See [Serialization](/basics/#serialization) |
## Gridview Panel API
```tsx
const MyComponent = (props: IGridviewPanelProps<{ title: string }>) => {
// props.api...
return <div>{`My first panel has the title: ${props.params.title}`}</div>;
};
```
| Property | Type | Description |
| ---------------------- | ----------------------------------------------------------- | ---------------- |
| id | `string` | Panel id |
| isFocused | `boolean` | Is panel focsed |
| isActive | `boolean` | Is panel active |
| isVisible | `boolean` | Is panel visible |
| width | `number` | Panel width |
| height | `number` | Panel height |
| | |
| onDidDimensionsChange | `Event<PanelDimensionChangeEvent>` | |
| onDidFocusChange | `Event<FocusEvent>` | |
| onDidVisibilityChange | `Event<VisibilityEvent>` | |
| onDidActiveChange | `Event<ActiveEvent>` | |
| onFocusEvent | `Event<void>` | |
| onDidConstraintsChange | `onDidConstraintsChange: Event<PanelConstraintChangeEvent>` | |
| | |
| setVisible | `(isVisible: boolean): void` | |
| setActive | `(): void` | |
| setConstraints | `(value: PanelConstraintChangeEvent2): void;` | |
| setSize | `(event: SizeEvent): void` | |

View File

@ -0,0 +1,160 @@
import { SimpleSplitview } from '../components/simpleSplitview';
# Splitview
<div
style={{
height: '100px',
backgroundColor: 'rgb(30,30,30)',
color: 'white',
margin: '20px 0px',
}}
>
<SimpleSplitview />
</div>
```tsx
import {
ISplitviewPanelProps,
Orientation,
SplitviewReact,
SplitviewReadyEvent,
} from 'dockview';
const components = {
default: (props: ISplitviewPanelProps<{ title: string }>) => {
return <div style={{ padding: '20px' }}>{props.params.title}</div>;
},
};
export const SimpleSplitview = () => {
const onReady = (event: SplitviewReadyEvent) => {
event.api.addPanel({
id: 'panel_1',
component: 'default',
params: {
title: 'Panel 1',
},
});
event.api.addPanel({
id: 'panel_2',
component: 'default',
params: {
title: 'Panel 2',
},
});
event.api.addPanel({
id: 'panel_3',
component: 'default',
params: {
title: 'Panel 3',
},
});
};
return (
<SplitviewReact
components={components}
onReady={onReady}
orientation={Orientation.HORIZONTAL}
className="dockview-theme-dark"
/>
);
};
```
## Component Props
```tsx
import { ReactSplitview } from 'dockview';
```
The `onReady` prop you will you access to the component `api`.
| Property | Type | Optional | Default | Description |
| ------------------- | -------------------------------------- | -------- | ------------------------ | ------------------------------------------------------- |
| onReady | `(event: SplitviewReadyEvent) => void` | No | | |
| components | `Record<string, ISplitviewPanelProps>` | No | | Panel renderers |
| orientation | `Orientation` | Yes | `Orientation.HORIZONTAL` | Orientation of the Splitview |
| proportionalLayout | `boolean` | Yes | `true` | See [Proportional layout](/basics/#proportional-layout) |
| hideBorders | `boolean` | Yes | `false` | Hide the borders between panels |
| className | `string` | Yes | `''` | Attaches a classname |
| disableAutoResizing | `boolean` | Yes | `false` | See [Auto resizing](/basics/#auto-resizing) |
## Splitview API
```tsx
const MyComponent = (props: ISplitviewPanelProps<{ title: string }>) => {
// props.containerApi...
return <div>{`My first panel has the title: ${props.params.title}`}</div>;
};
```
```tsx
const onReady = (event: SplitviewReadyEvent) => {
// event.api...
};
```
| Property | Type | Description |
| ------------------- | ------------------------------------------------------------------ | ------------------------------------------- |
| height | `number` | Component pixel height |
| width | `number` | Component pixel width |
| minimumSize | `number` | |
| maximumSize | `number` | |
| length | `number` | Number of panels |
| panels | `ISplitviewPanel[]` | |
| | | |
| onDidLayoutChange | `Event<void>` | |
| onDidLayoutFromJSON | `Event<void>` | |
| onDidAddView | `Event<IView>` | |
| onDidRemoveView | `Event<IView>` | |
| | | |
| addPanel | `addPanel(options: AddSplitviewComponentOptions): ISplitviewPanel` | |
| removePanel | `(panel: ISplitviewPanel, sizing?: Sizing): void` | |
| getPanel | `(id:string): ISplitviewPanel \| undefined` | |
| movePanel | `(from: number, to: number): void` | |
| | |
| setVisible | `(panel: ISplitviewPanel, isVisible: boolean): void` | |
| setActive | `(panel: ISplitviewPanel): void` | |
| updateOptions | `(options:SplitviewComponentUpdateOptions): void` | |
| focus | `(): void` | |
| layout | `(width: number, height:number): void` | See [Auto resizing](/basics/#auto-resizing) |
| resizeToFit | `(): void` | See [Auto resizing](/basics/#auto-resizing) |
| fromJSON | `(data: SerializedSplitview): void` | See [Serialization](/basics/#serialization) |
| toJSON | `(): SerializedSplitview` | See [Serialization](/basics/#serialization) |
## Splitview Panel API
```tsx
const MyComponent = (props: ISplitviewPanelProps<{ title: string }>) => {
// props.api...
return <div>{`My first panel has the title: ${props.params.title}`}</div>;
};
```
| Property | Type | Description |
| ---------------------- | ----------------------------------------------------------- | ---------------- |
| id | `string` | Panel id |
| isFocused | `boolean` | Is panel focsed |
| isActive | `boolean` | Is panel active |
| isVisible | `boolean` | Is panel visible |
| width | `number` | Panel width |
| height | `number` | Panel height |
| | |
| onDidDimensionsChange | `Event<PanelDimensionChangeEvent>` | |
| onDidFocusChange | `Event<FocusEvent>` | |
| onDidVisibilityChange | `Event<VisibilityEvent>` | |
| onDidActiveChange | `Event<ActiveEvent>` | |
| onFocusEvent | `Event<void>` | |
| onDidConstraintsChange | `onDidConstraintsChange: Event<PanelConstraintChangeEvent>` | |
| | | |
| setVisible | `(isVisible: boolean): void` | |
| setActive | `(): void` | |
| | | |
| setConstraints | `(value: PanelConstraintChangeEvent2): void;` | |
| setSize | `(event: PanelSizeEvent): void` | |

View File

@ -0,0 +1,33 @@
export interface Page {
title: string;
url?: string;
routes?: Page[];
}
export const PAGES: Page[] = [
{ title: 'Introduction', url: '/#introduction' },
{ title: 'Basics', url: '/basics/#basics' },
{
title: 'API',
url: '#api',
routes: [
{
title: 'Splitview',
url: '/splitview/#splitview',
},
{
title: 'Gridview',
url: '/gridview/#gridview',
},
{
title: 'Dockview',
url: '/dockview/#dockview',
},
{
title: 'Paneview',
url: '/paneview/#paneview',
},
],
},
{ title: 'Guides', url: '#guides' },
];

View File

@ -0,0 +1,72 @@
@import "./navigation.css";
@import "~dockview/dist/styles/dockview.css";
html,
body {
padding: 0;
margin: 0;
/* font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; */
font-family: 'Roboto', sans-serif;
}
a {
text-decoration: none;
color:dodgerblue;
}
a, a:hover, a:visited, a:active {
color:dodgerblue;
}
a:hover {
text-decoration: underline;
}
* {
box-sizing: border-box;
}
.icon {
width: 16px;
height: 16px;
display: inline-block;
margin-left: 8px;
}
.icon-link {
background-image: url(/icon-link.svg);
background-repeat: no-repeat;
background-size: 100%;
background-position: center center;
}
.markdown-body table {
border-collapse: collapse;
border-spacing: 0;
font-size: 12px;
}
.markdown-body td,
.markdown-body th {
padding: 0;
}
.markdown-body table tr {
background-color: rgb(255, 255, 255);
border-top: 1px solid rgb(198, 203, 209);
}
.markdown-body table th {
border:1px solid rgb(223, 226, 229);
padding: 6px 13px;
}
.markdown-body table td {
border:1px solid rgb(223, 226, 229);
padding: 6px 13px;
}
.markdown-body table tr:nth-child(2n) {
background-color: rgb(246, 248, 250);
}

View File

@ -0,0 +1,45 @@
.navigation {
padding: 30px;
background-color: lightgray;
font-size: 16px;
width: 200px;
border-radius: 15px;
}
.node {
padding: 5px 0px;
cursor: pointer;
}
.expandable-node::after {
}
.expanded::after {
border-width: 6px 4px 0px;
border-color: grey transparent transparent;
content: '';
width: 0px;
height: 0px;
border-style: solid;
border-radius: 1px;
display: inline-block;
vertical-align: middle;
margin-left: 10px;
margin-bottom: 2px;
}
.collapsed::after {
border-width: 4px 6px 4px 0px;
border-color: transparent grey transparent;
content: '';
width: 0px;
height: 0px;
border-style: solid;
border-radius: 1px;
display: inline-block;
vertical-align: middle;
margin-left: 10px;
margin-bottom: 2px;
}

View File

@ -0,0 +1,79 @@
import {
GridviewReact,
Orientation,
GridviewReadyEvent,
DockviewReact,
DockviewReadyEvent,
} from 'dockview';
const components = {
default: () => {
return <div>hello world</div>;
},
docking: () => {
return <Test2 />;
},
};
export const Test = () => {
const onReady = (event: GridviewReadyEvent) => {
event.api.addPanel({
component: 'default',
id: 'view_1',
});
event.api.addPanel({
component: 'default',
id: 'view_2',
});
event.api.addPanel({
component: 'docking',
id: 'view_3',
});
};
return (
<GridviewReact
components={components}
orientation={Orientation.HORIZONTAL}
onReady={onReady}
className="dockview-theme-dark"
/>
);
};
const components2 = {
default: () => {
return <div>hello world</div>;
},
};
export const Test2 = () => {
const onReady = (event: DockviewReadyEvent) => {
event.api.addPanel({
component: 'default',
id: 'view_1',
});
event.api.addPanel({
component: 'default',
id: 'view_2',
});
event.api.addPanel({
component: 'default',
id: 'view_3',
});
};
return (
// <div style={{ height: '100%', width: '100%' }}>
<DockviewReact
components={components2}
onReady={onReady}
className="dockview-theme-dark"
/>
// </div>
);
};

View File

@ -0,0 +1,24 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"],
"paths": {
"react": ["node_modules/react"],
"react-dom": ["node_modules/react-dom"]
}
}

File diff suppressed because it is too large Load Diff

8
scripts/package-docs.js Normal file
View File

@ -0,0 +1,8 @@
const fs = require('fs-extra');
const path = require('path');
const output = path.join(__dirname, '../');
const docsDir = path.join(__dirname, '../packages/dockview-docs/out');
fs.copySync(docsDir, path.join(output, 'docs'));

View File

@ -10,6 +10,6 @@ const storybookAppDir = path.join(
'../packages/dockview-demo/storybook-static'
);
fs.copySync(docsDir, path.join(output, 'docs'));
fs.copySync(docsDir, path.join(output, 'typedocs'));
fs.copySync(webpackAppDir, path.join(output, 'build'));
fs.copySync(storybookAppDir, path.join(output, 'storybook-static'));

17824
yarn.lock Normal file

File diff suppressed because it is too large Load Diff