diff --git a/.codesandbox/ci.json b/.codesandbox/ci.json
index fd3d8d2ad..60af87ecb 100644
--- a/.codesandbox/ci.json
+++ b/.codesandbox/ci.json
@@ -6,6 +6,41 @@
"packages/dockview"
],
"sandboxes": [
+ "/packages/docs/sandboxes/constraints-dockview",
+ "/packages/docs/sandboxes/customheader-dockview",
+ "/packages/docs/sandboxes/demo-dockview",
+ "/packages/docs/sandboxes/dnd-dockview",
+ "/packages/docs/sandboxes/dockview-app",
+ "/packages/docs/sandboxes/editor-gridview",
+ "/packages/docs/sandboxes/events-dockview",
+ "/packages/docs/sandboxes/externaldnd-dockview",
+ "/packages/docs/sandboxes/floatinggroup-dockview",
+ "/packages/docs/sandboxes/fullwidthtab-dockview",
+ "/packages/docs/sandboxes/headeractions-dockview",
+ "/packages/docs/sandboxes/groupcontol-dockview",
+ "/packages/docs/sandboxes/iframe-dockview",
+ "/packages/docs/sandboxes/keyboard-dockview",
+ "/packages/docs/sandboxes/layout-dockview",
+ "/packages/docs/sandboxes/lockedgroup-dockview",
+ "/packages/docs/sandboxes/maximizegroup-dockview",
+ "/packages/docs/sandboxes/nativeapp-dockview",
+ "/packages/docs/sandboxes/nested-dockview",
+ "/packages/docs/sandboxes/popoutgroup-dockview",
+ "/packages/docs/sandboxes/rendering-dockview",
+ "/packages/docs/sandboxes/rendermode-dockview",
+ "/packages/docs/sandboxes/resize-dockview",
+ "/packages/docs/sandboxes/resizecontainer-dockview",
+ "/packages/docs/sandboxes/scrollbars-dockview",
+ "/packages/docs/sandboxes/simple-dockview",
+ "/packages/docs/sandboxes/simple-gridview",
+ "/packages/docs/sandboxes/simple-paneview",
+ "/packages/docs/sandboxes/tabheight-dockview",
+ "/packages/docs/sandboxes/updatetitle-dockview",
+ "/packages/docs/sandboxes/watermark-dockview",
+ "/packages/docs/sandboxes/javascript/fullwidthtab-dockview",
+ "/packages/docs/sandboxes/javascript/simple-dockview",
+ "/packages/docs/sandboxes/javascript/tabheight-dockview",
+ "/packages/docs/sandboxes/javascript/vanilla-dockview"
],
"node": "18"
}
diff --git a/packages/docs/sandboxes/customheader-dockview/package.json b/packages/docs/sandboxes/customheader-dockview/package.json
new file mode 100644
index 000000000..d3ede7462
--- /dev/null
+++ b/packages/docs/sandboxes/customheader-dockview/package.json
@@ -0,0 +1,32 @@
+{
+ "name": "customheader-dockview",
+ "description": "",
+ "keywords": [
+ "dockview"
+ ],
+ "version": "1.0.0",
+ "main": "src/index.tsx",
+ "dependencies": {
+ "dockview": "*",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0"
+ },
+ "devDependencies": {
+ "@types/react": "^18.0.28",
+ "@types/react-dom": "^18.0.11",
+ "typescript": "^4.9.5",
+ "react-scripts": "*"
+ },
+ "scripts": {
+ "start": "react-scripts start",
+ "build": "react-scripts build",
+ "test": "react-scripts test --env=jsdom",
+ "eject": "react-scripts eject"
+ },
+ "browserslist": [
+ ">0.2%",
+ "not dead",
+ "not ie <= 11",
+ "not op_mini all"
+ ]
+}
\ No newline at end of file
diff --git a/packages/docs/sandboxes/customheader-dockview/public/index.html b/packages/docs/sandboxes/customheader-dockview/public/index.html
new file mode 100644
index 000000000..1f8a52426
--- /dev/null
+++ b/packages/docs/sandboxes/customheader-dockview/public/index.html
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ React App
+
+
+
+
+
+
+
+
+
diff --git a/packages/docs/sandboxes/customheader-dockview/src/app.tsx b/packages/docs/sandboxes/customheader-dockview/src/app.tsx
new file mode 100644
index 000000000..4106100a7
--- /dev/null
+++ b/packages/docs/sandboxes/customheader-dockview/src/app.tsx
@@ -0,0 +1,122 @@
+import {
+ DockviewDefaultTab,
+ DockviewReact,
+ DockviewReadyEvent,
+ IDockviewPanelHeaderProps,
+ IDockviewPanelProps,
+} from 'dockview';
+import * as React from 'react';
+
+interface CustomProps {
+ valueA: string;
+}
+
+const components = {
+ default: (props: IDockviewPanelProps) => {
+ return {props.api.title}
;
+ },
+};
+
+const headerComponents = {
+ default: (props: IDockviewPanelHeaderProps) => {
+ const onContextMenu = (event: React.MouseEvent) => {
+ event.preventDefault();
+ alert(
+ `This custom header was parsed the params ${JSON.stringify(
+ props.params
+ )}`
+ );
+ };
+ return ;
+ },
+};
+
+const CustomHeadersDockview = (props: { theme?: string }) => {
+ const onReady = (event: DockviewReadyEvent) => {
+ event.api.addPanel({
+ id: 'panel_1',
+ component: 'default',
+ title: 'Panel 1',
+ params: {
+ valueA: 'test value',
+ },
+ });
+ event.api.addPanel({
+ id: 'panel_2',
+ component: 'default',
+ title: 'Panel 2',
+ params: {
+ valueA: 'test value',
+ },
+ });
+ event.api.addPanel({
+ id: 'panel_3',
+ component: 'default',
+ title: 'Panel 3',
+ params: {
+ valueA: 'test value',
+ },
+ });
+ event.api.addPanel({
+ id: 'panel_4',
+ component: 'default',
+ title: 'Panel 4',
+ position: { referencePanel: 'panel_3', direction: 'right' },
+ params: {
+ valueA: 'test value',
+ },
+ });
+ event.api.addPanel({
+ id: 'panel_5',
+ component: 'default',
+ title: 'Panel 5',
+ position: { referencePanel: 'panel_4', direction: 'within' },
+ params: {
+ valueA: 'test value',
+ },
+ });
+ const panel6 = event.api.addPanel({
+ id: 'panel_6',
+ component: 'default',
+ title: 'Panel 6',
+ position: { referencePanel: 'panel_4', direction: 'below' },
+ params: {
+ valueA: 'test value',
+ },
+ });
+ panel6.group.locked = true;
+ panel6.group.header.hidden = true;
+ event.api.addPanel({
+ id: 'panel_7',
+ component: 'default',
+ title: 'Panel 7',
+ position: { referencePanel: 'panel_6', direction: 'right' },
+ params: {
+ valueA: 'test value',
+ },
+ });
+ event.api.addPanel({
+ id: 'panel_8',
+ component: 'default',
+
+ title: 'Panel 8',
+ position: { referencePanel: 'panel_7', direction: 'within' },
+ params: {
+ valueA: 'test value',
+ },
+ });
+
+ event.api.addGroup();
+ };
+
+ return (
+
+ );
+};
+
+export default CustomHeadersDockview;
diff --git a/packages/docs/sandboxes/customheader-dockview/src/index.tsx b/packages/docs/sandboxes/customheader-dockview/src/index.tsx
new file mode 100644
index 000000000..2fe1be232
--- /dev/null
+++ b/packages/docs/sandboxes/customheader-dockview/src/index.tsx
@@ -0,0 +1,20 @@
+import { StrictMode } from 'react';
+import * as ReactDOMClient from 'react-dom/client';
+import './styles.css';
+import 'dockview/dist/styles/dockview.css';
+
+import App from './app';
+
+const rootElement = document.getElementById('root');
+
+if (rootElement) {
+ const root = ReactDOMClient.createRoot(rootElement);
+
+ root.render(
+
+
+
+ );
+}
diff --git a/packages/docs/sandboxes/customheader-dockview/src/styles.css b/packages/docs/sandboxes/customheader-dockview/src/styles.css
new file mode 100644
index 000000000..92b6a1b36
--- /dev/null
+++ b/packages/docs/sandboxes/customheader-dockview/src/styles.css
@@ -0,0 +1,16 @@
+body {
+ margin: 0px;
+ color: white;
+ font-family: sans-serif;
+ text-align: center;
+}
+
+#root {
+ height: 100vh;
+ width: 100vw;
+}
+
+.app {
+ height: 100%;
+
+}
diff --git a/packages/docs/sandboxes/customheader-dockview/tsconfig.json b/packages/docs/sandboxes/customheader-dockview/tsconfig.json
new file mode 100644
index 000000000..cdc4fb5f5
--- /dev/null
+++ b/packages/docs/sandboxes/customheader-dockview/tsconfig.json
@@ -0,0 +1,18 @@
+{
+ "compilerOptions": {
+ "outDir": "build/dist",
+ "module": "esnext",
+ "target": "es5",
+ "lib": ["es6", "dom"],
+ "sourceMap": true,
+ "allowJs": true,
+ "jsx": "react-jsx",
+ "moduleResolution": "node",
+ "rootDir": "src",
+ "forceConsistentCasingInFileNames": true,
+ "noImplicitReturns": true,
+ "noImplicitThis": true,
+ "noImplicitAny": true,
+ "strictNullChecks": true
+ }
+}
diff --git a/packages/docs/sandboxes/react/dockview/constraints/package.json b/packages/docs/sandboxes/react/dockview/constraints/package.json
new file mode 100644
index 000000000..f6d71aac3
--- /dev/null
+++ b/packages/docs/sandboxes/react/dockview/constraints/package.json
@@ -0,0 +1,32 @@
+{
+ "name": "dockview.constraints",
+ "description": "",
+ "keywords": [
+ "dockview"
+ ],
+ "version": "1.0.0",
+ "main": "src/index.tsx",
+ "dependencies": {
+ "dockview": "*",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0"
+ },
+ "devDependencies": {
+ "@types/react": "^18.0.28",
+ "@types/react-dom": "^18.0.11",
+ "typescript": "^4.9.5",
+ "react-scripts": "*"
+ },
+ "scripts": {
+ "start": "react-scripts start",
+ "build": "react-scripts build",
+ "test": "react-scripts test --env=jsdom",
+ "eject": "react-scripts eject"
+ },
+ "browserslist": [
+ ">0.2%",
+ "not dead",
+ "not ie <= 11",
+ "not op_mini all"
+ ]
+}
diff --git a/packages/docs/sandboxes/react/dockview/constraints/public/index.html b/packages/docs/sandboxes/react/dockview/constraints/public/index.html
new file mode 100644
index 000000000..1f8a52426
--- /dev/null
+++ b/packages/docs/sandboxes/react/dockview/constraints/public/index.html
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ React App
+
+
+
+
+
+
+
+
+
diff --git a/packages/docs/sandboxes/react/dockview/constraints/src/app.tsx b/packages/docs/sandboxes/react/dockview/constraints/src/app.tsx
new file mode 100644
index 000000000..7824e03a2
--- /dev/null
+++ b/packages/docs/sandboxes/react/dockview/constraints/src/app.tsx
@@ -0,0 +1,148 @@
+import {
+ DockviewApi,
+ DockviewReact,
+ DockviewReadyEvent,
+ GridConstraintChangeEvent,
+ IDockviewPanelProps,
+} from 'dockview';
+import * as React from 'react';
+
+const components = {
+ default: (props: IDockviewPanelProps) => {
+ const [contraints, setContraints] =
+ React.useState(null);
+
+ React.useEffect(() => {
+ props.api.group.api.onDidConstraintsChange((event) => {
+ setContraints(event);
+ });
+ }, []);
+
+ const onClick = () => {
+ props.api.group.api.setConstraints({
+ maximumWidth: 300,
+ maximumHeight: 300,
+ });
+ };
+
+ return (
+
+
+ {contraints && (
+
+ {typeof contraints.maximumHeight === 'number' && (
+
+ {`Maximum Height: `}
+ {`${contraints.maximumHeight}px`}
+
+ )}
+ {typeof contraints.minimumHeight === 'number' && (
+
+ {`Minimum Height: `}
+ {`${contraints.minimumHeight}px`}
+
+ )}
+ {typeof contraints.maximumWidth === 'number' && (
+
+ {`Maximum Width: `}
+ {`${contraints.maximumWidth}px`}
+
+ )}
+ {typeof contraints.minimumWidth === 'number' && (
+
+ {`Minimum Width: `}
+ {`${contraints.minimumWidth}px`}
+
+ )}
+
+ )}
+
+ );
+ },
+};
+
+const App = (props: { theme?: string }) => {
+ const [api, setApi] = React.useState();
+
+ const onReady = (event: DockviewReadyEvent) => {
+ const panel1 = event.api.addPanel({
+ id: 'panel_1',
+ component: 'default',
+ });
+
+ const panel2 = event.api.addPanel({
+ id: 'panel_2',
+ component: 'default',
+ position: {
+ referencePanel: panel1,
+ direction: 'right',
+ },
+ });
+
+ const panel3 = event.api.addPanel({
+ id: 'panel_3',
+ component: 'default',
+ position: {
+ referencePanel: panel2,
+ direction: 'right',
+ },
+ });
+
+ const panel4 = event.api.addPanel({
+ id: 'panel_4',
+ component: 'default',
+ position: {
+ direction: 'below',
+ },
+ });
+ };
+
+ return (
+
+ );
+};
+
+export default App;
diff --git a/packages/docs/sandboxes/react/dockview/constraints/src/index.tsx b/packages/docs/sandboxes/react/dockview/constraints/src/index.tsx
new file mode 100644
index 000000000..2fe1be232
--- /dev/null
+++ b/packages/docs/sandboxes/react/dockview/constraints/src/index.tsx
@@ -0,0 +1,20 @@
+import { StrictMode } from 'react';
+import * as ReactDOMClient from 'react-dom/client';
+import './styles.css';
+import 'dockview/dist/styles/dockview.css';
+
+import App from './app';
+
+const rootElement = document.getElementById('root');
+
+if (rootElement) {
+ const root = ReactDOMClient.createRoot(rootElement);
+
+ root.render(
+
+
+
+ );
+}
diff --git a/packages/docs/sandboxes/react/dockview/constraints/src/styles.css b/packages/docs/sandboxes/react/dockview/constraints/src/styles.css
new file mode 100644
index 000000000..92b6a1b36
--- /dev/null
+++ b/packages/docs/sandboxes/react/dockview/constraints/src/styles.css
@@ -0,0 +1,16 @@
+body {
+ margin: 0px;
+ color: white;
+ font-family: sans-serif;
+ text-align: center;
+}
+
+#root {
+ height: 100vh;
+ width: 100vw;
+}
+
+.app {
+ height: 100%;
+
+}
diff --git a/packages/docs/sandboxes/react/dockview/constraints/tsconfig.json b/packages/docs/sandboxes/react/dockview/constraints/tsconfig.json
new file mode 100644
index 000000000..cdc4fb5f5
--- /dev/null
+++ b/packages/docs/sandboxes/react/dockview/constraints/tsconfig.json
@@ -0,0 +1,18 @@
+{
+ "compilerOptions": {
+ "outDir": "build/dist",
+ "module": "esnext",
+ "target": "es5",
+ "lib": ["es6", "dom"],
+ "sourceMap": true,
+ "allowJs": true,
+ "jsx": "react-jsx",
+ "moduleResolution": "node",
+ "rootDir": "src",
+ "forceConsistentCasingInFileNames": true,
+ "noImplicitReturns": true,
+ "noImplicitThis": true,
+ "noImplicitAny": true,
+ "strictNullChecks": true
+ }
+}
diff --git a/packages/docs/sandboxes/react/dockview/demo-dockview/package.json b/packages/docs/sandboxes/react/dockview/demo-dockview/package.json
new file mode 100644
index 000000000..a0fb2419f
--- /dev/null
+++ b/packages/docs/sandboxes/react/dockview/demo-dockview/package.json
@@ -0,0 +1,34 @@
+{
+ "name": "dockview.demo",
+ "description": "",
+ "keywords": [
+ "dockview"
+ ],
+ "version": "1.0.0",
+ "main": "src/index.tsx",
+ "dependencies": {
+ "dockview": "*",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0",
+ "uuid": "^9.0.0"
+ },
+ "devDependencies": {
+ "@types/react": "^18.0.28",
+ "@types/react-dom": "^18.0.11",
+ "@types/uuid": "^9.0.0",
+ "typescript": "^4.9.5",
+ "react-scripts": "*"
+ },
+ "scripts": {
+ "start": "react-scripts start",
+ "build": "react-scripts build",
+ "test": "react-scripts test --env=jsdom",
+ "eject": "react-scripts eject"
+ },
+ "browserslist": [
+ ">0.2%",
+ "not dead",
+ "not ie <= 11",
+ "not op_mini all"
+ ]
+}
diff --git a/packages/docs/sandboxes/react/dockview/demo-dockview/public/index.html b/packages/docs/sandboxes/react/dockview/demo-dockview/public/index.html
new file mode 100644
index 000000000..5a4850c1d
--- /dev/null
+++ b/packages/docs/sandboxes/react/dockview/demo-dockview/public/index.html
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ React App
+
+
+
+
+
+
+
+
+
diff --git a/packages/docs/sandboxes/react/dockview/demo-dockview/src/app.scss b/packages/docs/sandboxes/react/dockview/demo-dockview/src/app.scss
new file mode 100644
index 000000000..6abc9a64d
--- /dev/null
+++ b/packages/docs/sandboxes/react/dockview/demo-dockview/src/app.scss
@@ -0,0 +1,96 @@
+.group-control {
+ .action {
+ padding: 4px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ box-sizing: border-box;
+ font-size: 18px;
+ cursor: pointer;
+
+ &:hover {
+ border-radius: 2px;
+ background-color: var(--dv-icon-hover-background-color);
+ }
+ }
+}
+
+.data-table {
+ table {
+ font-size: 11px;
+ th {
+ padding: 0px 8px;
+ }
+ }
+}
+
+.action-container {
+ display: flex;
+ padding: 4px 0px;
+ overflow: auto;
+
+ button {
+ height: 25px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background-color: #1c254a;
+ color: white;
+ border: none;
+ cursor: pointer;
+ outline: 1px solid #4c65d4;
+
+ &:hover {
+ background-color: #222e62;
+ }
+ }
+
+ .text-button {
+ margin: 0px 4px;
+ }
+
+ .button-action {
+ margin: 0px 4px;
+ // display: flex;
+
+ .selected {
+ background-color: #4864dc;
+ }
+ }
+
+ .button-group {
+ button {
+ margin-right: 0px;
+ }
+ }
+
+ .demo-button {
+ min-width: 50px;
+ padding: 0px 2px;
+ border-radius: 0px;
+ display: flex;
+ flex-grow: 1;
+ align-items: center;
+ outline: 1px solid #4c65d4;
+ }
+
+ .demo-icon-button {
+ outline: 1px solid #4c65d4;
+ flex-grow: 1;
+ display: flex;
+ align-items: center;
+ border-radius: 0px;
+ padding: 0px 4px;
+ border: none;
+ cursor: pointer;
+
+ &:disabled {
+ color: gray;
+ cursor: help;
+ }
+
+ span {
+ font-size: 16px;
+ }
+ }
+}
diff --git a/packages/docs/sandboxes/react/dockview/demo-dockview/src/app.tsx b/packages/docs/sandboxes/react/dockview/demo-dockview/src/app.tsx
new file mode 100644
index 000000000..e2449a4ab
--- /dev/null
+++ b/packages/docs/sandboxes/react/dockview/demo-dockview/src/app.tsx
@@ -0,0 +1,431 @@
+import {
+ DockviewDefaultTab,
+ DockviewReact,
+ DockviewReadyEvent,
+ IDockviewPanelHeaderProps,
+ IDockviewPanelProps,
+ DockviewApi,
+} from 'dockview';
+import * as React from 'react';
+import './app.scss';
+import { defaultConfig } from './defaultLayout';
+import { GridActions } from './gridActions';
+import { PanelActions } from './panelActions';
+import { GroupActions } from './groupActions';
+import { LeftControls, PrefixHeaderControls, RightControls } from './controls';
+import { Table, usePanelApiMetadata } from './debugPanel';
+
+const DebugContext = React.createContext(false);
+
+const Option = (props: {
+ title: string;
+ onClick: () => void;
+ value: string;
+}) => {
+ return (
+
+ {`${props.title}: `}
+
+
+ );
+};
+
+const components = {
+ default: (props: IDockviewPanelProps) => {
+ const isDebug = React.useContext(DebugContext);
+ const metadata = usePanelApiMetadata(props.api);
+
+ return (
+
+
+ {props.api.title}
+
+
+ {isDebug && (
+
+
+ )}
+
+ );
+ },
+ nested: (props: IDockviewPanelProps) => {
+ return (
+ {
+ event.api.addPanel({ id: 'panel_1', component: 'default' });
+ event.api.addPanel({ id: 'panel_2', component: 'default' });
+ event.api.addPanel({
+ id: 'panel_3',
+ component: 'default',
+ floating: true,
+ });
+ }}
+ className={'dockview-theme-abyss'}
+ />
+ );
+ },
+ iframe: (props: IDockviewPanelProps) => {
+ return (
+