mirror of
https://github.com/mathuo/dockview
synced 2025-02-12 19:35:45 +00:00
code
This commit is contained in:
parent
62909463ed
commit
9fc0603d61
3
.prettierignore
Normal file
3
.prettierignore
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
typedocs/
|
||||||
|
dist/
|
||||||
|
build/
|
6
.prettierrc
Normal file
6
.prettierrc
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"trailingComma": "es5",
|
||||||
|
"tabWidth": 4,
|
||||||
|
"semi": false,
|
||||||
|
"singleQuote": true
|
||||||
|
}
|
13
.vscode/extensions.json
vendored
Normal file
13
.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
// See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
|
||||||
|
// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
|
||||||
|
|
||||||
|
// List of extensions which should be recommended for users of this workspace.
|
||||||
|
"recommendations": [
|
||||||
|
"esbenp.prettier-vscode"
|
||||||
|
],
|
||||||
|
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
|
||||||
|
"unwantedRecommendations": [
|
||||||
|
|
||||||
|
]
|
||||||
|
}
|
@ -1,16 +1,16 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
transform: {
|
transform: {
|
||||||
"^.+\\.tsx?$": "ts-jest",
|
'^.+\\.tsx?$': 'ts-jest',
|
||||||
},
|
},
|
||||||
testEnvironment: "jsdom",
|
testEnvironment: 'jsdom',
|
||||||
collectCoverageFrom: ["**/*.{ts,tsx}", "!**/node_modules/**"],
|
collectCoverageFrom: ['**/*.{ts,tsx}', '!**/node_modules/**'],
|
||||||
moduleNameMapper: {
|
moduleNameMapper: {
|
||||||
"\\.(css|less|sass|scss)$":
|
'\\.(css|less|sass|scss)$':
|
||||||
"<rootDir>/src/__tests__/__mocks__/styleMock.js",
|
'<rootDir>/src/__tests__/__mocks__/styleMock.js',
|
||||||
},
|
},
|
||||||
testMatch: [
|
testMatch: [
|
||||||
"<rootDir>/src/__tests__/**/*.spec.ts",
|
'<rootDir>/src/__tests__/**/*.spec.ts',
|
||||||
"<rootDir>/src/__tests__/**/*.spec.tsx",
|
'<rootDir>/src/__tests__/**/*.spec.tsx',
|
||||||
],
|
],
|
||||||
setupFilesAfterEnv: ["<rootDir>/src/__tests__/setupTests.ts"],
|
setupFilesAfterEnv: ['<rootDir>/src/__tests__/setupTests.ts'],
|
||||||
};
|
}
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
{
|
{
|
||||||
"packages": [
|
"packages": ["packages/*"],
|
||||||
"packages/*"
|
"version": "0.0.0"
|
||||||
],
|
|
||||||
"version": "0.0.0"
|
|
||||||
}
|
}
|
||||||
|
36436
package-lock.json
generated
36436
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
84
package.json
84
package.json
@ -1,44 +1,44 @@
|
|||||||
{
|
{
|
||||||
"name": "splitview-root",
|
"name": "splitview-root",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git+https://github.com/mathuo/splitview.git"
|
"url": "git+https://github.com/mathuo/splitview.git"
|
||||||
},
|
},
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/mathuo/splitview/issues"
|
"url": "https://github.com/mathuo/splitview/issues"
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/mathuo/splitview#readme",
|
"homepage": "https://github.com/mathuo/splitview#readme",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@testing-library/jest-dom": "^5.10.1",
|
"@testing-library/jest-dom": "^5.10.1",
|
||||||
"@types/jest": "^26.0.3",
|
"@types/jest": "^26.0.3",
|
||||||
"css-loader": "^3.6.0",
|
"css-loader": "^3.6.0",
|
||||||
"gulp": "^4.0.2",
|
"gulp": "^4.0.2",
|
||||||
"gulp-clean": "^0.4.0",
|
"gulp-clean": "^0.4.0",
|
||||||
"gulp-concat": "^2.6.1",
|
"gulp-concat": "^2.6.1",
|
||||||
"gulp-header": "^2.0.9",
|
"gulp-header": "^2.0.9",
|
||||||
"gulp-sass": "^4.1.0",
|
"gulp-sass": "^4.1.0",
|
||||||
"gulp-sourcemaps": "^2.6.5",
|
"gulp-sourcemaps": "^2.6.5",
|
||||||
"gulp-typescript": "^6.0.0-alpha.1",
|
"gulp-typescript": "^6.0.0-alpha.1",
|
||||||
"jest": "^26.1.0",
|
"jest": "^26.1.0",
|
||||||
"jsdom": "^16.2.2",
|
"jsdom": "^16.2.2",
|
||||||
"lerna": "^3.22.1",
|
"lerna": "^3.22.1",
|
||||||
"merge2": "^1.4.1",
|
"merge2": "^1.4.1",
|
||||||
"node-sass": "^4.14.1",
|
"node-sass": "^4.14.1",
|
||||||
"sass-loader": "^8.0.2",
|
"sass-loader": "^8.0.2",
|
||||||
"style-loader": "^1.2.1",
|
"style-loader": "^1.2.1",
|
||||||
"ts-jest": "^26.1.1",
|
"ts-jest": "^26.1.1",
|
||||||
"ts-loader": "^7.0.5",
|
"ts-loader": "^7.0.5",
|
||||||
"typescript": "^3.9.5",
|
"typescript": "^3.9.5",
|
||||||
"webpack": "^4.43.0",
|
"webpack": "^4.43.0",
|
||||||
"webpack-cli": "^3.3.12",
|
"webpack-cli": "^3.3.12",
|
||||||
"webpack-dev-server": "^3.11.0"
|
"webpack-dev-server": "^3.11.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
{
|
{
|
||||||
"name": "splitview-demo",
|
"name": "splitview-demo",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "bash ../../node_modules/.bin/webpack --config webpack.config.js",
|
"build": "bash ../../node_modules/.bin/webpack --config webpack.config.js",
|
||||||
"start": "bash ../../node_modules/.bin/webpack-dev-server --config webpack.config.js"
|
"start": "../../node_modules/.bin/webpack-dev-server --config webpack.config.js"
|
||||||
},
|
},
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"react": "^16.13.1",
|
"react": "^16.13.1",
|
||||||
"react-dom": "^16.13.1",
|
"react-dom": "^16.13.1",
|
||||||
"splitview": "*",
|
"splitview": "*",
|
||||||
"splitview-react": "*"
|
"splitview-react": "*"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/react": "^16.9.41",
|
"@types/react": "^16.9.41",
|
||||||
"@types/react-dom": "^16.9.8"
|
"@types/react-dom": "^16.9.8"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<html>
|
<html>
|
||||||
<body>
|
<body>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
<script src="/dist/bundle.js"></script>
|
<script src="/dist/bundle.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -1,52 +1,52 @@
|
|||||||
import * as React from "react";
|
import * as React from 'react'
|
||||||
// import { LoadFromConfig } from "./loadFromConfig";
|
// import { LoadFromConfig } from "./loadFromConfig";
|
||||||
// import { FromApi } from "./fromApi";
|
// import { FromApi } from "./fromApi";
|
||||||
// import { PaneDemo } from "./pane";
|
// import { PaneDemo } from "./pane";
|
||||||
import { TestGrid } from "./layout-grid/reactgrid";
|
import { TestGrid } from './layout-grid/reactgrid'
|
||||||
import { Application } from "./layout-grid/application";
|
import { Application } from './layout-grid/application'
|
||||||
|
|
||||||
const options = [
|
const options = [
|
||||||
// { id: "config", component: LoadFromConfig },
|
// { id: "config", component: LoadFromConfig },
|
||||||
// { id: "api", component: FromApi },
|
// { id: "api", component: FromApi },
|
||||||
// { id: "pane", component: PaneDemo },
|
// { id: "pane", component: PaneDemo },
|
||||||
{ id: "grid", component: Application },
|
{ id: 'grid', component: Application },
|
||||||
];
|
]
|
||||||
|
|
||||||
export const App = () => {
|
export const App = () => {
|
||||||
const [value, setValue] = React.useState<string>(options[0].id);
|
const [value, setValue] = React.useState<string>(options[0].id)
|
||||||
|
|
||||||
const onChange = (event: React.ChangeEvent<HTMLSelectElement>) =>
|
const onChange = (event: React.ChangeEvent<HTMLSelectElement>) =>
|
||||||
setValue(event.target.value);
|
setValue(event.target.value)
|
||||||
|
|
||||||
const Component = React.useMemo(
|
const Component = React.useMemo(
|
||||||
() => options.find((o) => o.id === value)?.component,
|
() => options.find((o) => o.id === value)?.component,
|
||||||
[value]
|
[value]
|
||||||
);
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
height: "100vh",
|
height: '100vh',
|
||||||
width: "100vw",
|
width: '100vw',
|
||||||
display: "flex",
|
display: 'flex',
|
||||||
flexDirection: "column",
|
flexDirection: 'column',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div style={{ height: "20px", flexShrink: 0 }}>
|
<div style={{ height: '20px', flexShrink: 0 }}>
|
||||||
<select onChange={onChange} value={value}>
|
<select onChange={onChange} value={value}>
|
||||||
{options.map((option, i) => (
|
{options.map((option, i) => (
|
||||||
<option key={i} value={option.id}>
|
<option key={i} value={option.id}>
|
||||||
{option.id}{" "}
|
{option.id}{' '}
|
||||||
</option>
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{Component && (
|
{Component && (
|
||||||
<div style={{ width: "100%", flexGrow: 1 }}>
|
<div style={{ width: '100%', flexGrow: 1 }}>
|
||||||
<Component />
|
<Component />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)
|
||||||
</div>
|
}
|
||||||
);
|
|
||||||
};
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
.header {
|
.header {
|
||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
span {
|
span {
|
||||||
margin-top: auto;
|
margin-top: auto;
|
||||||
margin-bottom: auto;
|
margin-bottom: auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
@import "~splitview/dist/styles.css";
|
@import '~splitview/dist/styles.css';
|
||||||
|
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-family: Arial, "Helvetica Neue", Helvetica, sans-serif;
|
font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
*,
|
*,
|
||||||
*::after,
|
*::after,
|
||||||
*::before {
|
*::before {
|
||||||
// -webkit-user-drag: none;
|
// -webkit-user-drag: none;
|
||||||
-webkit-app-region: no-drag;
|
-webkit-app-region: no-drag;
|
||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import * as React from "react";
|
import * as React from 'react'
|
||||||
import * as ReactDOM from "react-dom";
|
import * as ReactDOM from 'react-dom'
|
||||||
import { App } from "./app";
|
import { App } from './app'
|
||||||
import "./index.scss";
|
import './index.scss'
|
||||||
|
|
||||||
ReactDOM.render(<App />, document.getElementById("app"));
|
ReactDOM.render(<App />, document.getElementById('app'))
|
||||||
|
@ -1,75 +1,83 @@
|
|||||||
import * as React from "react";
|
import * as React from 'react'
|
||||||
import {
|
import {
|
||||||
Orientation,
|
Orientation,
|
||||||
GridviewComponent,
|
GridviewComponent,
|
||||||
LayoutPriority,
|
LayoutPriority,
|
||||||
GridviewReadyEvent,
|
GridviewReadyEvent,
|
||||||
ComponentGridview,
|
ComponentGridview,
|
||||||
IGridviewPanelProps,
|
IGridviewPanelProps,
|
||||||
} from "splitview";
|
} from 'splitview'
|
||||||
import { TestGrid } from "./reactgrid";
|
import { TestGrid } from './reactgrid'
|
||||||
|
|
||||||
const rootcomponents: {
|
const rootcomponents: {
|
||||||
[index: string]: React.FunctionComponent<IGridviewPanelProps>;
|
[index: string]: React.FunctionComponent<IGridviewPanelProps>
|
||||||
} = {
|
} = {
|
||||||
sidebar: (props: IGridviewPanelProps) => {
|
sidebar: (props: IGridviewPanelProps) => {
|
||||||
return <div style={{backgroundColor: "rgb(37,37,38)", height:"100%"}}>sidebar</div>;
|
return (
|
||||||
},
|
<div style={{ backgroundColor: 'rgb(37,37,38)', height: '100%' }}>
|
||||||
editor: TestGrid,
|
sidebar
|
||||||
panel: () => {
|
</div>
|
||||||
return <div style={{backgroundColor: "rgb(30,30,30)", height: "100%"}}>panel</div>;
|
)
|
||||||
},
|
},
|
||||||
};
|
editor: TestGrid,
|
||||||
|
panel: () => {
|
||||||
|
return (
|
||||||
|
<div style={{ backgroundColor: 'rgb(30,30,30)', height: '100%' }}>
|
||||||
|
panel
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
export const Application = () => {
|
export const Application = () => {
|
||||||
const api = React.useRef<ComponentGridview>();
|
const api = React.useRef<ComponentGridview>()
|
||||||
|
|
||||||
const onReady = (event: GridviewReadyEvent) => {
|
const onReady = (event: GridviewReadyEvent) => {
|
||||||
// event.api.deserialize(rootLayout);
|
// event.api.deserialize(rootLayout);
|
||||||
event.api.addComponent({
|
event.api.addComponent({
|
||||||
id: "1",
|
id: '1',
|
||||||
component: "sidebar",
|
component: 'sidebar',
|
||||||
snap: true,
|
snap: true,
|
||||||
});
|
})
|
||||||
event.api.addComponent({
|
event.api.addComponent({
|
||||||
id: "2",
|
id: '2',
|
||||||
component: "editor",
|
component: 'editor',
|
||||||
snap: true,
|
snap: true,
|
||||||
position: { reference: "1", direction: "right" },
|
position: { reference: '1', direction: 'right' },
|
||||||
priority: LayoutPriority.High,
|
priority: LayoutPriority.High,
|
||||||
});
|
})
|
||||||
|
|
||||||
api.current = event.api as ComponentGridview;
|
api.current = event.api as ComponentGridview
|
||||||
};
|
}
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
const callback = (ev: UIEvent) => {
|
const callback = (ev: UIEvent) => {
|
||||||
const height = window.innerHeight - 20;
|
const height = window.innerHeight - 20
|
||||||
const width = window.innerWidth;
|
const width = window.innerWidth
|
||||||
|
|
||||||
api.current?.layout(width, height);
|
api.current?.layout(width, height)
|
||||||
};
|
}
|
||||||
window.addEventListener("resize", callback);
|
window.addEventListener('resize', callback)
|
||||||
callback(undefined);
|
callback(undefined)
|
||||||
|
|
||||||
api.current.addComponent({
|
api.current.addComponent({
|
||||||
id: "3",
|
id: '3',
|
||||||
component: "panel",
|
component: 'panel',
|
||||||
position: { reference: "2", direction: "below" },
|
position: { reference: '2', direction: 'below' },
|
||||||
size: 200,
|
size: 200,
|
||||||
snap: true,
|
snap: true,
|
||||||
});
|
})
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
window.removeEventListener("resize", callback);
|
window.removeEventListener('resize', callback)
|
||||||
};
|
}
|
||||||
}, []);
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<GridviewComponent
|
<GridviewComponent
|
||||||
components={rootcomponents}
|
components={rootcomponents}
|
||||||
onReady={onReady}
|
onReady={onReady}
|
||||||
orientation={Orientation.HORIZONTAL}
|
orientation={Orientation.HORIZONTAL}
|
||||||
/>
|
/>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import * as React from "react";
|
import * as React from 'react'
|
||||||
import { IPanelProps } from "splitview";
|
import { IPanelProps } from 'splitview'
|
||||||
|
|
||||||
export const CustomTab = (props: IPanelProps) => {
|
export const CustomTab = (props: IPanelProps) => {
|
||||||
return <div>hello</div>;
|
return <div>hello</div>
|
||||||
};
|
}
|
||||||
|
@ -1,33 +1,39 @@
|
|||||||
import * as React from "react";
|
import * as React from 'react'
|
||||||
import { Api, IPanelProps } from "splitview";
|
import { Api, IPanelProps } from 'splitview'
|
||||||
|
|
||||||
export const Editor = (props: IPanelProps & { layoutApi: Api }) => {
|
export const Editor = (props: IPanelProps & { layoutApi: Api }) => {
|
||||||
const [tabHeight, setTabHeight] = React.useState<number>(0);
|
const [tabHeight, setTabHeight] = React.useState<number>(0)
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (props.layoutApi) {
|
if (props.layoutApi) {
|
||||||
setTabHeight(props.layoutApi.getTabHeight());
|
setTabHeight(props.layoutApi.getTabHeight())
|
||||||
|
}
|
||||||
|
}, [props.layoutApi])
|
||||||
|
|
||||||
|
const onTabHeightChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const value = Number(event.target.value)
|
||||||
|
if (!Number.isNaN(value)) {
|
||||||
|
setTabHeight(value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, [props.layoutApi]);
|
|
||||||
|
|
||||||
const onTabHeightChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
const onClick = () => {
|
||||||
const value = Number(event.target.value);
|
props.layoutApi.setTabHeight(tabHeight)
|
||||||
if (!Number.isNaN(value)) {
|
|
||||||
setTabHeight(value);
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
const onClick = () => {
|
return (
|
||||||
props.layoutApi.setTabHeight(tabHeight);
|
<div
|
||||||
};
|
style={{ height: '100%', backgroundColor: 'white', color: 'black' }}
|
||||||
|
>
|
||||||
return (
|
<label>
|
||||||
<div style={{ height: "100%", backgroundColor: "white", color: "black" }}>
|
Tab height
|
||||||
<label>
|
<input
|
||||||
Tab height
|
onChange={onTabHeightChange}
|
||||||
<input onChange={onTabHeightChange} value={tabHeight} type="number" />
|
value={tabHeight}
|
||||||
<button onClick={onClick}>Apply</button>
|
type="number"
|
||||||
</label>
|
/>
|
||||||
</div>
|
<button onClick={onClick}>Apply</button>
|
||||||
);
|
</label>
|
||||||
};
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
@ -1,410 +1,425 @@
|
|||||||
import * as React from "react";
|
import * as React from 'react'
|
||||||
import {
|
import {
|
||||||
ReactGrid,
|
ReactGrid,
|
||||||
OnReadyEvent,
|
OnReadyEvent,
|
||||||
Api,
|
Api,
|
||||||
IPanelProps,
|
IPanelProps,
|
||||||
ClosePanelResult,
|
ClosePanelResult,
|
||||||
CompositeDisposable,
|
CompositeDisposable,
|
||||||
GroupChangeKind,
|
GroupChangeKind,
|
||||||
IGridviewPanelProps,
|
IGridviewPanelProps,
|
||||||
TabContextMenuEvent
|
TabContextMenuEvent,
|
||||||
} from "splitview";
|
} from 'splitview'
|
||||||
import { CustomTab } from "./customTab";
|
import { CustomTab } from './customTab'
|
||||||
import { Editor } from "./editorPanel";
|
import { Editor } from './editorPanel'
|
||||||
import { SplitPanel } from "./splitPanel";
|
import { SplitPanel } from './splitPanel'
|
||||||
|
|
||||||
const components = {
|
const components = {
|
||||||
inner_component: (props: IPanelProps) => {
|
inner_component: (props: IPanelProps) => {
|
||||||
const _api = React.useRef<Api>();
|
const _api = React.useRef<Api>()
|
||||||
const [api, setApi] = React.useState<Api>();
|
const [api, setApi] = React.useState<Api>()
|
||||||
|
|
||||||
const onReady = (event: OnReadyEvent) => {
|
const onReady = (event: OnReadyEvent) => {
|
||||||
_api.current = event.api;
|
_api.current = event.api
|
||||||
|
|
||||||
const layout = props.api.getStateKey<object>("layout");
|
const layout = props.api.getStateKey<object>('layout')
|
||||||
if (layout) {
|
if (layout) {
|
||||||
event.api.deserialize(layout);
|
event.api.deserialize(layout)
|
||||||
} else {
|
} else {
|
||||||
event.api.addPanelFromComponent({
|
event.api.addPanelFromComponent({
|
||||||
componentName: "test_component",
|
componentName: 'test_component',
|
||||||
id: "inner-1",
|
id: 'inner-1',
|
||||||
title: "inner-1",
|
title: 'inner-1',
|
||||||
});
|
})
|
||||||
event.api.addPanelFromComponent({
|
event.api.addPanelFromComponent({
|
||||||
componentName: "test_component",
|
componentName: 'test_component',
|
||||||
id: "inner-2",
|
id: 'inner-2',
|
||||||
title: "inner-2",
|
title: 'inner-2',
|
||||||
});
|
})
|
||||||
event.api.addPanelFromComponent({
|
event.api.addPanelFromComponent({
|
||||||
componentName: "test_component",
|
componentName: 'test_component',
|
||||||
id: nextGuid(),
|
id: nextGuid(),
|
||||||
title: "inner-3",
|
title: 'inner-3',
|
||||||
position: { direction: "within", referencePanel: "inner-1" },
|
position: {
|
||||||
});
|
direction: 'within',
|
||||||
event.api.addPanelFromComponent({
|
referencePanel: 'inner-1',
|
||||||
componentName: "test_component",
|
},
|
||||||
id: nextGuid(),
|
})
|
||||||
title: "inner-4",
|
event.api.addPanelFromComponent({
|
||||||
position: { direction: "within", referencePanel: "inner-2" },
|
componentName: 'test_component',
|
||||||
});
|
id: nextGuid(),
|
||||||
}
|
title: 'inner-4',
|
||||||
setApi(event.api);
|
position: {
|
||||||
};
|
direction: 'within',
|
||||||
|
referencePanel: 'inner-2',
|
||||||
React.useEffect(() => {
|
},
|
||||||
const compDis = new CompositeDisposable(
|
})
|
||||||
props.api.onDidDimensionsChange((event) => {
|
}
|
||||||
_api.current?.layout(event.width, event.height);
|
setApi(event.api)
|
||||||
}),
|
|
||||||
_api.current.onDidLayoutChange((event) => {
|
|
||||||
if (event.kind === GroupChangeKind.LAYOUT_CONFIG_UPDATED) {
|
|
||||||
props.api.setState("layout", _api.current.toJSON());
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
compDis.dispose();
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
if (!api) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
api.onDidLayoutChange((event) => {
|
|
||||||
// on inner grid changes
|
|
||||||
});
|
|
||||||
}, [api]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
boxSizing: "border-box",
|
|
||||||
// borderTop: "1px solid var(--splitview-divider-color)",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ReactGrid
|
|
||||||
onReady={onReady}
|
|
||||||
components={components}
|
|
||||||
tabHeight={20}
|
|
||||||
debug={true}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
test_component: (props: IPanelProps & { [key: string]: any }) => {
|
|
||||||
const [panelState, setPanelState] = React.useState<{
|
|
||||||
isGroupActive: boolean;
|
|
||||||
isPanelVisible: boolean;
|
|
||||||
}>({
|
|
||||||
isGroupActive: false,
|
|
||||||
isPanelVisible: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
const disposable = new CompositeDisposable(
|
|
||||||
props.api.onDidFocusChange((event) => {
|
|
||||||
setPanelState((_) => ({ ..._, isGroupActive: event.isFocused }));
|
|
||||||
}),
|
|
||||||
props.api.onDidChangeVisibility((x) => {
|
|
||||||
setPanelState((_) => ({ ..._, isPanelVisible: x.isVisible }));
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
props.api.setClosePanelHook(() => {
|
|
||||||
if (confirm("close?")) {
|
|
||||||
return Promise.resolve(ClosePanelResult.CLOSE);
|
|
||||||
}
|
}
|
||||||
return Promise.resolve(ClosePanelResult.DONT_CLOSE);
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => {
|
React.useEffect(() => {
|
||||||
disposable.dispose();
|
const compDis = new CompositeDisposable(
|
||||||
};
|
props.api.onDidDimensionsChange((event) => {
|
||||||
}, []);
|
_api.current?.layout(event.width, event.height)
|
||||||
|
}),
|
||||||
|
_api.current.onDidLayoutChange((event) => {
|
||||||
|
if (event.kind === GroupChangeKind.LAYOUT_CONFIG_UPDATED) {
|
||||||
|
props.api.setState('layout', _api.current.toJSON())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
const onClick = () => {
|
return () => {
|
||||||
props.api.setState("test_key", "hello");
|
compDis.dispose()
|
||||||
};
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
const backgroundColor = React.useMemo(
|
React.useEffect(() => {
|
||||||
() =>
|
if (!api) {
|
||||||
// "#1e1e1e",
|
return
|
||||||
`rgb(${Math.floor(Math.random() * 256)},${Math.floor(
|
}
|
||||||
Math.random() * 256
|
|
||||||
)},${Math.floor(Math.random() * 256)})`,
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
backgroundColor,
|
|
||||||
height: "100%",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div>test component</div>
|
|
||||||
<button onClick={onClick}>set state</button>
|
|
||||||
{/* {props.api.getState()["test_key"]} */}
|
|
||||||
|
|
||||||
<div>{`G:${panelState.isGroupActive} P:${panelState.isPanelVisible}`}</div>
|
api.onDidLayoutChange((event) => {
|
||||||
<div>{props.text || "-"}</div>
|
// on inner grid changes
|
||||||
</div>
|
})
|
||||||
);
|
}, [api])
|
||||||
},
|
|
||||||
editor: Editor,
|
return (
|
||||||
split_panel: SplitPanel,
|
<div
|
||||||
};
|
style={{
|
||||||
|
boxSizing: 'border-box',
|
||||||
|
// borderTop: "1px solid var(--splitview-divider-color)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ReactGrid
|
||||||
|
onReady={onReady}
|
||||||
|
components={components}
|
||||||
|
tabHeight={20}
|
||||||
|
debug={true}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
test_component: (props: IPanelProps & { [key: string]: any }) => {
|
||||||
|
const [panelState, setPanelState] = React.useState<{
|
||||||
|
isGroupActive: boolean
|
||||||
|
isPanelVisible: boolean
|
||||||
|
}>({
|
||||||
|
isGroupActive: false,
|
||||||
|
isPanelVisible: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
const disposable = new CompositeDisposable(
|
||||||
|
props.api.onDidFocusChange((event) => {
|
||||||
|
setPanelState((_) => ({
|
||||||
|
..._,
|
||||||
|
isGroupActive: event.isFocused,
|
||||||
|
}))
|
||||||
|
}),
|
||||||
|
props.api.onDidChangeVisibility((x) => {
|
||||||
|
setPanelState((_) => ({
|
||||||
|
..._,
|
||||||
|
isPanelVisible: x.isVisible,
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
props.api.setClosePanelHook(() => {
|
||||||
|
if (confirm('close?')) {
|
||||||
|
return Promise.resolve(ClosePanelResult.CLOSE)
|
||||||
|
}
|
||||||
|
return Promise.resolve(ClosePanelResult.DONT_CLOSE)
|
||||||
|
})
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
disposable.dispose()
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const onClick = () => {
|
||||||
|
props.api.setState('test_key', 'hello')
|
||||||
|
}
|
||||||
|
|
||||||
|
const backgroundColor = React.useMemo(
|
||||||
|
() =>
|
||||||
|
// "#1e1e1e",
|
||||||
|
`rgb(${Math.floor(Math.random() * 256)},${Math.floor(
|
||||||
|
Math.random() * 256
|
||||||
|
)},${Math.floor(Math.random() * 256)})`,
|
||||||
|
[]
|
||||||
|
)
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
backgroundColor,
|
||||||
|
height: '100%',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div>test component</div>
|
||||||
|
<button onClick={onClick}>set state</button>
|
||||||
|
{/* {props.api.getState()["test_key"]} */}
|
||||||
|
|
||||||
|
<div>{`G:${panelState.isGroupActive} P:${panelState.isPanelVisible}`}</div>
|
||||||
|
<div>{props.text || '-'}</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
editor: Editor,
|
||||||
|
split_panel: SplitPanel,
|
||||||
|
}
|
||||||
|
|
||||||
const tabComponents = {
|
const tabComponents = {
|
||||||
default: CustomTab,
|
default: CustomTab,
|
||||||
};
|
}
|
||||||
|
|
||||||
const nextGuid = (() => {
|
const nextGuid = (() => {
|
||||||
let counter = 0;
|
let counter = 0
|
||||||
return () => "panel_" + (counter++).toString();
|
return () => 'panel_' + (counter++).toString()
|
||||||
})();
|
})()
|
||||||
|
|
||||||
export const TestGrid = (props: IGridviewPanelProps) => {
|
export const TestGrid = (props: IGridviewPanelProps) => {
|
||||||
const _api = React.useRef<Api>();
|
const _api = React.useRef<Api>()
|
||||||
const [api, setApi] = React.useState<Api>();
|
const [api, setApi] = React.useState<Api>()
|
||||||
|
|
||||||
const onReady = (event: OnReadyEvent) => {
|
const onReady = (event: OnReadyEvent) => {
|
||||||
_api.current = event.api;
|
_api.current = event.api
|
||||||
setApi(event.api);
|
setApi(event.api)
|
||||||
};
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
if (!api) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const panelReference = api.addPanelFromComponent({
|
React.useEffect(() => {
|
||||||
componentName: "test_component",
|
if (!api) {
|
||||||
id: nextGuid(),
|
return
|
||||||
title: "Item 1",
|
}
|
||||||
params: { text: "how low?" },
|
|
||||||
});
|
|
||||||
api.addPanelFromComponent({
|
|
||||||
componentName: "test_component",
|
|
||||||
id: "item2",
|
|
||||||
title: "Item 2",
|
|
||||||
});
|
|
||||||
api.addPanelFromComponent({
|
|
||||||
componentName: "split_panel",
|
|
||||||
id: nextGuid(),
|
|
||||||
title: "Item 3 with a long title",
|
|
||||||
});
|
|
||||||
api.addPanelFromComponent({
|
|
||||||
componentName: "test_component",
|
|
||||||
id: nextGuid(),
|
|
||||||
title: "Item 3",
|
|
||||||
position: { direction: "below", referencePanel: "item2" },
|
|
||||||
suppressClosable: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
// setInterval(() => {
|
const panelReference = api.addPanelFromComponent({
|
||||||
// panelReference.update({ params: { text: `Tick ${Date.now()}` } });
|
componentName: 'test_component',
|
||||||
// // panelReference.remove();
|
id: nextGuid(),
|
||||||
// }, 1000);
|
title: 'Item 1',
|
||||||
|
params: { text: 'how low?' },
|
||||||
|
})
|
||||||
|
api.addPanelFromComponent({
|
||||||
|
componentName: 'test_component',
|
||||||
|
id: 'item2',
|
||||||
|
title: 'Item 2',
|
||||||
|
})
|
||||||
|
api.addPanelFromComponent({
|
||||||
|
componentName: 'split_panel',
|
||||||
|
id: nextGuid(),
|
||||||
|
title: 'Item 3 with a long title',
|
||||||
|
})
|
||||||
|
api.addPanelFromComponent({
|
||||||
|
componentName: 'test_component',
|
||||||
|
id: nextGuid(),
|
||||||
|
title: 'Item 3',
|
||||||
|
position: { direction: 'below', referencePanel: 'item2' },
|
||||||
|
suppressClosable: true,
|
||||||
|
})
|
||||||
|
|
||||||
api.addDndHandle("text/plain", (ev) => {
|
// setInterval(() => {
|
||||||
const { event } = ev;
|
// panelReference.update({ params: { text: `Tick ${Date.now()}` } });
|
||||||
|
// // panelReference.remove();
|
||||||
|
// }, 1000);
|
||||||
|
|
||||||
return {
|
api.addDndHandle('text/plain', (ev) => {
|
||||||
id: "yellow",
|
const { event } = ev
|
||||||
componentName: "test_component",
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
api.addDndHandle("Files", (ev) => {
|
return {
|
||||||
const { event } = ev;
|
id: 'yellow',
|
||||||
|
componentName: 'test_component',
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
ev.event.event.preventDefault();
|
api.addDndHandle('Files', (ev) => {
|
||||||
|
const { event } = ev
|
||||||
|
|
||||||
return {
|
ev.event.event.preventDefault()
|
||||||
id: Date.now().toString(),
|
|
||||||
title: event.event.dataTransfer.files[0].name,
|
|
||||||
componentName: "test_component",
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}, [api]);
|
|
||||||
|
|
||||||
const onAdd = () => {
|
return {
|
||||||
const id = nextGuid();
|
id: Date.now().toString(),
|
||||||
api.addPanelFromComponent({
|
title: event.event.dataTransfer.files[0].name,
|
||||||
componentName: "test_component",
|
componentName: 'test_component',
|
||||||
id,
|
}
|
||||||
});
|
})
|
||||||
};
|
}, [api])
|
||||||
|
|
||||||
const onAddEmpty = () => {
|
const onAdd = () => {
|
||||||
api.addEmptyGroup();
|
const id = nextGuid()
|
||||||
};
|
api.addPanelFromComponent({
|
||||||
|
componentName: 'test_component',
|
||||||
React.useEffect(() => {
|
id,
|
||||||
// const callback = (ev: UIEvent) => {
|
})
|
||||||
// const height = window.innerHeight - 40;
|
|
||||||
// const width = window.innerWidth;
|
|
||||||
|
|
||||||
// _api.current?.layout(width, height);
|
|
||||||
// };
|
|
||||||
// window.addEventListener("resize", callback);
|
|
||||||
// callback(undefined);
|
|
||||||
|
|
||||||
props.api.setConstraints({
|
|
||||||
minimumWidth: () => _api.current.minimumWidth,
|
|
||||||
minimumHeight: () => _api.current.minimumHeight,
|
|
||||||
});
|
|
||||||
|
|
||||||
const disposable = new CompositeDisposable(
|
|
||||||
_api.current.onDidLayoutChange((event) => {
|
|
||||||
console.log(event.kind);
|
|
||||||
}),
|
|
||||||
props.api.onDidDimensionsChange((event) => {
|
|
||||||
const { width, height } = event;
|
|
||||||
_api.current.layout(width, height - 20);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
disposable.dispose();
|
|
||||||
// window.removeEventListener("resize", callback);
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const onConfig = () => {
|
|
||||||
const data = api.toJSON();
|
|
||||||
const stringData = JSON.stringify(data, null, 4);
|
|
||||||
console.log(stringData);
|
|
||||||
localStorage.setItem("layout", stringData);
|
|
||||||
};
|
|
||||||
|
|
||||||
const onLoad = async () => {
|
|
||||||
const didClose = await api.closeAllGroups();
|
|
||||||
if (!didClose) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
const data = localStorage.getItem("layout");
|
|
||||||
if (data) {
|
const onAddEmpty = () => {
|
||||||
const jsonData = JSON.parse(data);
|
api.addEmptyGroup()
|
||||||
api.deserialize(jsonData);
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
const onClear = () => {
|
React.useEffect(() => {
|
||||||
api.closeAllGroups();
|
// const callback = (ev: UIEvent) => {
|
||||||
};
|
// const height = window.innerHeight - 40;
|
||||||
|
// const width = window.innerWidth;
|
||||||
|
|
||||||
const onNextGroup = () => {
|
// _api.current?.layout(width, height);
|
||||||
api.moveToNext({ includePanel: true });
|
// };
|
||||||
};
|
// window.addEventListener("resize", callback);
|
||||||
|
// callback(undefined);
|
||||||
|
|
||||||
const onPreviousGroup = () => {
|
props.api.setConstraints({
|
||||||
api.moveToPrevious({ includePanel: true });
|
minimumWidth: () => _api.current.minimumWidth,
|
||||||
};
|
minimumHeight: () => _api.current.minimumHeight,
|
||||||
|
})
|
||||||
|
|
||||||
const onNextPanel = () => {
|
const disposable = new CompositeDisposable(
|
||||||
api.activeGroup?.moveToNext();
|
_api.current.onDidLayoutChange((event) => {
|
||||||
};
|
console.log(event.kind)
|
||||||
|
}),
|
||||||
|
props.api.onDidDimensionsChange((event) => {
|
||||||
|
const { width, height } = event
|
||||||
|
_api.current.layout(width, height - 20)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
const onPreviousPanel = () => {
|
return () => {
|
||||||
api.activeGroup?.moveToPrevious();
|
disposable.dispose()
|
||||||
};
|
// window.removeEventListener("resize", callback);
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
const dragRef = React.useRef<HTMLDivElement>();
|
const onConfig = () => {
|
||||||
|
const data = api.toJSON()
|
||||||
React.useEffect(() => {
|
const stringData = JSON.stringify(data, null, 4)
|
||||||
if (!api) {
|
console.log(stringData)
|
||||||
return;
|
localStorage.setItem('layout', stringData)
|
||||||
}
|
}
|
||||||
api.createDragTarget(
|
|
||||||
{ element: dragRef.current, content: "drag me" },
|
|
||||||
() => ({
|
|
||||||
id: "yellow",
|
|
||||||
componentName: "test_component",
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}, [api]);
|
|
||||||
|
|
||||||
const onDragStart = (event: React.DragEvent) => {
|
const onLoad = async () => {
|
||||||
event.dataTransfer.setData("text/plain", "Panel2");
|
const didClose = await api.closeAllGroups()
|
||||||
};
|
if (!didClose) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const data = localStorage.getItem('layout')
|
||||||
|
if (data) {
|
||||||
|
const jsonData = JSON.parse(data)
|
||||||
|
api.deserialize(jsonData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const onAddEditor = () => {
|
const onClear = () => {
|
||||||
api.addPanelFromComponent({
|
api.closeAllGroups()
|
||||||
id: "editor",
|
}
|
||||||
componentName: "editor",
|
|
||||||
tabComponentName: "default",
|
|
||||||
params: { layoutApi: api },
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const onTabContextMenu = React.useMemo(() => (event: TabContextMenuEvent) => {
|
const onNextGroup = () => {
|
||||||
console.log(event);
|
api.moveToNext({ includePanel: true })
|
||||||
},[])
|
}
|
||||||
|
|
||||||
return (
|
const onPreviousGroup = () => {
|
||||||
<div
|
api.moveToPrevious({ includePanel: true })
|
||||||
// className="visual-studio-theme"
|
}
|
||||||
style={{ width: "100%", overflow: "hidden" }}
|
|
||||||
>
|
const onNextPanel = () => {
|
||||||
<div
|
api.activeGroup?.moveToNext()
|
||||||
style={{
|
}
|
||||||
height: "20px",
|
|
||||||
display: "flex",
|
const onPreviousPanel = () => {
|
||||||
maxHeight: "20px",
|
api.activeGroup?.moveToPrevious()
|
||||||
minHeight: "20px",
|
}
|
||||||
}}
|
|
||||||
>
|
const dragRef = React.useRef<HTMLDivElement>()
|
||||||
<button onClick={onAdd}>Add</button>
|
|
||||||
<button onClick={onAddEditor}>Expr</button>
|
React.useEffect(() => {
|
||||||
<button onClick={onAddEmpty}>Add empty</button>
|
if (!api) {
|
||||||
<button onClick={onConfig}>Save</button>
|
return
|
||||||
<button onClick={onLoad}>Load</button>
|
}
|
||||||
<button onClick={onClear}>Clear</button>
|
api.createDragTarget(
|
||||||
<button onClick={onNextGroup}>Next</button>
|
{ element: dragRef.current, content: 'drag me' },
|
||||||
<button onClick={onPreviousGroup}>Before</button>
|
() => ({
|
||||||
<button onClick={onNextPanel}>NextPanel</button>
|
id: 'yellow',
|
||||||
<button onClick={onPreviousPanel}>BeforePanel</button>
|
componentName: 'test_component',
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}, [api])
|
||||||
|
|
||||||
|
const onDragStart = (event: React.DragEvent) => {
|
||||||
|
event.dataTransfer.setData('text/plain', 'Panel2')
|
||||||
|
}
|
||||||
|
|
||||||
|
const onAddEditor = () => {
|
||||||
|
api.addPanelFromComponent({
|
||||||
|
id: 'editor',
|
||||||
|
componentName: 'editor',
|
||||||
|
tabComponentName: 'default',
|
||||||
|
params: { layoutApi: api },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const onTabContextMenu = React.useMemo(
|
||||||
|
() => (event: TabContextMenuEvent) => {
|
||||||
|
console.log(event)
|
||||||
|
},
|
||||||
|
[]
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
<div
|
<div
|
||||||
draggable={true}
|
// className="visual-studio-theme"
|
||||||
className="my-dragger"
|
style={{ width: '100%', overflow: 'hidden' }}
|
||||||
style={{
|
|
||||||
backgroundColor: "dodgerblue",
|
|
||||||
borderRadius: "10px",
|
|
||||||
color: " white",
|
|
||||||
}}
|
|
||||||
ref={dragRef}
|
|
||||||
>
|
>
|
||||||
Drag me
|
<div
|
||||||
|
style={{
|
||||||
|
height: '20px',
|
||||||
|
display: 'flex',
|
||||||
|
maxHeight: '20px',
|
||||||
|
minHeight: '20px',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<button onClick={onAdd}>Add</button>
|
||||||
|
<button onClick={onAddEditor}>Expr</button>
|
||||||
|
<button onClick={onAddEmpty}>Add empty</button>
|
||||||
|
<button onClick={onConfig}>Save</button>
|
||||||
|
<button onClick={onLoad}>Load</button>
|
||||||
|
<button onClick={onClear}>Clear</button>
|
||||||
|
<button onClick={onNextGroup}>Next</button>
|
||||||
|
<button onClick={onPreviousGroup}>Before</button>
|
||||||
|
<button onClick={onNextPanel}>NextPanel</button>
|
||||||
|
<button onClick={onPreviousPanel}>BeforePanel</button>
|
||||||
|
<div
|
||||||
|
draggable={true}
|
||||||
|
className="my-dragger"
|
||||||
|
style={{
|
||||||
|
backgroundColor: 'dodgerblue',
|
||||||
|
borderRadius: '10px',
|
||||||
|
color: ' white',
|
||||||
|
}}
|
||||||
|
ref={dragRef}
|
||||||
|
>
|
||||||
|
Drag me
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
onDragStart={onDragStart}
|
||||||
|
draggable={true}
|
||||||
|
className="my-dragger"
|
||||||
|
style={{
|
||||||
|
backgroundColor: 'orange',
|
||||||
|
borderRadius: '10px',
|
||||||
|
color: ' white',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Drag me too
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ReactGrid
|
||||||
|
// autoSizeToFitContainer={true}
|
||||||
|
onReady={onReady}
|
||||||
|
components={components}
|
||||||
|
tabComponents={tabComponents}
|
||||||
|
debug={true}
|
||||||
|
// tabHeight={30}
|
||||||
|
enableExternalDragEvents={true}
|
||||||
|
// serializedLayout={data}
|
||||||
|
onTabContextMenu={onTabContextMenu}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
)
|
||||||
onDragStart={onDragStart}
|
}
|
||||||
draggable={true}
|
|
||||||
className="my-dragger"
|
|
||||||
style={{
|
|
||||||
backgroundColor: "orange",
|
|
||||||
borderRadius: "10px",
|
|
||||||
color: " white",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Drag me too
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<ReactGrid
|
|
||||||
// autoSizeToFitContainer={true}
|
|
||||||
onReady={onReady}
|
|
||||||
components={components}
|
|
||||||
tabComponents={tabComponents}
|
|
||||||
debug={true}
|
|
||||||
// tabHeight={30}
|
|
||||||
enableExternalDragEvents={true}
|
|
||||||
// serializedLayout={data}
|
|
||||||
onTabContextMenu={onTabContextMenu}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
@ -1,88 +1,88 @@
|
|||||||
import * as React from "react";
|
import * as React from 'react'
|
||||||
import {
|
import {
|
||||||
CompositeDisposable,
|
CompositeDisposable,
|
||||||
IPanelProps,
|
IPanelProps,
|
||||||
ISplitviewPanelProps,
|
ISplitviewPanelProps,
|
||||||
Orientation,
|
Orientation,
|
||||||
SplitviewFacade,
|
SplitviewFacade,
|
||||||
SplitviewReadyEvent,
|
SplitviewReadyEvent,
|
||||||
} from "splitview";
|
} from 'splitview'
|
||||||
import { SplitViewComponent } from "splitview";
|
import { SplitViewComponent } from 'splitview'
|
||||||
|
|
||||||
const components = {
|
const components = {
|
||||||
default1: (props: ISplitviewPanelProps) => {
|
default1: (props: ISplitviewPanelProps) => {
|
||||||
const [focused, setFocused] = React.useState<boolean>(false);
|
const [focused, setFocused] = React.useState<boolean>(false)
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
const disposable = new CompositeDisposable(
|
const disposable = new CompositeDisposable(
|
||||||
props.api.onDidFocusChange((event) => {
|
props.api.onDidFocusChange((event) => {
|
||||||
setFocused(event.isFocused);
|
setFocused(event.isFocused)
|
||||||
})
|
})
|
||||||
);
|
)
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
disposable.dispose();
|
disposable.dispose()
|
||||||
};
|
}
|
||||||
}, []);
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{ height: "100%", width: "100%" }}
|
style={{ height: '100%', width: '100%' }}
|
||||||
>{`component [isFocused: ${focused}]`}</div>
|
>{`component [isFocused: ${focused}]`}</div>
|
||||||
);
|
)
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
|
|
||||||
export const SplitPanel = (props: IPanelProps) => {
|
export const SplitPanel = (props: IPanelProps) => {
|
||||||
const api = React.useRef<SplitviewFacade>();
|
const api = React.useRef<SplitviewFacade>()
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
const disposable = new CompositeDisposable(
|
const disposable = new CompositeDisposable(
|
||||||
props.api.onDidDimensionsChange((event) => {
|
props.api.onDidDimensionsChange((event) => {
|
||||||
api.current?.layout(event.width, event.height - 20);
|
api.current?.layout(event.width, event.height - 20)
|
||||||
}),
|
}),
|
||||||
api.current.onChange((event) => {
|
api.current.onChange((event) => {
|
||||||
props.api.setState("sview_layout", api.current.toJSON());
|
props.api.setState('sview_layout', api.current.toJSON())
|
||||||
})
|
})
|
||||||
);
|
)
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
disposable.dispose();
|
disposable.dispose()
|
||||||
};
|
}
|
||||||
}, []);
|
}, [])
|
||||||
|
|
||||||
const onReady = (event: SplitviewReadyEvent) => {
|
const onReady = (event: SplitviewReadyEvent) => {
|
||||||
const existingLayout = props.api.getStateKey("sview_layout");
|
const existingLayout = props.api.getStateKey('sview_layout')
|
||||||
|
|
||||||
if (existingLayout) {
|
if (existingLayout) {
|
||||||
event.api.deserialize(existingLayout);
|
event.api.deserialize(existingLayout)
|
||||||
} else {
|
} else {
|
||||||
event.api.addFromComponent({ id: "1", component: "default1" });
|
event.api.addFromComponent({ id: '1', component: 'default1' })
|
||||||
event.api.addFromComponent({ id: "2", component: "default1" });
|
event.api.addFromComponent({ id: '2', component: 'default1' })
|
||||||
|
}
|
||||||
|
api.current = event.api
|
||||||
}
|
}
|
||||||
api.current = event.api;
|
|
||||||
};
|
|
||||||
|
|
||||||
const onSave = () => {
|
const onSave = () => {
|
||||||
props.api.setState("sview_layout", api.current.toJSON());
|
props.api.setState('sview_layout', api.current.toJSON())
|
||||||
};
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: "flex",
|
display: 'flex',
|
||||||
flexDirection: "column",
|
flexDirection: 'column',
|
||||||
height: "100%",
|
height: '100%',
|
||||||
color: "white",
|
color: 'white',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div style={{ height: "20px", flexShrink: 0 }}>
|
<div style={{ height: '20px', flexShrink: 0 }}>
|
||||||
<button onClick={onSave}>save</button>
|
<button onClick={onSave}>save</button>
|
||||||
</div>
|
</div>
|
||||||
<SplitViewComponent
|
<SplitViewComponent
|
||||||
components={components}
|
components={components}
|
||||||
onReady={onReady}
|
onReady={onReady}
|
||||||
orientation={Orientation.VERTICAL}
|
orientation={Orientation.VERTICAL}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"extends": "../../tsconfig.build.json",
|
"extends": "../../tsconfig.build.json",
|
||||||
|
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"composite": true,
|
"composite": true,
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"outDir": "./dist",
|
"outDir": "./dist",
|
||||||
"rootDir": "./src"
|
"rootDir": "./src"
|
||||||
},
|
},
|
||||||
"include": ["src/**/*"]
|
"include": ["src/**/*"]
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"extends": "../../tsconfig.json",
|
"extends": "../../tsconfig.json",
|
||||||
"exclude": ["**/node_modules", "src/__tests__"]
|
"exclude": ["**/node_modules", "src/__tests__"]
|
||||||
}
|
}
|
||||||
|
@ -1,53 +1,53 @@
|
|||||||
var path = require("path");
|
var path = require('path')
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
entry: path.resolve(__dirname, "src/index.tsx"),
|
entry: path.resolve(__dirname, 'src/index.tsx'),
|
||||||
devtool: "source-map",
|
devtool: 'source-map',
|
||||||
output: {
|
output: {
|
||||||
filename: "bundle.js",
|
filename: 'bundle.js',
|
||||||
path: path.resolve(__dirname, "dist"),
|
path: path.resolve(__dirname, 'dist'),
|
||||||
},
|
|
||||||
mode: "development",
|
|
||||||
resolve: {
|
|
||||||
extensions: [".ts", ".js", ".tsx", "jsx"],
|
|
||||||
alias: {
|
|
||||||
react: path.resolve(__dirname, "node_modules/react"),
|
|
||||||
"react-dom": path.resolve(__dirname, "node_modules/react-dom"),
|
|
||||||
},
|
},
|
||||||
},
|
mode: 'development',
|
||||||
module: {
|
resolve: {
|
||||||
rules: [
|
extensions: ['.ts', '.js', '.tsx', 'jsx'],
|
||||||
{
|
alias: {
|
||||||
test: /\.tsx?$/,
|
react: path.resolve(__dirname, 'node_modules/react'),
|
||||||
loader: "ts-loader",
|
'react-dom': path.resolve(__dirname, 'node_modules/react-dom'),
|
||||||
options: { configFile: "tsconfig.build.json" },
|
},
|
||||||
},
|
},
|
||||||
{
|
module: {
|
||||||
test: /\.s[ac]ss$/i,
|
rules: [
|
||||||
use: [
|
{
|
||||||
// Creates `style` nodes from JS strings
|
test: /\.tsx?$/,
|
||||||
"style-loader",
|
loader: 'ts-loader',
|
||||||
// Translates CSS into CommonJS
|
options: { configFile: 'tsconfig.build.json' },
|
||||||
"css-loader",
|
},
|
||||||
// Compiles Sass to CSS
|
{
|
||||||
"sass-loader",
|
test: /\.s[ac]ss$/i,
|
||||||
|
use: [
|
||||||
|
// Creates `style` nodes from JS strings
|
||||||
|
'style-loader',
|
||||||
|
// Translates CSS into CommonJS
|
||||||
|
'css-loader',
|
||||||
|
// Compiles Sass to CSS
|
||||||
|
'sass-loader',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.css$/i,
|
||||||
|
use: [
|
||||||
|
// Creates `style` nodes from JS strings
|
||||||
|
'style-loader',
|
||||||
|
// Translates CSS into CommonJS
|
||||||
|
'css-loader',
|
||||||
|
],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
devServer: {
|
||||||
test: /\.css$/i,
|
port: 9000,
|
||||||
use: [
|
compress: true,
|
||||||
// Creates `style` nodes from JS strings
|
contentBase: path.resolve(__dirname, 'public'),
|
||||||
"style-loader",
|
publicPath: '/dist',
|
||||||
// Translates CSS into CommonJS
|
},
|
||||||
"css-loader",
|
}
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
devServer: {
|
|
||||||
port: 9000,
|
|
||||||
compress: true,
|
|
||||||
contentBase: path.resolve(__dirname, "public"),
|
|
||||||
publicPath: "/dist",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
const gulp = require("gulp");
|
const gulp = require('gulp')
|
||||||
const buildfile = require("../../scripts/build");
|
const buildfile = require('../../scripts/build')
|
||||||
const package = require("./package");
|
const package = require('./package')
|
||||||
|
|
||||||
buildfile.build({ tsconfig: "./tsconfig.build.json", package });
|
buildfile.build({ tsconfig: './tsconfig.build.json', package })
|
||||||
|
|
||||||
gulp.task("run", gulp.series(["clean", "esm", "sass"]));
|
gulp.task('run', gulp.series(['clean', 'esm', 'sass']))
|
||||||
|
862
packages/splitview-react/package-lock.json
generated
862
packages/splitview-react/package-lock.json
generated
@ -1,433 +1,433 @@
|
|||||||
{
|
{
|
||||||
"name": "splitview-react",
|
"name": "splitview-react",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": {
|
"@babel/code-frame": {
|
||||||
"version": "7.10.4",
|
"version": "7.10.4",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz",
|
||||||
"integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==",
|
"integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/highlight": "^7.10.4"
|
"@babel/highlight": "^7.10.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@babel/helper-validator-identifier": {
|
"@babel/helper-validator-identifier": {
|
||||||
"version": "7.10.4",
|
"version": "7.10.4",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz",
|
||||||
"integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==",
|
"integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@babel/highlight": {
|
"@babel/highlight": {
|
||||||
"version": "7.10.4",
|
"version": "7.10.4",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz",
|
||||||
"integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==",
|
"integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/helper-validator-identifier": "^7.10.4",
|
"@babel/helper-validator-identifier": "^7.10.4",
|
||||||
"chalk": "^2.0.0",
|
"chalk": "^2.0.0",
|
||||||
"js-tokens": "^4.0.0"
|
"js-tokens": "^4.0.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chalk": {
|
"chalk": {
|
||||||
"version": "2.4.2",
|
"version": "2.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||||
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"ansi-styles": "^3.2.1",
|
"ansi-styles": "^3.2.1",
|
||||||
"escape-string-regexp": "^1.0.5",
|
"escape-string-regexp": "^1.0.5",
|
||||||
"supports-color": "^5.3.0"
|
"supports-color": "^5.3.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@babel/runtime": {
|
"@babel/runtime": {
|
||||||
"version": "7.11.2",
|
"version": "7.11.2",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.11.2.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.11.2.tgz",
|
||||||
"integrity": "sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw==",
|
"integrity": "sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"regenerator-runtime": "^0.13.4"
|
"regenerator-runtime": "^0.13.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@babel/runtime-corejs3": {
|
"@babel/runtime-corejs3": {
|
||||||
"version": "7.11.2",
|
"version": "7.11.2",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.11.2.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.11.2.tgz",
|
||||||
"integrity": "sha512-qh5IR+8VgFz83VBa6OkaET6uN/mJOhHONuy3m1sgF0CV6mXdPSEBdA7e1eUbVvyNtANjMbg22JUv71BaDXLY6A==",
|
"integrity": "sha512-qh5IR+8VgFz83VBa6OkaET6uN/mJOhHONuy3m1sgF0CV6mXdPSEBdA7e1eUbVvyNtANjMbg22JUv71BaDXLY6A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"core-js-pure": "^3.0.0",
|
"core-js-pure": "^3.0.0",
|
||||||
"regenerator-runtime": "^0.13.4"
|
"regenerator-runtime": "^0.13.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@jest/types": {
|
"@jest/types": {
|
||||||
"version": "26.3.0",
|
"version": "26.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/@jest/types/-/types-26.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@jest/types/-/types-26.3.0.tgz",
|
||||||
"integrity": "sha512-BDPG23U0qDeAvU4f99haztXwdAg3hz4El95LkAM+tHAqqhiVzRpEGHHU8EDxT/AnxOrA65YjLBwDahdJ9pTLJQ==",
|
"integrity": "sha512-BDPG23U0qDeAvU4f99haztXwdAg3hz4El95LkAM+tHAqqhiVzRpEGHHU8EDxT/AnxOrA65YjLBwDahdJ9pTLJQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/istanbul-lib-coverage": "^2.0.0",
|
"@types/istanbul-lib-coverage": "^2.0.0",
|
||||||
"@types/istanbul-reports": "^3.0.0",
|
"@types/istanbul-reports": "^3.0.0",
|
||||||
"@types/node": "*",
|
"@types/node": "*",
|
||||||
"@types/yargs": "^15.0.0",
|
"@types/yargs": "^15.0.0",
|
||||||
"chalk": "^4.0.0"
|
"chalk": "^4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@testing-library/dom": {
|
"@testing-library/dom": {
|
||||||
"version": "7.24.2",
|
"version": "7.24.2",
|
||||||
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-7.24.2.tgz",
|
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-7.24.2.tgz",
|
||||||
"integrity": "sha512-ERxcZSoHx0EcN4HfshySEWmEf5Kkmgi+J7O79yCJ3xggzVlBJ2w/QjJUC+EBkJJ2OeSw48i3IoePN4w8JlVUIA==",
|
"integrity": "sha512-ERxcZSoHx0EcN4HfshySEWmEf5Kkmgi+J7O79yCJ3xggzVlBJ2w/QjJUC+EBkJJ2OeSw48i3IoePN4w8JlVUIA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/code-frame": "^7.10.4",
|
"@babel/code-frame": "^7.10.4",
|
||||||
"@babel/runtime": "^7.10.3",
|
"@babel/runtime": "^7.10.3",
|
||||||
"@types/aria-query": "^4.2.0",
|
"@types/aria-query": "^4.2.0",
|
||||||
"aria-query": "^4.2.2",
|
"aria-query": "^4.2.2",
|
||||||
"chalk": "^4.1.0",
|
"chalk": "^4.1.0",
|
||||||
"dom-accessibility-api": "^0.5.1",
|
"dom-accessibility-api": "^0.5.1",
|
||||||
"pretty-format": "^26.4.2"
|
"pretty-format": "^26.4.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@testing-library/react": {
|
"@testing-library/react": {
|
||||||
"version": "10.4.9",
|
"version": "10.4.9",
|
||||||
"resolved": "https://registry.npmjs.org/@testing-library/react/-/react-10.4.9.tgz",
|
"resolved": "https://registry.npmjs.org/@testing-library/react/-/react-10.4.9.tgz",
|
||||||
"integrity": "sha512-pHZKkqUy0tmiD81afs8xfiuseXfU/N7rAX3iKjeZYje86t9VaB0LrxYVa+OOsvkrveX5jCK3IjajVn2MbePvqA==",
|
"integrity": "sha512-pHZKkqUy0tmiD81afs8xfiuseXfU/N7rAX3iKjeZYje86t9VaB0LrxYVa+OOsvkrveX5jCK3IjajVn2MbePvqA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/runtime": "^7.10.3",
|
"@babel/runtime": "^7.10.3",
|
||||||
"@testing-library/dom": "^7.22.3"
|
"@testing-library/dom": "^7.22.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/aria-query": {
|
"@types/aria-query": {
|
||||||
"version": "4.2.0",
|
"version": "4.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.0.tgz",
|
||||||
"integrity": "sha512-iIgQNzCm0v7QMhhe4Jjn9uRh+I6GoPmt03CbEtwx3ao8/EfoQcmgtqH4vQ5Db/lxiIGaWDv6nwvunuh0RyX0+A==",
|
"integrity": "sha512-iIgQNzCm0v7QMhhe4Jjn9uRh+I6GoPmt03CbEtwx3ao8/EfoQcmgtqH4vQ5Db/lxiIGaWDv6nwvunuh0RyX0+A==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/color-name": {
|
"@types/color-name": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
|
||||||
"integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==",
|
"integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/istanbul-lib-coverage": {
|
"@types/istanbul-lib-coverage": {
|
||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz",
|
||||||
"integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==",
|
"integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/istanbul-lib-report": {
|
"@types/istanbul-lib-report": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz",
|
||||||
"integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==",
|
"integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/istanbul-lib-coverage": "*"
|
"@types/istanbul-lib-coverage": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/istanbul-reports": {
|
"@types/istanbul-reports": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz",
|
||||||
"integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==",
|
"integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/istanbul-lib-report": "*"
|
"@types/istanbul-lib-report": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/node": {
|
"@types/node": {
|
||||||
"version": "14.10.2",
|
"version": "14.10.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.10.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.10.2.tgz",
|
||||||
"integrity": "sha512-IzMhbDYCpv26pC2wboJ4MMOa9GKtjplXfcAqrMeNJpUUwpM/2ATt2w1JPUXwS6spu856TvKZL2AOmeU2rAxskw==",
|
"integrity": "sha512-IzMhbDYCpv26pC2wboJ4MMOa9GKtjplXfcAqrMeNJpUUwpM/2ATt2w1JPUXwS6spu856TvKZL2AOmeU2rAxskw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/prop-types": {
|
"@types/prop-types": {
|
||||||
"version": "15.7.3",
|
"version": "15.7.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz",
|
||||||
"integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==",
|
"integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/react": {
|
"@types/react": {
|
||||||
"version": "16.9.49",
|
"version": "16.9.49",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.49.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.49.tgz",
|
||||||
"integrity": "sha512-DtLFjSj0OYAdVLBbyjhuV9CdGVHCkHn2R+xr3XkBvK2rS1Y1tkc14XSGjYgm5Fjjr90AxH9tiSzc1pCFMGO06g==",
|
"integrity": "sha512-DtLFjSj0OYAdVLBbyjhuV9CdGVHCkHn2R+xr3XkBvK2rS1Y1tkc14XSGjYgm5Fjjr90AxH9tiSzc1pCFMGO06g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/prop-types": "*",
|
"@types/prop-types": "*",
|
||||||
"csstype": "^3.0.2"
|
"csstype": "^3.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/react-dom": {
|
"@types/react-dom": {
|
||||||
"version": "16.9.8",
|
"version": "16.9.8",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.8.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.8.tgz",
|
||||||
"integrity": "sha512-ykkPQ+5nFknnlU6lDd947WbQ6TE3NNzbQAkInC2EKY1qeYdTKp7onFusmYZb+ityzx2YviqT6BXSu+LyWWJwcA==",
|
"integrity": "sha512-ykkPQ+5nFknnlU6lDd947WbQ6TE3NNzbQAkInC2EKY1qeYdTKp7onFusmYZb+ityzx2YviqT6BXSu+LyWWJwcA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/react": "*"
|
"@types/react": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/yargs": {
|
"@types/yargs": {
|
||||||
"version": "15.0.5",
|
"version": "15.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.5.tgz",
|
||||||
"integrity": "sha512-Dk/IDOPtOgubt/IaevIUbTgV7doaKkoorvOyYM2CMwuDyP89bekI7H4xLIwunNYiK9jhCkmc6pUrJk3cj2AB9w==",
|
"integrity": "sha512-Dk/IDOPtOgubt/IaevIUbTgV7doaKkoorvOyYM2CMwuDyP89bekI7H4xLIwunNYiK9jhCkmc6pUrJk3cj2AB9w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/yargs-parser": "*"
|
"@types/yargs-parser": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/yargs-parser": {
|
"@types/yargs-parser": {
|
||||||
"version": "15.0.0",
|
"version": "15.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-15.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-15.0.0.tgz",
|
||||||
"integrity": "sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==",
|
"integrity": "sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"ansi-regex": {
|
"ansi-regex": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
|
||||||
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
|
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"ansi-styles": {
|
"ansi-styles": {
|
||||||
"version": "3.2.1",
|
"version": "3.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"color-convert": "^1.9.0"
|
"color-convert": "^1.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"aria-query": {
|
"aria-query": {
|
||||||
"version": "4.2.2",
|
"version": "4.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz",
|
||||||
"integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==",
|
"integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/runtime": "^7.10.2",
|
"@babel/runtime": "^7.10.2",
|
||||||
"@babel/runtime-corejs3": "^7.10.2"
|
"@babel/runtime-corejs3": "^7.10.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"chalk": {
|
"chalk": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
|
||||||
"integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
|
"integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"ansi-styles": "^4.1.0",
|
"ansi-styles": "^4.1.0",
|
||||||
"supports-color": "^7.1.0"
|
"supports-color": "^7.1.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ansi-styles": {
|
"ansi-styles": {
|
||||||
"version": "4.2.1",
|
"version": "4.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
|
||||||
"integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
|
"integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/color-name": "^1.1.1",
|
"@types/color-name": "^1.1.1",
|
||||||
"color-convert": "^2.0.1"
|
"color-convert": "^2.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"color-convert": {
|
"color-convert": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"color-name": "~1.1.4"
|
"color-name": "~1.1.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"color-name": {
|
"color-name": {
|
||||||
"version": "1.1.4",
|
"version": "1.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"has-flag": {
|
"has-flag": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"supports-color": {
|
"supports-color": {
|
||||||
"version": "7.2.0",
|
"version": "7.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||||
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"has-flag": "^4.0.0"
|
"has-flag": "^4.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"color-convert": {
|
"color-convert": {
|
||||||
"version": "1.9.3",
|
"version": "1.9.3",
|
||||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"color-name": "1.1.3"
|
"color-name": "1.1.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"color-name": {
|
"color-name": {
|
||||||
"version": "1.1.3",
|
"version": "1.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||||
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
|
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"core-js-pure": {
|
"core-js-pure": {
|
||||||
"version": "3.6.5",
|
"version": "3.6.5",
|
||||||
"resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.6.5.tgz",
|
"resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.6.5.tgz",
|
||||||
"integrity": "sha512-lacdXOimsiD0QyNf9BC/mxivNJ/ybBGJXQFKzRekp1WTHoVUWsUHEn+2T8GJAzzIhyOuXA+gOxCVN3l+5PLPUA==",
|
"integrity": "sha512-lacdXOimsiD0QyNf9BC/mxivNJ/ybBGJXQFKzRekp1WTHoVUWsUHEn+2T8GJAzzIhyOuXA+gOxCVN3l+5PLPUA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"csstype": {
|
"csstype": {
|
||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.3.tgz",
|
||||||
"integrity": "sha512-jPl+wbWPOWJ7SXsWyqGRk3lGecbar0Cb0OvZF/r/ZU011R4YqiRehgkQ9p4eQfo9DSDLqLL3wHwfxeJiuIsNag==",
|
"integrity": "sha512-jPl+wbWPOWJ7SXsWyqGRk3lGecbar0Cb0OvZF/r/ZU011R4YqiRehgkQ9p4eQfo9DSDLqLL3wHwfxeJiuIsNag==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"dom-accessibility-api": {
|
"dom-accessibility-api": {
|
||||||
"version": "0.5.2",
|
"version": "0.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.2.tgz",
|
||||||
"integrity": "sha512-k7hRNKAiPJXD2aBqfahSo4/01cTsKWXf+LqJgglnkN2Nz8TsxXKQBXHhKe0Ye9fEfHEZY49uSA5Sr3AqP/sWKA==",
|
"integrity": "sha512-k7hRNKAiPJXD2aBqfahSo4/01cTsKWXf+LqJgglnkN2Nz8TsxXKQBXHhKe0Ye9fEfHEZY49uSA5Sr3AqP/sWKA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"escape-string-regexp": {
|
"escape-string-regexp": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||||
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
|
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"has-flag": {
|
"has-flag": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||||
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
|
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"js-tokens": {
|
"js-tokens": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"loose-envify": {
|
"loose-envify": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||||
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"js-tokens": "^3.0.0 || ^4.0.0"
|
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"object-assign": {
|
"object-assign": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||||
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
|
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"pretty-format": {
|
"pretty-format": {
|
||||||
"version": "26.4.2",
|
"version": "26.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.4.2.tgz",
|
||||||
"integrity": "sha512-zK6Gd8zDsEiVydOCGLkoBoZuqv8VTiHyAbKznXe/gaph/DAeZOmit9yMfgIz5adIgAMMs5XfoYSwAX3jcCO1tA==",
|
"integrity": "sha512-zK6Gd8zDsEiVydOCGLkoBoZuqv8VTiHyAbKznXe/gaph/DAeZOmit9yMfgIz5adIgAMMs5XfoYSwAX3jcCO1tA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@jest/types": "^26.3.0",
|
"@jest/types": "^26.3.0",
|
||||||
"ansi-regex": "^5.0.0",
|
"ansi-regex": "^5.0.0",
|
||||||
"ansi-styles": "^4.0.0",
|
"ansi-styles": "^4.0.0",
|
||||||
"react-is": "^16.12.0"
|
"react-is": "^16.12.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ansi-styles": {
|
"ansi-styles": {
|
||||||
"version": "4.2.1",
|
"version": "4.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
|
||||||
"integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
|
"integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/color-name": "^1.1.1",
|
"@types/color-name": "^1.1.1",
|
||||||
"color-convert": "^2.0.1"
|
"color-convert": "^2.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"color-convert": {
|
"color-convert": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"color-name": "~1.1.4"
|
"color-name": "~1.1.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"color-name": {
|
"color-name": {
|
||||||
"version": "1.1.4",
|
"version": "1.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"prop-types": {
|
"prop-types": {
|
||||||
"version": "15.7.2",
|
"version": "15.7.2",
|
||||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
|
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
|
||||||
"integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
|
"integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"loose-envify": "^1.4.0",
|
"loose-envify": "^1.4.0",
|
||||||
"object-assign": "^4.1.1",
|
"object-assign": "^4.1.1",
|
||||||
"react-is": "^16.8.1"
|
"react-is": "^16.8.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react": {
|
"react": {
|
||||||
"version": "16.13.1",
|
"version": "16.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/react/-/react-16.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/react/-/react-16.13.1.tgz",
|
||||||
"integrity": "sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w==",
|
"integrity": "sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"loose-envify": "^1.1.0",
|
"loose-envify": "^1.1.0",
|
||||||
"object-assign": "^4.1.1",
|
"object-assign": "^4.1.1",
|
||||||
"prop-types": "^15.6.2"
|
"prop-types": "^15.6.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react-dom": {
|
"react-dom": {
|
||||||
"version": "16.13.1",
|
"version": "16.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.13.1.tgz",
|
||||||
"integrity": "sha512-81PIMmVLnCNLO/fFOQxdQkvEq/+Hfpv24XNJfpyZhTRfO0QcmQIF/PgCa1zCOj2w1hrn12MFLyaJ/G0+Mxtfag==",
|
"integrity": "sha512-81PIMmVLnCNLO/fFOQxdQkvEq/+Hfpv24XNJfpyZhTRfO0QcmQIF/PgCa1zCOj2w1hrn12MFLyaJ/G0+Mxtfag==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"loose-envify": "^1.1.0",
|
"loose-envify": "^1.1.0",
|
||||||
"object-assign": "^4.1.1",
|
"object-assign": "^4.1.1",
|
||||||
"prop-types": "^15.6.2",
|
"prop-types": "^15.6.2",
|
||||||
"scheduler": "^0.19.1"
|
"scheduler": "^0.19.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react-is": {
|
"react-is": {
|
||||||
"version": "16.13.1",
|
"version": "16.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"regenerator-runtime": {
|
"regenerator-runtime": {
|
||||||
"version": "0.13.7",
|
"version": "0.13.7",
|
||||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz",
|
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz",
|
||||||
"integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==",
|
"integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"scheduler": {
|
"scheduler": {
|
||||||
"version": "0.19.1",
|
"version": "0.19.1",
|
||||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz",
|
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz",
|
||||||
"integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==",
|
"integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"loose-envify": "^1.1.0",
|
"loose-envify": "^1.1.0",
|
||||||
"object-assign": "^4.1.1"
|
"object-assign": "^4.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"supports-color": {
|
"supports-color": {
|
||||||
"version": "5.5.0",
|
"version": "5.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"has-flag": "^3.0.0"
|
"has-flag": "^3.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,26 +1,26 @@
|
|||||||
{
|
{
|
||||||
"name": "splitview-react",
|
"name": "splitview-react",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "dist/esm/index.js",
|
"main": "dist/esm/index.js",
|
||||||
"types": "dist/esm/index.d.ts",
|
"types": "dist/esm/index.d.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
},
|
},
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"splitview": "*"
|
"splitview": "*"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@testing-library/react": "^10.4.2",
|
"@testing-library/react": "^10.4.2",
|
||||||
"@types/react": "^16.9.41",
|
"@types/react": "^16.9.41",
|
||||||
"@types/react-dom": "^16.9.8",
|
"@types/react-dom": "^16.9.8",
|
||||||
"react": "^16.13.1",
|
"react": "^16.13.1",
|
||||||
"react-dom": "^16.13.1"
|
"react-dom": "^16.13.1"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^16.x",
|
"react": "^16.x",
|
||||||
"react-dom": "^16.x"
|
"react-dom": "^16.x"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,117 +1,121 @@
|
|||||||
import * as React from "react";
|
import * as React from 'react'
|
||||||
import { Orientation } from "splitview";
|
import { Orientation } from 'splitview'
|
||||||
import { IViewWithReactComponent } from "../splitview";
|
import { IViewWithReactComponent } from '../splitview'
|
||||||
|
|
||||||
// component view
|
// component view
|
||||||
|
|
||||||
export interface IPaneComponentProps extends IViewWithReactComponent {
|
export interface IPaneComponentProps extends IViewWithReactComponent {
|
||||||
setExpanded(expanded: boolean): void;
|
setExpanded(expanded: boolean): void
|
||||||
orientation: Orientation;
|
orientation: Orientation
|
||||||
size: number;
|
size: number
|
||||||
orthogonalSize: number;
|
orthogonalSize: number
|
||||||
userprops?: { [index: string]: any };
|
userprops?: { [index: string]: any }
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPaneComponentRef {
|
export interface IPaneComponentRef {
|
||||||
layout: (size: number, orthogonalSize: number) => void;
|
layout: (size: number, orthogonalSize: number) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PaneComponent = React.ForwardRefRenderFunction<
|
export type PaneComponent = React.ForwardRefRenderFunction<
|
||||||
IPaneComponentRef,
|
IPaneComponentRef,
|
||||||
IPaneComponentProps
|
IPaneComponentProps
|
||||||
>;
|
>
|
||||||
|
|
||||||
export interface IPaneHeaderComponentProps extends IViewWithReactComponent {
|
export interface IPaneHeaderComponentProps extends IViewWithReactComponent {
|
||||||
setExpanded(expanded: boolean): void;
|
setExpanded(expanded: boolean): void
|
||||||
isExpanded: boolean;
|
isExpanded: boolean
|
||||||
userprops?: { [index: string]: any };
|
userprops?: { [index: string]: any }
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PaneHeaderComponent = React.ForwardRefRenderFunction<
|
export type PaneHeaderComponent = React.ForwardRefRenderFunction<
|
||||||
{},
|
{},
|
||||||
IPaneHeaderComponentProps
|
IPaneHeaderComponentProps
|
||||||
>;
|
>
|
||||||
|
|
||||||
// component view facade
|
// component view facade
|
||||||
|
|
||||||
export interface IPaneRootProps {
|
export interface IPaneRootProps {
|
||||||
component: PaneComponent;
|
component: PaneComponent
|
||||||
props: {};
|
props: {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPaneHeaderRootProps {
|
export interface IPaneHeaderRootProps {
|
||||||
component: PaneHeaderComponent;
|
component: PaneHeaderComponent
|
||||||
props: {};
|
props: {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPaneRootRef extends IPaneComponentRef {
|
export interface IPaneRootRef extends IPaneComponentRef {
|
||||||
updateProps: (props: Partial<IPaneComponentProps>) => void;
|
updateProps: (props: Partial<IPaneComponentProps>) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPaneHeaderRootRef {
|
export interface IPaneHeaderRootRef {
|
||||||
updateProps: (props: Partial<IPaneHeaderComponentProps>) => void;
|
updateProps: (props: Partial<IPaneHeaderComponentProps>) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PaneRoot = React.forwardRef(
|
export const PaneRoot = React.forwardRef(
|
||||||
(props: IPaneRootProps, facadeRef: React.Ref<IPaneRootRef>) => {
|
(props: IPaneRootProps, facadeRef: React.Ref<IPaneRootRef>) => {
|
||||||
const ref = React.useRef<IPaneComponentRef>();
|
const ref = React.useRef<IPaneComponentRef>()
|
||||||
const [facadeProps, setFacadeProps] = React.useState<IPaneComponentProps>();
|
const [facadeProps, setFacadeProps] = React.useState<
|
||||||
|
IPaneComponentProps
|
||||||
|
>()
|
||||||
|
|
||||||
React.useImperativeHandle(
|
React.useImperativeHandle(
|
||||||
facadeRef,
|
facadeRef,
|
||||||
() => {
|
() => {
|
||||||
return {
|
return {
|
||||||
updateProps: (props) => {
|
updateProps: (props) => {
|
||||||
setFacadeProps((_props) => ({ ..._props, ...props }));
|
setFacadeProps((_props) => ({ ..._props, ...props }))
|
||||||
},
|
},
|
||||||
layout: (size, orthogonalSize) => {
|
layout: (size, orthogonalSize) => {
|
||||||
ref.current?.layout(size, orthogonalSize);
|
ref.current?.layout(size, orthogonalSize)
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
},
|
},
|
||||||
[ref]
|
[ref]
|
||||||
);
|
)
|
||||||
|
|
||||||
const Component = React.useMemo(() => React.forwardRef(props.component), [
|
const Component = React.useMemo(
|
||||||
props.component,
|
() => React.forwardRef(props.component),
|
||||||
]);
|
[props.component]
|
||||||
|
)
|
||||||
|
|
||||||
const _props = React.useMemo(
|
const _props = React.useMemo(
|
||||||
() => ({ ...props.props, ...facadeProps, ref }),
|
() => ({ ...props.props, ...facadeProps, ref }),
|
||||||
[props.props, facadeProps]
|
[props.props, facadeProps]
|
||||||
);
|
)
|
||||||
|
|
||||||
return React.createElement(Component, _props);
|
return React.createElement(Component, _props)
|
||||||
}
|
}
|
||||||
);
|
)
|
||||||
|
|
||||||
export const PaneHeaderRoot = React.forwardRef(
|
export const PaneHeaderRoot = React.forwardRef(
|
||||||
(props: IPaneHeaderRootProps, facadeRef: React.Ref<IPaneHeaderRootRef>) => {
|
(props: IPaneHeaderRootProps, facadeRef: React.Ref<IPaneHeaderRootRef>) => {
|
||||||
const [facadeProps, setFacadeProps] = React.useState<
|
const [facadeProps, setFacadeProps] = React.useState<
|
||||||
IPaneHeaderComponentProps
|
IPaneHeaderComponentProps
|
||||||
>();
|
>()
|
||||||
|
|
||||||
React.useImperativeHandle(
|
React.useImperativeHandle(
|
||||||
facadeRef,
|
facadeRef,
|
||||||
() => {
|
() => {
|
||||||
return {
|
return {
|
||||||
updateProps: (props) => {
|
updateProps: (props) => {
|
||||||
setFacadeProps((_props) => ({ ..._props, ...props }));
|
setFacadeProps((_props) => ({ ..._props, ...props }))
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
},
|
},
|
||||||
[]
|
[]
|
||||||
);
|
)
|
||||||
|
|
||||||
const Component = React.useMemo(() => React.forwardRef(props.component), [
|
const Component = React.useMemo(
|
||||||
props.component,
|
() => React.forwardRef(props.component),
|
||||||
]);
|
[props.component]
|
||||||
|
)
|
||||||
|
|
||||||
const _props = React.useMemo(() => ({ ...props.props, ...facadeProps }), [
|
const _props = React.useMemo(
|
||||||
props.props,
|
() => ({ ...props.props, ...facadeProps }),
|
||||||
facadeProps,
|
[props.props, facadeProps]
|
||||||
]);
|
)
|
||||||
|
|
||||||
return React.createElement(Component, _props);
|
return React.createElement(Component, _props)
|
||||||
}
|
}
|
||||||
);
|
)
|
||||||
|
@ -1,64 +1,67 @@
|
|||||||
import * as React from "react";
|
import * as React from 'react'
|
||||||
import { IViewWithReactComponent } from "../splitview";
|
import { IViewWithReactComponent } from '../splitview'
|
||||||
|
|
||||||
// component view
|
// component view
|
||||||
|
|
||||||
export interface IViewComponentProps
|
export interface IViewComponentProps
|
||||||
extends Omit<IViewWithReactComponent, "component"> {
|
extends Omit<IViewWithReactComponent, 'component'> {
|
||||||
userprops?: { [index: string]: any };
|
userprops?: { [index: string]: any }
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IViewComponentRef {
|
export interface IViewComponentRef {
|
||||||
layout: (size: number, orthogonalSize: number) => void;
|
layout: (size: number, orthogonalSize: number) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ViewComponent = React.ForwardRefRenderFunction<
|
export type ViewComponent = React.ForwardRefRenderFunction<
|
||||||
IViewComponentRef,
|
IViewComponentRef,
|
||||||
IViewComponentProps
|
IViewComponentProps
|
||||||
>;
|
>
|
||||||
|
|
||||||
// component view facade
|
// component view facade
|
||||||
|
|
||||||
export interface IViewRootProps {
|
export interface IViewRootProps {
|
||||||
component: ViewComponent;
|
component: ViewComponent
|
||||||
props: {};
|
props: {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IViewRootRef extends IViewComponentRef {
|
export interface IViewRootRef extends IViewComponentRef {
|
||||||
updateProps: (props: Partial<IViewComponentProps>) => void;
|
updateProps: (props: Partial<IViewComponentProps>) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ViewRoot = React.forwardRef(
|
export const ViewRoot = React.forwardRef(
|
||||||
(props: IViewRootProps, facadeRef: React.Ref<IViewRootRef>) => {
|
(props: IViewRootProps, facadeRef: React.Ref<IViewRootRef>) => {
|
||||||
const ref = React.useRef<IViewComponentRef>();
|
const ref = React.useRef<IViewComponentRef>()
|
||||||
const [facadeProps, setFacadeProps] = React.useState<IViewComponentProps>();
|
const [facadeProps, setFacadeProps] = React.useState<
|
||||||
|
IViewComponentProps
|
||||||
|
>()
|
||||||
|
|
||||||
React.useImperativeHandle(
|
React.useImperativeHandle(
|
||||||
facadeRef,
|
facadeRef,
|
||||||
() => {
|
() => {
|
||||||
return {
|
return {
|
||||||
updateProps: (props) => {
|
updateProps: (props) => {
|
||||||
setFacadeProps((_props) => ({ ..._props, ...props }));
|
setFacadeProps((_props) => ({ ..._props, ...props }))
|
||||||
},
|
},
|
||||||
layout: (size, orthogonalSize) => {
|
layout: (size, orthogonalSize) => {
|
||||||
ref.current?.layout(size, orthogonalSize);
|
ref.current?.layout(size, orthogonalSize)
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
},
|
},
|
||||||
[ref]
|
[ref]
|
||||||
);
|
)
|
||||||
|
|
||||||
const Component = React.useMemo(() => React.forwardRef(props.component), [
|
const Component = React.useMemo(
|
||||||
props.component,
|
() => React.forwardRef(props.component),
|
||||||
]);
|
[props.component]
|
||||||
|
)
|
||||||
|
|
||||||
const _props = React.useMemo(
|
const _props = React.useMemo(
|
||||||
() => ({ ...props.props, ...facadeProps, ref }),
|
() => ({ ...props.props, ...facadeProps, ref }),
|
||||||
[props.props, facadeProps]
|
[props.props, facadeProps]
|
||||||
);
|
)
|
||||||
|
|
||||||
return React.createElement(Component, _props);
|
return React.createElement(Component, _props)
|
||||||
|
|
||||||
// return <Component ref={ref} {...props.props} {...facadeProps} />;
|
// return <Component ref={ref} {...props.props} {...facadeProps} />;
|
||||||
}
|
}
|
||||||
);
|
)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
export * from "./splitview";
|
export * from './splitview'
|
||||||
export * from "./paneview";
|
export * from './paneview'
|
||||||
export * from "./bridge/view";
|
export * from './bridge/view'
|
||||||
export * from "./panel/view";
|
export * from './panel/view'
|
||||||
export * from "./bridge/pane";
|
export * from './bridge/pane'
|
||||||
export * from "./panel/pane";
|
export * from './panel/pane'
|
||||||
|
@ -1,143 +1,143 @@
|
|||||||
import * as React from "react";
|
import * as React from 'react'
|
||||||
import * as ReactDOM from "react-dom";
|
import * as ReactDOM from 'react-dom'
|
||||||
import { Pane, IDisposable } from "splitview";
|
import { Pane, IDisposable } from 'splitview'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
PaneComponent,
|
PaneComponent,
|
||||||
PaneRoot as PaneBodyRoot,
|
PaneRoot as PaneBodyRoot,
|
||||||
IPaneRootRef,
|
IPaneRootRef,
|
||||||
PaneHeaderComponent,
|
PaneHeaderComponent,
|
||||||
PaneHeaderRoot,
|
PaneHeaderRoot,
|
||||||
IPaneHeaderRootRef,
|
IPaneHeaderRootRef,
|
||||||
} from "../bridge/pane";
|
} from '../bridge/pane'
|
||||||
import { IViewWithReactComponent } from "../splitview";
|
import { IViewWithReactComponent } from '../splitview'
|
||||||
import { IPaneWithReactComponent } from "../paneview";
|
import { IPaneWithReactComponent } from '../paneview'
|
||||||
|
|
||||||
export class PaneReact extends Pane {
|
export class PaneReact extends Pane {
|
||||||
public readonly id: string;
|
public readonly id: string
|
||||||
|
|
||||||
private bodyDisposable: IDisposable;
|
private bodyDisposable: IDisposable
|
||||||
private headerDisposable: IDisposable;
|
private headerDisposable: IDisposable
|
||||||
private bodyRef: IPaneRootRef;
|
private bodyRef: IPaneRootRef
|
||||||
private headerRef: IPaneHeaderRootRef;
|
private headerRef: IPaneHeaderRootRef
|
||||||
private disposable: IDisposable;
|
private disposable: IDisposable
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly view: IPaneWithReactComponent,
|
private readonly view: IPaneWithReactComponent,
|
||||||
private readonly bodyComponent: PaneComponent,
|
private readonly bodyComponent: PaneComponent,
|
||||||
private readonly options: {
|
private readonly options: {
|
||||||
headerName: string;
|
headerName: string
|
||||||
addPortal: (portal: React.ReactPortal) => IDisposable;
|
addPortal: (portal: React.ReactPortal) => IDisposable
|
||||||
headerComponent?: PaneHeaderComponent;
|
headerComponent?: PaneHeaderComponent
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
super({ isExpanded: view.isExpanded });
|
super({ isExpanded: view.isExpanded })
|
||||||
this.layout = this.layout.bind(this);
|
this.layout = this.layout.bind(this)
|
||||||
this.onDidChange = this.onDidChange.bind(this);
|
this.onDidChange = this.onDidChange.bind(this)
|
||||||
this.setRef = this.setRef.bind(this);
|
this.setRef = this.setRef.bind(this)
|
||||||
this.setHeaderRef = this.setHeaderRef.bind(this);
|
this.setHeaderRef = this.setHeaderRef.bind(this)
|
||||||
this.setExpanded = this.setExpanded.bind(this);
|
this.setExpanded = this.setExpanded.bind(this)
|
||||||
|
|
||||||
this.id = view.id;
|
this.id = view.id
|
||||||
|
|
||||||
this.minimumSize = view.minimumSize;
|
this.minimumSize = view.minimumSize
|
||||||
this.maximumSize = view.maximumSize;
|
this.maximumSize = view.maximumSize
|
||||||
|
|
||||||
this.render();
|
this.render()
|
||||||
}
|
|
||||||
|
|
||||||
public renderBody(element: HTMLElement) {
|
|
||||||
if (this.bodyDisposable) {
|
|
||||||
this.bodyDisposable.dispose();
|
|
||||||
this.bodyDisposable = undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const bodyPortal = ReactDOM.createPortal(
|
public renderBody(element: HTMLElement) {
|
||||||
<PaneBodyRoot
|
if (this.bodyDisposable) {
|
||||||
ref={this.setRef}
|
this.bodyDisposable.dispose()
|
||||||
component={this.bodyComponent}
|
this.bodyDisposable = undefined
|
||||||
props={{
|
}
|
||||||
minimumSize: this.minimumSize,
|
|
||||||
maximumSize: this.maximumSize,
|
|
||||||
snapSize: this.view.snapSize,
|
|
||||||
userprops: this.view.componentProps,
|
|
||||||
id: this.id,
|
|
||||||
}}
|
|
||||||
/>,
|
|
||||||
element
|
|
||||||
);
|
|
||||||
this.bodyDisposable = this.options.addPortal(bodyPortal);
|
|
||||||
}
|
|
||||||
|
|
||||||
public renderHeader(element: HTMLElement) {
|
const bodyPortal = ReactDOM.createPortal(
|
||||||
if (this.headerDisposable) {
|
<PaneBodyRoot
|
||||||
this.headerDisposable.dispose();
|
ref={this.setRef}
|
||||||
this.disposable?.dispose();
|
component={this.bodyComponent}
|
||||||
this.headerDisposable = undefined;
|
props={{
|
||||||
|
minimumSize: this.minimumSize,
|
||||||
|
maximumSize: this.maximumSize,
|
||||||
|
snapSize: this.view.snapSize,
|
||||||
|
userprops: this.view.componentProps,
|
||||||
|
id: this.id,
|
||||||
|
}}
|
||||||
|
/>,
|
||||||
|
element
|
||||||
|
)
|
||||||
|
this.bodyDisposable = this.options.addPortal(bodyPortal)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.options.headerComponent) {
|
public renderHeader(element: HTMLElement) {
|
||||||
this.disposable = this.onDidChangeExpansionState((isExpanded) => {
|
if (this.headerDisposable) {
|
||||||
this.headerRef?.updateProps({ isExpanded });
|
this.headerDisposable.dispose()
|
||||||
});
|
this.disposable?.dispose()
|
||||||
|
this.headerDisposable = undefined
|
||||||
|
}
|
||||||
|
|
||||||
const headerPortal = ReactDOM.createPortal(
|
if (this.options.headerComponent) {
|
||||||
<PaneHeaderRoot
|
this.disposable = this.onDidChangeExpansionState((isExpanded) => {
|
||||||
ref={this.setHeaderRef}
|
this.headerRef?.updateProps({ isExpanded })
|
||||||
component={this.options.headerComponent}
|
})
|
||||||
props={{
|
|
||||||
|
const headerPortal = ReactDOM.createPortal(
|
||||||
|
<PaneHeaderRoot
|
||||||
|
ref={this.setHeaderRef}
|
||||||
|
component={this.options.headerComponent}
|
||||||
|
props={{
|
||||||
|
minimumSize: this.minimumSize,
|
||||||
|
maximumSize: this.maximumSize,
|
||||||
|
snapSize: this.view.snapSize,
|
||||||
|
userprops: this.view.headerProps,
|
||||||
|
id: this.id,
|
||||||
|
}}
|
||||||
|
/>,
|
||||||
|
element
|
||||||
|
)
|
||||||
|
this.headerDisposable = this.options.addPortal(headerPortal)
|
||||||
|
} else {
|
||||||
|
element.textContent = this.options.headerName
|
||||||
|
element.onclick = () => {
|
||||||
|
this.setExpanded(!this.isExpanded())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public update(view: IViewWithReactComponent) {
|
||||||
|
this.minimumSize = view.minimumSize
|
||||||
|
this.maximumSize = view.maximumSize
|
||||||
|
|
||||||
|
this.render()
|
||||||
|
|
||||||
|
this.bodyRef?.updateProps({
|
||||||
minimumSize: this.minimumSize,
|
minimumSize: this.minimumSize,
|
||||||
maximumSize: this.maximumSize,
|
maximumSize: this.maximumSize,
|
||||||
snapSize: this.view.snapSize,
|
})
|
||||||
userprops: this.view.headerProps,
|
|
||||||
id: this.id,
|
|
||||||
}}
|
|
||||||
/>,
|
|
||||||
element
|
|
||||||
);
|
|
||||||
this.headerDisposable = this.options.addPortal(headerPortal);
|
|
||||||
} else {
|
|
||||||
element.textContent = this.options.headerName;
|
|
||||||
element.onclick = () => {
|
|
||||||
this.setExpanded(!this.isExpanded());
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public update(view: IViewWithReactComponent) {
|
public layout(size: number, orthogonalSize: number) {
|
||||||
this.minimumSize = view.minimumSize;
|
super.layout(size, orthogonalSize)
|
||||||
this.maximumSize = view.maximumSize;
|
this.orthogonalSize = orthogonalSize
|
||||||
|
this.bodyRef?.layout(size, orthogonalSize)
|
||||||
|
this.bodyRef?.updateProps({ size, orthogonalSize })
|
||||||
|
}
|
||||||
|
|
||||||
this.render();
|
private setRef(ref: IPaneRootRef) {
|
||||||
|
this.bodyRef = ref
|
||||||
|
}
|
||||||
|
|
||||||
this.bodyRef?.updateProps({
|
private setHeaderRef(ref: IPaneRootRef) {
|
||||||
minimumSize: this.minimumSize,
|
this.headerRef = ref
|
||||||
maximumSize: this.maximumSize,
|
this.headerRef?.updateProps({
|
||||||
});
|
isExpanded: this.isExpanded(),
|
||||||
}
|
setExpanded: this.setExpanded,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
public layout(size: number, orthogonalSize: number) {
|
public dispose() {
|
||||||
super.layout(size, orthogonalSize);
|
this.bodyDisposable?.dispose()
|
||||||
this.orthogonalSize = orthogonalSize;
|
this.headerDisposable?.dispose()
|
||||||
this.bodyRef?.layout(size, orthogonalSize);
|
this.disposable?.dispose()
|
||||||
this.bodyRef?.updateProps({ size, orthogonalSize });
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private setRef(ref: IPaneRootRef) {
|
|
||||||
this.bodyRef = ref;
|
|
||||||
}
|
|
||||||
|
|
||||||
private setHeaderRef(ref: IPaneRootRef) {
|
|
||||||
this.headerRef = ref;
|
|
||||||
this.headerRef?.updateProps({
|
|
||||||
isExpanded: this.isExpanded(),
|
|
||||||
setExpanded: this.setExpanded,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public dispose() {
|
|
||||||
this.bodyDisposable?.dispose();
|
|
||||||
this.headerDisposable?.dispose();
|
|
||||||
this.disposable?.dispose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,108 +1,108 @@
|
|||||||
import * as React from "react";
|
import * as React from 'react'
|
||||||
import * as ReactDOM from "react-dom";
|
import * as ReactDOM from 'react-dom'
|
||||||
import { IView, Emitter } from "splitview";
|
import { IView, Emitter } from 'splitview'
|
||||||
import { IViewRootRef, ViewComponent, ViewRoot } from "../bridge/view";
|
import { IViewRootRef, ViewComponent, ViewRoot } from '../bridge/view'
|
||||||
|
|
||||||
import { IViewWithReactComponent } from "../splitview";
|
import { IViewWithReactComponent } from '../splitview'
|
||||||
|
|
||||||
export class ReactRenderView implements IView {
|
export class ReactRenderView implements IView {
|
||||||
private ref: IViewRootRef;
|
private ref: IViewRootRef
|
||||||
private disposable: { dispose: () => void };
|
private disposable: { dispose: () => void }
|
||||||
|
|
||||||
public readonly id: string;
|
public readonly id: string
|
||||||
private readonly component: ViewComponent;
|
private readonly component: ViewComponent
|
||||||
public readonly props: {};
|
public readonly props: {}
|
||||||
|
|
||||||
public element: HTMLElement;
|
public element: HTMLElement
|
||||||
public minimumSize: number;
|
public minimumSize: number
|
||||||
public maximumSize: number;
|
public maximumSize: number
|
||||||
public snapSize: number;
|
public snapSize: number
|
||||||
public size: number;
|
public size: number
|
||||||
|
|
||||||
private readonly _onDidChange = new Emitter<number | undefined>();
|
private readonly _onDidChange = new Emitter<number | undefined>()
|
||||||
public readonly onDidChange = this._onDidChange.event;
|
public readonly onDidChange = this._onDidChange.event
|
||||||
|
|
||||||
private _rendered = false;
|
private _rendered = false
|
||||||
private _size: number;
|
private _size: number
|
||||||
private _orthogonalSize: number;
|
private _orthogonalSize: number
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
view: IViewWithReactComponent,
|
view: IViewWithReactComponent,
|
||||||
private readonly addPortal: (
|
private readonly addPortal: (
|
||||||
portal: React.ReactPortal
|
portal: React.ReactPortal
|
||||||
) => { dispose: () => void }
|
) => { dispose: () => void }
|
||||||
) {
|
) {
|
||||||
this.layout = this.layout.bind(this);
|
this.layout = this.layout.bind(this)
|
||||||
this.onDidChange = this.onDidChange.bind(this);
|
this.onDidChange = this.onDidChange.bind(this)
|
||||||
this.setRef = this.setRef.bind(this);
|
this.setRef = this.setRef.bind(this)
|
||||||
|
|
||||||
this.id = view.id;
|
this.id = view.id
|
||||||
this.component = view.component;
|
this.component = view.component
|
||||||
this.props = view.props;
|
this.props = view.props
|
||||||
|
|
||||||
this.minimumSize = view.minimumSize;
|
this.minimumSize = view.minimumSize
|
||||||
this.maximumSize = view.maximumSize;
|
this.maximumSize = view.maximumSize
|
||||||
this.snapSize = view.snapSize;
|
this.snapSize = view.snapSize
|
||||||
|
|
||||||
this.element = document.createElement("div");
|
this.element = document.createElement('div')
|
||||||
this.element.id = "react-attachable-view";
|
this.element.id = 'react-attachable-view'
|
||||||
}
|
|
||||||
|
|
||||||
public update(view: IView) {
|
|
||||||
this.minimumSize = view.minimumSize;
|
|
||||||
this.maximumSize = view.maximumSize;
|
|
||||||
this.snapSize = view.snapSize;
|
|
||||||
|
|
||||||
this.ref?.updateProps({
|
|
||||||
minimumSize: this.minimumSize,
|
|
||||||
maximumSize: this.maximumSize,
|
|
||||||
snapSize: this.snapSize,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public layout(size: number, orthogonalSize: number) {
|
|
||||||
if (!this._rendered) {
|
|
||||||
this.attachReactComponent();
|
|
||||||
this._rendered = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this._size = size;
|
public update(view: IView) {
|
||||||
this._orthogonalSize = orthogonalSize;
|
this.minimumSize = view.minimumSize
|
||||||
this.ref?.layout(size, orthogonalSize);
|
this.maximumSize = view.maximumSize
|
||||||
}
|
this.snapSize = view.snapSize
|
||||||
|
|
||||||
private attachReactComponent() {
|
this.ref?.updateProps({
|
||||||
const portal = this.createReactElement();
|
minimumSize: this.minimumSize,
|
||||||
if (this.disposable) {
|
maximumSize: this.maximumSize,
|
||||||
this.disposable.dispose();
|
snapSize: this.snapSize,
|
||||||
this.disposable = undefined;
|
})
|
||||||
}
|
}
|
||||||
this.disposable = this.addPortal(portal);
|
|
||||||
}
|
|
||||||
|
|
||||||
private createReactElement() {
|
public layout(size: number, orthogonalSize: number) {
|
||||||
return ReactDOM.createPortal(
|
if (!this._rendered) {
|
||||||
<ViewRoot
|
this.attachReactComponent()
|
||||||
ref={this.setRef}
|
this._rendered = true
|
||||||
component={this.component}
|
}
|
||||||
props={{
|
|
||||||
minimumSize: this.minimumSize,
|
|
||||||
maximumSize: this.maximumSize,
|
|
||||||
snapSize: this.snapSize,
|
|
||||||
userprops: this.props,
|
|
||||||
id: this.id,
|
|
||||||
}}
|
|
||||||
/>,
|
|
||||||
this.element
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private setRef(ref: IViewRootRef) {
|
this._size = size
|
||||||
this.ref = ref;
|
this._orthogonalSize = orthogonalSize
|
||||||
this.ref?.layout(this._size, this._orthogonalSize);
|
this.ref?.layout(size, orthogonalSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
public dispose() {
|
private attachReactComponent() {
|
||||||
this.disposable?.dispose();
|
const portal = this.createReactElement()
|
||||||
}
|
if (this.disposable) {
|
||||||
|
this.disposable.dispose()
|
||||||
|
this.disposable = undefined
|
||||||
|
}
|
||||||
|
this.disposable = this.addPortal(portal)
|
||||||
|
}
|
||||||
|
|
||||||
|
private createReactElement() {
|
||||||
|
return ReactDOM.createPortal(
|
||||||
|
<ViewRoot
|
||||||
|
ref={this.setRef}
|
||||||
|
component={this.component}
|
||||||
|
props={{
|
||||||
|
minimumSize: this.minimumSize,
|
||||||
|
maximumSize: this.maximumSize,
|
||||||
|
snapSize: this.snapSize,
|
||||||
|
userprops: this.props,
|
||||||
|
id: this.id,
|
||||||
|
}}
|
||||||
|
/>,
|
||||||
|
this.element
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private setRef(ref: IViewRootRef) {
|
||||||
|
this.ref = ref
|
||||||
|
this.ref?.layout(this._size, this._orthogonalSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
public dispose() {
|
||||||
|
this.disposable?.dispose()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,196 +1,215 @@
|
|||||||
import * as React from "react";
|
import * as React from 'react'
|
||||||
import { Orientation, IBaseView, PaneView } from "splitview";
|
import { Orientation, IBaseView, PaneView } from 'splitview'
|
||||||
|
|
||||||
import { PaneReact } from "./panel/pane";
|
import { PaneReact } from './panel/pane'
|
||||||
import { PaneComponent, PaneHeaderComponent } from "./bridge/pane";
|
import { PaneComponent, PaneHeaderComponent } from './bridge/pane'
|
||||||
|
|
||||||
export interface IPaneWithReactComponent extends IBaseView {
|
export interface IPaneWithReactComponent extends IBaseView {
|
||||||
id: string;
|
id: string
|
||||||
headerId: string;
|
headerId: string
|
||||||
component: PaneComponent;
|
component: PaneComponent
|
||||||
headerComponent: PaneHeaderComponent;
|
headerComponent: PaneHeaderComponent
|
||||||
isExpanded: boolean;
|
isExpanded: boolean
|
||||||
componentProps: {};
|
componentProps: {}
|
||||||
headerProps: {};
|
headerProps: {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPaneViewReactProps {
|
export interface IPaneViewReactProps {
|
||||||
orientation: Orientation;
|
orientation: Orientation
|
||||||
onReady?: (event: PaneViewReadyEvent) => void;
|
onReady?: (event: PaneViewReadyEvent) => void
|
||||||
components?: { [index: string]: PaneComponent };
|
components?: { [index: string]: PaneComponent }
|
||||||
headerComponents?: { [index: string]: PaneHeaderComponent };
|
headerComponents?: { [index: string]: PaneHeaderComponent }
|
||||||
size: number;
|
size: number
|
||||||
orthogonalSize: number;
|
orthogonalSize: number
|
||||||
initialLayout?: PaneViewSerializedConfig;
|
initialLayout?: PaneViewSerializedConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PaneViewReadyEvent {
|
export interface PaneViewReadyEvent {
|
||||||
api: PaneviewApi;
|
api: PaneviewApi
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PaneViewSerializedConfig {
|
export interface PaneViewSerializedConfig {
|
||||||
views: Array<
|
views: Array<
|
||||||
Omit<IPaneWithReactComponent, "component" | "headerComponent"> & {
|
Omit<IPaneWithReactComponent, 'component' | 'headerComponent'> & {
|
||||||
size?: number;
|
size?: number
|
||||||
}
|
}
|
||||||
>;
|
>
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PaneviewApi {
|
export interface PaneviewApi {
|
||||||
add: (
|
add: (
|
||||||
options: Omit<IPaneWithReactComponent, "component" | "headerComponent"> & {
|
options: Omit<
|
||||||
size?: number;
|
IPaneWithReactComponent,
|
||||||
index?: number;
|
'component' | 'headerComponent'
|
||||||
}
|
> & {
|
||||||
) => void;
|
size?: number
|
||||||
moveView: (from: number, to: number) => void;
|
index?: number
|
||||||
toJSON: () => {};
|
}
|
||||||
|
) => void
|
||||||
|
moveView: (from: number, to: number) => void
|
||||||
|
toJSON: () => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPaneViewComponentRef {
|
export interface IPaneViewComponentRef {
|
||||||
layout: (size: number, orthogonalSize: number) => void;
|
layout: (size: number, orthogonalSize: number) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PaneViewComponent = React.forwardRef(
|
export const PaneViewComponent = React.forwardRef(
|
||||||
(props: IPaneViewReactProps, _ref: React.Ref<IPaneViewComponentRef>) => {
|
(props: IPaneViewReactProps, _ref: React.Ref<IPaneViewComponentRef>) => {
|
||||||
const ref = React.useRef<HTMLDivElement>();
|
const ref = React.useRef<HTMLDivElement>()
|
||||||
const dimension = React.useRef<{ size: number; orthogonalSize: number }>();
|
const dimension = React.useRef<{
|
||||||
const paneview = React.useRef<PaneView>();
|
size: number
|
||||||
const [portals, setPortals] = React.useState<React.ReactPortal[]>([]);
|
orthogonalSize: number
|
||||||
|
}>()
|
||||||
|
const paneview = React.useRef<PaneView>()
|
||||||
|
const [portals, setPortals] = React.useState<React.ReactPortal[]>([])
|
||||||
|
|
||||||
const createView = React.useCallback((_view: IPaneWithReactComponent) => {
|
const createView = React.useCallback(
|
||||||
return new PaneReact(_view, _view.component, {
|
(_view: IPaneWithReactComponent) => {
|
||||||
headerName: "header",
|
return new PaneReact(_view, _view.component, {
|
||||||
headerComponent: _view.headerComponent,
|
headerName: 'header',
|
||||||
addPortal: (portal) => {
|
headerComponent: _view.headerComponent,
|
||||||
setPortals((portals) => [...portals, portal]);
|
addPortal: (portal) => {
|
||||||
return {
|
setPortals((portals) => [...portals, portal])
|
||||||
dispose: () => {
|
return {
|
||||||
setPortals((portals) => portals.filter((_) => _ !== portal));
|
dispose: () => {
|
||||||
|
setPortals((portals) =>
|
||||||
|
portals.filter((_) => _ !== portal)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
},
|
},
|
||||||
};
|
[]
|
||||||
},
|
)
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const hydrate = React.useCallback(() => {
|
const hydrate = React.useCallback(() => {
|
||||||
if (!props.initialLayout || !paneview.current) {
|
if (!props.initialLayout || !paneview.current) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const serializedConfig = props.initialLayout;
|
const serializedConfig = props.initialLayout
|
||||||
|
|
||||||
serializedConfig.views.forEach((view) => {
|
serializedConfig.views.forEach((view) => {
|
||||||
const component = props.components[view.id];
|
const component = props.components[view.id]
|
||||||
const headerComponent = props.headerComponents[view.headerId];
|
const headerComponent = props.headerComponents[view.headerId]
|
||||||
paneview.current.addPane(
|
paneview.current.addPane(
|
||||||
createView({ ...view, component, headerComponent }),
|
createView({ ...view, component, headerComponent }),
|
||||||
view.size
|
view.size
|
||||||
);
|
)
|
||||||
});
|
})
|
||||||
paneview.current.layout(props.size, props.orthogonalSize);
|
paneview.current.layout(props.size, props.orthogonalSize)
|
||||||
}, [props.initialLayout]);
|
}, [props.initialLayout])
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (paneview.current && dimension?.current) {
|
if (paneview.current && dimension?.current) {
|
||||||
paneview.current?.layout(
|
paneview.current?.layout(
|
||||||
dimension.current.size,
|
dimension.current.size,
|
||||||
dimension.current.orthogonalSize
|
dimension.current.orthogonalSize
|
||||||
);
|
)
|
||||||
dimension.current = undefined;
|
dimension.current = undefined
|
||||||
}
|
}
|
||||||
}, [paneview.current]);
|
}, [paneview.current])
|
||||||
|
|
||||||
// if you put this in a hook it's laggy
|
// if you put this in a hook it's laggy
|
||||||
// paneview.current?.layout(props.size, props.orthogonalSize);
|
// paneview.current?.layout(props.size, props.orthogonalSize);
|
||||||
|
|
||||||
React.useImperativeHandle(
|
React.useImperativeHandle(
|
||||||
_ref,
|
_ref,
|
||||||
() => ({
|
() => ({
|
||||||
layout: (size, orthogonalSize) => {
|
layout: (size, orthogonalSize) => {
|
||||||
if (!paneview.current) {
|
if (!paneview.current) {
|
||||||
// handle the case when layout is called and paneview doesn't exist yet
|
// handle the case when layout is called and paneview doesn't exist yet
|
||||||
// we cache the values and use them at the first opportunity
|
// we cache the values and use them at the first opportunity
|
||||||
dimension.current = { size, orthogonalSize };
|
dimension.current = { size, orthogonalSize }
|
||||||
}
|
}
|
||||||
paneview.current?.layout(size, orthogonalSize);
|
paneview.current?.layout(size, orthogonalSize)
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
[paneview]
|
[paneview]
|
||||||
);
|
)
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
paneview.current = new PaneView(ref.current, {
|
paneview.current = new PaneView(ref.current, {
|
||||||
orientation: props.orientation,
|
orientation: props.orientation,
|
||||||
});
|
})
|
||||||
|
|
||||||
hydrate();
|
hydrate()
|
||||||
|
|
||||||
if (props.onReady) {
|
if (props.onReady) {
|
||||||
props.onReady({
|
props.onReady({
|
||||||
api: {
|
api: {
|
||||||
add: (
|
add: (
|
||||||
options: Omit<
|
options: Omit<
|
||||||
IPaneWithReactComponent,
|
IPaneWithReactComponent,
|
||||||
"component" | "headerComponent"
|
'component' | 'headerComponent'
|
||||||
> & {
|
> & {
|
||||||
props?: {};
|
props?: {}
|
||||||
size?: number;
|
size?: number
|
||||||
index?: number;
|
index?: number
|
||||||
}
|
}
|
||||||
) => {
|
) => {
|
||||||
const component = props.components[options.id];
|
const component = props.components[options.id]
|
||||||
const headerComponent = props.headerComponents[options.headerId];
|
const headerComponent =
|
||||||
paneview.current.addPane(
|
props.headerComponents[options.headerId]
|
||||||
createView({ ...options, component, headerComponent }),
|
paneview.current.addPane(
|
||||||
options.size,
|
createView({
|
||||||
options.index
|
...options,
|
||||||
);
|
component,
|
||||||
paneview.current.layout(props.size, props.orthogonalSize);
|
headerComponent,
|
||||||
},
|
}),
|
||||||
moveView: (from: number, to: number) => {
|
options.size,
|
||||||
paneview.current.moveView(from, to);
|
options.index
|
||||||
},
|
)
|
||||||
toJSON: () => {
|
paneview.current.layout(
|
||||||
return {
|
props.size,
|
||||||
// views: (paneview.current.getViews() as PaneReact[]).map((v) =>
|
props.orthogonalSize
|
||||||
// Object.entries({
|
)
|
||||||
// size: v.size,
|
},
|
||||||
// id: v.id,
|
moveView: (from: number, to: number) => {
|
||||||
// snapSize: v.snapSize,
|
paneview.current.moveView(from, to)
|
||||||
// minimumSize: v.minimumSize,
|
},
|
||||||
// maximumSize: v.maximumSize,
|
toJSON: () => {
|
||||||
// props: v.props,
|
return {
|
||||||
// }).reduce(
|
// views: (paneview.current.getViews() as PaneReact[]).map((v) =>
|
||||||
// (x, y) =>
|
// Object.entries({
|
||||||
// y[1] !== undefined || x !== null
|
// size: v.size,
|
||||||
// ? { ...x, [y[0]]: y[1] }
|
// id: v.id,
|
||||||
// : x,
|
// snapSize: v.snapSize,
|
||||||
// {}
|
// minimumSize: v.minimumSize,
|
||||||
// )
|
// maximumSize: v.maximumSize,
|
||||||
// ),
|
// props: v.props,
|
||||||
};
|
// }).reduce(
|
||||||
},
|
// (x, y) =>
|
||||||
},
|
// y[1] !== undefined || x !== null
|
||||||
});
|
// ? { ...x, [y[0]]: y[1] }
|
||||||
}
|
// : x,
|
||||||
|
// {}
|
||||||
|
// )
|
||||||
|
// ),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
paneview.current.layout(props.size, props.orthogonalSize);
|
paneview.current.layout(props.size, props.orthogonalSize)
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
paneview.current?.dispose();
|
paneview.current?.dispose()
|
||||||
paneview.current = undefined;
|
paneview.current = undefined
|
||||||
};
|
}
|
||||||
}, []);
|
}, [])
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
paneview.current?.setOrientation(props.orientation);
|
paneview.current?.setOrientation(props.orientation)
|
||||||
}, [props.orientation]);
|
}, [props.orientation])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={ref} className="split-view-react-wrapper">
|
<div ref={ref} className="split-view-react-wrapper">
|
||||||
{portals}
|
{portals}
|
||||||
</div>
|
</div>
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
);
|
)
|
||||||
|
@ -1,160 +1,168 @@
|
|||||||
import * as React from "react";
|
import * as React from 'react'
|
||||||
import { SplitView, Orientation, IBaseView } from "splitview";
|
import { SplitView, Orientation, IBaseView } from 'splitview'
|
||||||
import { ReactRenderView } from "./panel/view";
|
import { ReactRenderView } from './panel/view'
|
||||||
import { ViewComponent } from "./bridge/view";
|
import { ViewComponent } from './bridge/view'
|
||||||
|
|
||||||
export interface IViewWithReactComponent extends IBaseView {
|
export interface IViewWithReactComponent extends IBaseView {
|
||||||
id: string;
|
id: string
|
||||||
props?: {};
|
props?: {}
|
||||||
component: ViewComponent;
|
component: ViewComponent
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OnReadyEvent {
|
export interface OnReadyEvent {
|
||||||
api: SplitviewApi;
|
api: SplitviewApi
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SerializedConfig {
|
export interface SerializedConfig {
|
||||||
views: Array<Omit<IViewWithReactComponent, "component"> & { size?: number }>;
|
views: Array<Omit<IViewWithReactComponent, 'component'> & { size?: number }>
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SplitviewApi {
|
export interface SplitviewApi {
|
||||||
add: (
|
add: (
|
||||||
options: Omit<IViewWithReactComponent, "component"> & {
|
options: Omit<IViewWithReactComponent, 'component'> & {
|
||||||
size?: number;
|
size?: number
|
||||||
index?: number;
|
index?: number
|
||||||
}
|
}
|
||||||
) => void;
|
) => void
|
||||||
moveView: (from: number, to: number) => void;
|
moveView: (from: number, to: number) => void
|
||||||
toJSON: () => {};
|
toJSON: () => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISplitViewReactProps {
|
export interface ISplitViewReactProps {
|
||||||
orientation: Orientation;
|
orientation: Orientation
|
||||||
size: number;
|
size: number
|
||||||
orthogonalSize: number;
|
orthogonalSize: number
|
||||||
onReady?: (event: OnReadyEvent) => void;
|
onReady?: (event: OnReadyEvent) => void
|
||||||
components?: { [index: string]: ViewComponent };
|
components?: { [index: string]: ViewComponent }
|
||||||
initialLayout?: SerializedConfig;
|
initialLayout?: SerializedConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISplitViewComponentRef {
|
export interface ISplitViewComponentRef {
|
||||||
layout: (size: number, orthogonalSize: number) => void;
|
layout: (size: number, orthogonalSize: number) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SplitViewComponent = React.forwardRef(
|
export const SplitViewComponent = React.forwardRef(
|
||||||
(props: ISplitViewReactProps, ref: React.Ref<ISplitViewComponentRef>) => {
|
(props: ISplitViewReactProps, ref: React.Ref<ISplitViewComponentRef>) => {
|
||||||
const containerRef = React.useRef<HTMLDivElement>();
|
const containerRef = React.useRef<HTMLDivElement>()
|
||||||
const splitview = React.useRef<SplitView>();
|
const splitview = React.useRef<SplitView>()
|
||||||
const [portals, setPortals] = React.useState<React.ReactPortal[]>([]);
|
const [portals, setPortals] = React.useState<React.ReactPortal[]>([])
|
||||||
|
|
||||||
const hydrate = React.useCallback(() => {
|
const hydrate = React.useCallback(() => {
|
||||||
if (!props.initialLayout || !splitview.current) {
|
if (!props.initialLayout || !splitview.current) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const serializedConfig = props.initialLayout;
|
const serializedConfig = props.initialLayout
|
||||||
|
|
||||||
serializedConfig.views.forEach((view) => {
|
serializedConfig.views.forEach((view) => {
|
||||||
const component = props.components[view.id];
|
const component = props.components[view.id]
|
||||||
splitview.current.addView(
|
splitview.current.addView(
|
||||||
createView({ ...view, component }),
|
createView({ ...view, component }),
|
||||||
view.size
|
view.size
|
||||||
);
|
)
|
||||||
});
|
})
|
||||||
splitview.current.layout(props.size, props.orthogonalSize);
|
splitview.current.layout(props.size, props.orthogonalSize)
|
||||||
}, [props.initialLayout]);
|
}, [props.initialLayout])
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
splitview.current?.setOrientation(props.orientation);
|
splitview.current?.setOrientation(props.orientation)
|
||||||
splitview.current?.layout(props.size, props.orthogonalSize);
|
splitview.current?.layout(props.size, props.orthogonalSize)
|
||||||
}, [props.orientation]);
|
}, [props.orientation])
|
||||||
|
|
||||||
React.useImperativeHandle(
|
React.useImperativeHandle(
|
||||||
ref,
|
ref,
|
||||||
() => ({
|
() => ({
|
||||||
layout: (size, orthogonalSize) => {
|
layout: (size, orthogonalSize) => {
|
||||||
splitview.current?.layout(size, orthogonalSize);
|
splitview.current?.layout(size, orthogonalSize)
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
[splitview]
|
[splitview]
|
||||||
);
|
)
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
splitview.current = new SplitView(containerRef.current, {
|
splitview.current = new SplitView(containerRef.current, {
|
||||||
orientation: props.orientation,
|
orientation: props.orientation,
|
||||||
});
|
})
|
||||||
|
|
||||||
hydrate();
|
hydrate()
|
||||||
|
|
||||||
if (props.onReady) {
|
if (props.onReady) {
|
||||||
props.onReady({
|
props.onReady({
|
||||||
api: {
|
api: {
|
||||||
add: (
|
add: (
|
||||||
options: Omit<IViewWithReactComponent, "component"> & {
|
options: Omit<
|
||||||
props?: {};
|
IViewWithReactComponent,
|
||||||
size?: number;
|
'component'
|
||||||
index?: number;
|
> & {
|
||||||
}
|
props?: {}
|
||||||
) => {
|
size?: number
|
||||||
const component = props.components[options.id];
|
index?: number
|
||||||
splitview.current.addView(
|
}
|
||||||
createView({ ...options, component }),
|
) => {
|
||||||
options.size,
|
const component = props.components[options.id]
|
||||||
options.index
|
splitview.current.addView(
|
||||||
);
|
createView({ ...options, component }),
|
||||||
splitview.current.layout(props.size, props.orthogonalSize);
|
options.size,
|
||||||
},
|
options.index
|
||||||
moveView: (from: number, to: number) => {
|
)
|
||||||
splitview.current.moveView(from, to);
|
splitview.current.layout(
|
||||||
},
|
props.size,
|
||||||
toJSON: () => {
|
props.orthogonalSize
|
||||||
return {
|
)
|
||||||
views: (splitview.current.getViews() as ReactRenderView[]).map(
|
},
|
||||||
(v) =>
|
moveView: (from: number, to: number) => {
|
||||||
Object.entries({
|
splitview.current.moveView(from, to)
|
||||||
size: v.size,
|
},
|
||||||
id: v.id,
|
toJSON: () => {
|
||||||
snapSize: v.snapSize,
|
return {
|
||||||
minimumSize: v.minimumSize,
|
views: (splitview.current.getViews() as ReactRenderView[]).map(
|
||||||
maximumSize: v.maximumSize,
|
(v) =>
|
||||||
props: v.props,
|
Object.entries({
|
||||||
}).reduce(
|
size: v.size,
|
||||||
(x, y) =>
|
id: v.id,
|
||||||
y[1] !== undefined || x !== null
|
snapSize: v.snapSize,
|
||||||
? { ...x, [y[0]]: y[1] }
|
minimumSize: v.minimumSize,
|
||||||
: x,
|
maximumSize: v.maximumSize,
|
||||||
{}
|
props: v.props,
|
||||||
)
|
}).reduce(
|
||||||
),
|
(x, y) =>
|
||||||
};
|
y[1] !== undefined || x !== null
|
||||||
},
|
? { ...x, [y[0]]: y[1] }
|
||||||
},
|
: x,
|
||||||
});
|
{}
|
||||||
}
|
)
|
||||||
|
),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
splitview.current.layout(props.size, props.orthogonalSize);
|
splitview.current.layout(props.size, props.orthogonalSize)
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
splitview.current.dispose();
|
splitview.current.dispose()
|
||||||
};
|
}
|
||||||
}, []);
|
}, [])
|
||||||
|
|
||||||
const createView = React.useCallback(
|
const createView = React.useCallback(
|
||||||
(view: IViewWithReactComponent) =>
|
(view: IViewWithReactComponent) =>
|
||||||
new ReactRenderView(view, (portal) => {
|
new ReactRenderView(view, (portal) => {
|
||||||
setPortals((portals) => [...portals, portal]);
|
setPortals((portals) => [...portals, portal])
|
||||||
return {
|
return {
|
||||||
dispose: () =>
|
dispose: () =>
|
||||||
void setPortals((portals) => portals.filter((_) => _ !== portal)),
|
void setPortals((portals) =>
|
||||||
};
|
portals.filter((_) => _ !== portal)
|
||||||
}),
|
),
|
||||||
[]
|
}
|
||||||
);
|
}),
|
||||||
|
[]
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={containerRef} className="split-view-container-react">
|
<div ref={containerRef} className="split-view-container-react">
|
||||||
{portals}
|
{portals}
|
||||||
</div>
|
</div>
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
);
|
)
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"extends": "../../tsconfig.build.json",
|
"extends": "../../tsconfig.build.json",
|
||||||
|
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"composite": true,
|
"composite": true,
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"outDir": "./dist",
|
"outDir": "./dist",
|
||||||
"rootDir": "./src"
|
"rootDir": "./src"
|
||||||
},
|
},
|
||||||
"include": ["src/**/*"],
|
"include": ["src/**/*"],
|
||||||
"exclude": ["**/node_modules"]
|
"exclude": ["**/node_modules"]
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
{
|
{
|
||||||
"extends": "../../tsconfig.json"
|
"extends": "../../tsconfig.json"
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
const gulp = require("gulp");
|
const gulp = require('gulp')
|
||||||
const buildfile = require("../../scripts/build");
|
const buildfile = require('../../scripts/build')
|
||||||
const package = require("./package");
|
const package = require('./package')
|
||||||
|
|
||||||
buildfile.build({ tsconfig: "./tsconfig.build.json", package });
|
buildfile.build({ tsconfig: './tsconfig.build.json', package })
|
||||||
|
|
||||||
gulp.task("run", gulp.series(["esm", "sass"]));
|
gulp.task('run', gulp.series(['esm', 'sass']))
|
||||||
|
730
packages/splitview/package-lock.json
generated
730
packages/splitview/package-lock.json
generated
@ -1,368 +1,368 @@
|
|||||||
{
|
{
|
||||||
"name": "splitview",
|
"name": "splitview",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/prop-types": {
|
"@types/prop-types": {
|
||||||
"version": "15.7.3",
|
"version": "15.7.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz",
|
||||||
"integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw=="
|
"integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw=="
|
||||||
},
|
},
|
||||||
"@types/react": {
|
"@types/react": {
|
||||||
"version": "16.9.43",
|
"version": "16.9.43",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.43.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.43.tgz",
|
||||||
"integrity": "sha512-PxshAFcnJqIWYpJbLPriClH53Z2WlJcVZE+NP2etUtWQs2s7yIMj3/LDKZT/5CHJ/F62iyjVCDu2H3jHEXIxSg==",
|
"integrity": "sha512-PxshAFcnJqIWYpJbLPriClH53Z2WlJcVZE+NP2etUtWQs2s7yIMj3/LDKZT/5CHJ/F62iyjVCDu2H3jHEXIxSg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/prop-types": "*",
|
"@types/prop-types": "*",
|
||||||
"csstype": "^2.2.0"
|
"csstype": "^2.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/react-dom": {
|
"@types/react-dom": {
|
||||||
"version": "16.9.8",
|
"version": "16.9.8",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.8.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.8.tgz",
|
||||||
"integrity": "sha512-ykkPQ+5nFknnlU6lDd947WbQ6TE3NNzbQAkInC2EKY1qeYdTKp7onFusmYZb+ityzx2YviqT6BXSu+LyWWJwcA==",
|
"integrity": "sha512-ykkPQ+5nFknnlU6lDd947WbQ6TE3NNzbQAkInC2EKY1qeYdTKp7onFusmYZb+ityzx2YviqT6BXSu+LyWWJwcA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/react": "*"
|
"@types/react": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"at-least-node": {
|
"at-least-node": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
|
||||||
"integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==",
|
"integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"balanced-match": {
|
"balanced-match": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
||||||
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
|
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"brace-expansion": {
|
"brace-expansion": {
|
||||||
"version": "1.1.11",
|
"version": "1.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"balanced-match": "^1.0.0",
|
"balanced-match": "^1.0.0",
|
||||||
"concat-map": "0.0.1"
|
"concat-map": "0.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"concat-map": {
|
"concat-map": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
|
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"csstype": {
|
"csstype": {
|
||||||
"version": "2.6.11",
|
"version": "2.6.11",
|
||||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.11.tgz",
|
"resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.11.tgz",
|
||||||
"integrity": "sha512-l8YyEC9NBkSm783PFTvh0FmJy7s5pFKrDp49ZL7zBGX3fWkO+N4EEyan1qqp8cwPLDcD0OSdyY6hAMoxp34JFw=="
|
"integrity": "sha512-l8YyEC9NBkSm783PFTvh0FmJy7s5pFKrDp49ZL7zBGX3fWkO+N4EEyan1qqp8cwPLDcD0OSdyY6hAMoxp34JFw=="
|
||||||
},
|
},
|
||||||
"fs-extra": {
|
"fs-extra": {
|
||||||
"version": "9.0.1",
|
"version": "9.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz",
|
||||||
"integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==",
|
"integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"at-least-node": "^1.0.0",
|
"at-least-node": "^1.0.0",
|
||||||
"graceful-fs": "^4.2.0",
|
"graceful-fs": "^4.2.0",
|
||||||
"jsonfile": "^6.0.1",
|
"jsonfile": "^6.0.1",
|
||||||
"universalify": "^1.0.0"
|
"universalify": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"fs.realpath": {
|
"fs.realpath": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||||
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
|
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"glob": {
|
"glob": {
|
||||||
"version": "7.1.6",
|
"version": "7.1.6",
|
||||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
|
||||||
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
|
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"fs.realpath": "^1.0.0",
|
"fs.realpath": "^1.0.0",
|
||||||
"inflight": "^1.0.4",
|
"inflight": "^1.0.4",
|
||||||
"inherits": "2",
|
"inherits": "2",
|
||||||
"minimatch": "^3.0.4",
|
"minimatch": "^3.0.4",
|
||||||
"once": "^1.3.0",
|
"once": "^1.3.0",
|
||||||
"path-is-absolute": "^1.0.0"
|
"path-is-absolute": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"graceful-fs": {
|
"graceful-fs": {
|
||||||
"version": "4.2.4",
|
"version": "4.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
|
||||||
"integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
|
"integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"handlebars": {
|
"handlebars": {
|
||||||
"version": "4.7.6",
|
"version": "4.7.6",
|
||||||
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.6.tgz",
|
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.6.tgz",
|
||||||
"integrity": "sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA==",
|
"integrity": "sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"minimist": "^1.2.5",
|
"minimist": "^1.2.5",
|
||||||
"neo-async": "^2.6.0",
|
"neo-async": "^2.6.0",
|
||||||
"source-map": "^0.6.1",
|
"source-map": "^0.6.1",
|
||||||
"uglify-js": "^3.1.4",
|
"uglify-js": "^3.1.4",
|
||||||
"wordwrap": "^1.0.0"
|
"wordwrap": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"highlight.js": {
|
"highlight.js": {
|
||||||
"version": "10.1.2",
|
"version": "10.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.1.2.tgz",
|
||||||
"integrity": "sha512-Q39v/Mn5mfBlMff9r+zzA+gWxRsCRKwEMvYTiisLr/XUiFI/4puWt0Ojdko3R3JCNWGdOWaA5g/Yxqa23kC5AA==",
|
"integrity": "sha512-Q39v/Mn5mfBlMff9r+zzA+gWxRsCRKwEMvYTiisLr/XUiFI/4puWt0Ojdko3R3JCNWGdOWaA5g/Yxqa23kC5AA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"inflight": {
|
"inflight": {
|
||||||
"version": "1.0.6",
|
"version": "1.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||||
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
|
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"once": "^1.3.0",
|
"once": "^1.3.0",
|
||||||
"wrappy": "1"
|
"wrappy": "1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"inherits": {
|
"inherits": {
|
||||||
"version": "2.0.4",
|
"version": "2.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"interpret": {
|
"interpret": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz",
|
||||||
"integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==",
|
"integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"js-tokens": {
|
"js-tokens": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
|
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
|
||||||
},
|
},
|
||||||
"jsonfile": {
|
"jsonfile": {
|
||||||
"version": "6.0.1",
|
"version": "6.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.0.1.tgz",
|
||||||
"integrity": "sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==",
|
"integrity": "sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"graceful-fs": "^4.1.6",
|
"graceful-fs": "^4.1.6",
|
||||||
"universalify": "^1.0.0"
|
"universalify": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lodash": {
|
"lodash": {
|
||||||
"version": "4.17.20",
|
"version": "4.17.20",
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
|
||||||
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
|
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"loose-envify": {
|
"loose-envify": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||||
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"js-tokens": "^3.0.0 || ^4.0.0"
|
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lunr": {
|
"lunr": {
|
||||||
"version": "2.3.9",
|
"version": "2.3.9",
|
||||||
"resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz",
|
"resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz",
|
||||||
"integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==",
|
"integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"marked": {
|
"marked": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/marked/-/marked-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/marked/-/marked-1.1.1.tgz",
|
||||||
"integrity": "sha512-mJzT8D2yPxoPh7h0UXkB+dBj4FykPJ2OIfxAWeIHrvoHDkFxukV/29QxoFQoPM6RLEwhIFdJpmKBlqVM3s2ZIw==",
|
"integrity": "sha512-mJzT8D2yPxoPh7h0UXkB+dBj4FykPJ2OIfxAWeIHrvoHDkFxukV/29QxoFQoPM6RLEwhIFdJpmKBlqVM3s2ZIw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"minimatch": {
|
"minimatch": {
|
||||||
"version": "3.0.4",
|
"version": "3.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"brace-expansion": "^1.1.7"
|
"brace-expansion": "^1.1.7"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"minimist": {
|
"minimist": {
|
||||||
"version": "1.2.5",
|
"version": "1.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"neo-async": {
|
"neo-async": {
|
||||||
"version": "2.6.2",
|
"version": "2.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
|
||||||
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
|
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"object-assign": {
|
"object-assign": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||||
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
|
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
|
||||||
},
|
},
|
||||||
"once": {
|
"once": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||||
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"wrappy": "1"
|
"wrappy": "1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"path-is-absolute": {
|
"path-is-absolute": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||||
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
|
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"path-parse": {
|
"path-parse": {
|
||||||
"version": "1.0.6",
|
"version": "1.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
|
||||||
"integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
|
"integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"progress": {
|
"progress": {
|
||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
|
||||||
"integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
|
"integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"prop-types": {
|
"prop-types": {
|
||||||
"version": "15.7.2",
|
"version": "15.7.2",
|
||||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
|
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
|
||||||
"integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
|
"integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"loose-envify": "^1.4.0",
|
"loose-envify": "^1.4.0",
|
||||||
"object-assign": "^4.1.1",
|
"object-assign": "^4.1.1",
|
||||||
"react-is": "^16.8.1"
|
"react-is": "^16.8.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react": {
|
"react": {
|
||||||
"version": "16.13.1",
|
"version": "16.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/react/-/react-16.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/react/-/react-16.13.1.tgz",
|
||||||
"integrity": "sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w==",
|
"integrity": "sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"loose-envify": "^1.1.0",
|
"loose-envify": "^1.1.0",
|
||||||
"object-assign": "^4.1.1",
|
"object-assign": "^4.1.1",
|
||||||
"prop-types": "^15.6.2"
|
"prop-types": "^15.6.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react-dom": {
|
"react-dom": {
|
||||||
"version": "16.13.1",
|
"version": "16.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.13.1.tgz",
|
||||||
"integrity": "sha512-81PIMmVLnCNLO/fFOQxdQkvEq/+Hfpv24XNJfpyZhTRfO0QcmQIF/PgCa1zCOj2w1hrn12MFLyaJ/G0+Mxtfag==",
|
"integrity": "sha512-81PIMmVLnCNLO/fFOQxdQkvEq/+Hfpv24XNJfpyZhTRfO0QcmQIF/PgCa1zCOj2w1hrn12MFLyaJ/G0+Mxtfag==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"loose-envify": "^1.1.0",
|
"loose-envify": "^1.1.0",
|
||||||
"object-assign": "^4.1.1",
|
"object-assign": "^4.1.1",
|
||||||
"prop-types": "^15.6.2",
|
"prop-types": "^15.6.2",
|
||||||
"scheduler": "^0.19.1"
|
"scheduler": "^0.19.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react-is": {
|
"react-is": {
|
||||||
"version": "16.13.1",
|
"version": "16.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||||
},
|
},
|
||||||
"rechoir": {
|
"rechoir": {
|
||||||
"version": "0.6.2",
|
"version": "0.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
|
||||||
"integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=",
|
"integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"resolve": "^1.1.6"
|
"resolve": "^1.1.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"resolve": {
|
"resolve": {
|
||||||
"version": "1.17.0",
|
"version": "1.17.0",
|
||||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz",
|
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz",
|
||||||
"integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==",
|
"integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"path-parse": "^1.0.6"
|
"path-parse": "^1.0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"scheduler": {
|
"scheduler": {
|
||||||
"version": "0.19.1",
|
"version": "0.19.1",
|
||||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz",
|
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz",
|
||||||
"integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==",
|
"integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"loose-envify": "^1.1.0",
|
"loose-envify": "^1.1.0",
|
||||||
"object-assign": "^4.1.1"
|
"object-assign": "^4.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"shelljs": {
|
"shelljs": {
|
||||||
"version": "0.8.4",
|
"version": "0.8.4",
|
||||||
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.4.tgz",
|
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.4.tgz",
|
||||||
"integrity": "sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ==",
|
"integrity": "sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"glob": "^7.0.0",
|
"glob": "^7.0.0",
|
||||||
"interpret": "^1.0.0",
|
"interpret": "^1.0.0",
|
||||||
"rechoir": "^0.6.2"
|
"rechoir": "^0.6.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"source-map": {
|
"source-map": {
|
||||||
"version": "0.6.1",
|
"version": "0.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"typedoc": {
|
"typedoc": {
|
||||||
"version": "0.18.0",
|
"version": "0.18.0",
|
||||||
"resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.18.0.tgz",
|
"resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.18.0.tgz",
|
||||||
"integrity": "sha512-UgDQwapCGQCCdYhEQzQ+kGutmcedklilgUGf62Vw6RdI29u6FcfAXFQfRTiJEbf16aK3YnkB20ctQK1JusCRbA==",
|
"integrity": "sha512-UgDQwapCGQCCdYhEQzQ+kGutmcedklilgUGf62Vw6RdI29u6FcfAXFQfRTiJEbf16aK3YnkB20ctQK1JusCRbA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"fs-extra": "^9.0.1",
|
"fs-extra": "^9.0.1",
|
||||||
"handlebars": "^4.7.6",
|
"handlebars": "^4.7.6",
|
||||||
"highlight.js": "^10.0.0",
|
"highlight.js": "^10.0.0",
|
||||||
"lodash": "^4.17.15",
|
"lodash": "^4.17.15",
|
||||||
"lunr": "^2.3.8",
|
"lunr": "^2.3.8",
|
||||||
"marked": "^1.1.1",
|
"marked": "^1.1.1",
|
||||||
"minimatch": "^3.0.0",
|
"minimatch": "^3.0.0",
|
||||||
"progress": "^2.0.3",
|
"progress": "^2.0.3",
|
||||||
"shelljs": "^0.8.4",
|
"shelljs": "^0.8.4",
|
||||||
"typedoc-default-themes": "^0.10.2"
|
"typedoc-default-themes": "^0.10.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"typedoc-default-themes": {
|
"typedoc-default-themes": {
|
||||||
"version": "0.10.2",
|
"version": "0.10.2",
|
||||||
"resolved": "https://registry.npmjs.org/typedoc-default-themes/-/typedoc-default-themes-0.10.2.tgz",
|
"resolved": "https://registry.npmjs.org/typedoc-default-themes/-/typedoc-default-themes-0.10.2.tgz",
|
||||||
"integrity": "sha512-zo09yRj+xwLFE3hyhJeVHWRSPuKEIAsFK5r2u47KL/HBKqpwdUSanoaz5L34IKiSATFrjG5ywmIu98hPVMfxZg==",
|
"integrity": "sha512-zo09yRj+xwLFE3hyhJeVHWRSPuKEIAsFK5r2u47KL/HBKqpwdUSanoaz5L34IKiSATFrjG5ywmIu98hPVMfxZg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"lunr": "^2.3.8"
|
"lunr": "^2.3.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uglify-js": {
|
"uglify-js": {
|
||||||
"version": "3.10.1",
|
"version": "3.10.1",
|
||||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.10.1.tgz",
|
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.10.1.tgz",
|
||||||
"integrity": "sha512-RjxApKkrPJB6kjJxQS3iZlf///REXWYxYJxO/MpmlQzVkDWVI3PSnCBWezMecmTU/TRkNxrl8bmsfFQCp+LO+Q==",
|
"integrity": "sha512-RjxApKkrPJB6kjJxQS3iZlf///REXWYxYJxO/MpmlQzVkDWVI3PSnCBWezMecmTU/TRkNxrl8bmsfFQCp+LO+Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"universalify": {
|
"universalify": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz",
|
||||||
"integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==",
|
"integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"wordwrap": {
|
"wordwrap": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
|
||||||
"integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=",
|
"integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"wrappy": {
|
"wrappy": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
|
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
|
||||||
"dev": true
|
"dev": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,23 +1,23 @@
|
|||||||
{
|
{
|
||||||
"name": "splitview",
|
"name": "splitview",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "dist/esm/index.js",
|
"main": "dist/esm/index.js",
|
||||||
"types": "dist/esm/index.d.ts",
|
"types": "dist/esm/index.d.ts",
|
||||||
"module": "dist/esm/index.js",
|
"module": "dist/esm/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "gulp run",
|
"build": "gulp run",
|
||||||
"docs": "typedoc"
|
"docs": "typedoc"
|
||||||
},
|
},
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/react": "^16.9.43",
|
"@types/react": "^16.9.43",
|
||||||
"@types/react-dom": "^16.9.8",
|
"@types/react-dom": "^16.9.8",
|
||||||
"react": "^16.13.1",
|
"react": "^16.13.1",
|
||||||
"react-dom": "^16.13.1"
|
"react-dom": "^16.13.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"typedoc": "^0.18.0"
|
"typedoc": "^0.18.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,69 +1,69 @@
|
|||||||
export function tail<T>(arr: T[]): [T[], T] {
|
export function tail<T>(arr: T[]): [T[], T] {
|
||||||
if (arr.length === 0) {
|
if (arr.length === 0) {
|
||||||
throw new Error("Invalid tail call");
|
throw new Error('Invalid tail call')
|
||||||
}
|
}
|
||||||
|
|
||||||
return [arr.slice(0, arr.length - 1), arr[arr.length - 1]];
|
return [arr.slice(0, arr.length - 1), arr[arr.length - 1]]
|
||||||
}
|
}
|
||||||
|
|
||||||
export function last<T>(arr: T[]): T {
|
export function last<T>(arr: T[]): T {
|
||||||
return arr.length > 0 ? arr[arr.length - 1] : undefined;
|
return arr.length > 0 ? arr[arr.length - 1] : undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
export function sequenceEquals<T>(arr1: T[], arr2: T[]) {
|
export function sequenceEquals<T>(arr1: T[], arr2: T[]) {
|
||||||
if (arr1.length !== arr2.length) {
|
if (arr1.length !== arr2.length) {
|
||||||
return false;
|
return false
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = 0; i < arr1.length; i++) {
|
|
||||||
if (arr1[i] !== arr2[i]) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return true;
|
for (let i = 0; i < arr1.length; i++) {
|
||||||
|
if (arr1[i] !== arr2[i]) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pushes an element to the start of the array, if found.
|
* Pushes an element to the start of the array, if found.
|
||||||
*/
|
*/
|
||||||
export function pushToStart<T>(arr: T[], value: T): void {
|
export function pushToStart<T>(arr: T[], value: T): void {
|
||||||
const index = arr.indexOf(value);
|
const index = arr.indexOf(value)
|
||||||
|
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
arr.splice(index, 1);
|
arr.splice(index, 1)
|
||||||
arr.unshift(value);
|
arr.unshift(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pushes an element to the end of the array, if found.
|
* Pushes an element to the end of the array, if found.
|
||||||
*/
|
*/
|
||||||
export function pushToEnd<T>(arr: T[], value: T): void {
|
export function pushToEnd<T>(arr: T[], value: T): void {
|
||||||
const index = arr.indexOf(value);
|
const index = arr.indexOf(value)
|
||||||
|
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
arr.splice(index, 1);
|
arr.splice(index, 1)
|
||||||
arr.push(value);
|
arr.push(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const range = (from: number, to: number = undefined) => {
|
export const range = (from: number, to: number = undefined) => {
|
||||||
const result: number[] = [];
|
const result: number[] = []
|
||||||
|
|
||||||
if (to === undefined) {
|
if (to === undefined) {
|
||||||
to = from;
|
to = from
|
||||||
from = 0;
|
from = 0
|
||||||
}
|
|
||||||
|
|
||||||
if (from <= to) {
|
|
||||||
for (let i = from; i < to; i++) {
|
|
||||||
result.push(i);
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
for (let i = from; i > to; i--) {
|
|
||||||
result.push(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
if (from <= to) {
|
||||||
};
|
for (let i = from; i < to; i++) {
|
||||||
|
result.push(i)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (let i = from; i > to; i--) {
|
||||||
|
result.push(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
export function timeoutPromise(timeout: number): Promise<void> {
|
export function timeoutPromise(timeout: number): Promise<void> {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
resolve();
|
resolve()
|
||||||
}, timeout);
|
}, timeout)
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
import { Event, Emitter, addDisposableListener } from "./events";
|
import { Event, Emitter, addDisposableListener } from './events'
|
||||||
import { IDisposable, CompositeDisposable } from "./lifecycle";
|
import { IDisposable, CompositeDisposable } from './lifecycle'
|
||||||
|
|
||||||
export function getDomNodePagePosition(domNode: HTMLElement) {
|
export function getDomNodePagePosition(domNode: HTMLElement) {
|
||||||
const bb = domNode.getBoundingClientRect();
|
const bb = domNode.getBoundingClientRect()
|
||||||
return {
|
return {
|
||||||
left: bb.left + window.scrollX,
|
left: bb.left + window.scrollX,
|
||||||
top: bb.top + window.scrollY,
|
top: bb.top + window.scrollY,
|
||||||
width: bb.width,
|
width: bb.width,
|
||||||
height: bb.height,
|
height: bb.height,
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -16,213 +16,217 @@ export function getDomNodePagePosition(domNode: HTMLElement) {
|
|||||||
* the element is above or below the containers view portal.
|
* the element is above or below the containers view portal.
|
||||||
*/
|
*/
|
||||||
export const scrollIntoView = (
|
export const scrollIntoView = (
|
||||||
element: HTMLElement,
|
element: HTMLElement,
|
||||||
container: HTMLElement
|
container: HTMLElement
|
||||||
) => {
|
) => {
|
||||||
const { inView, breachPoint } = isElementInView(element, container, true);
|
const { inView, breachPoint } = isElementInView(element, container, true)
|
||||||
if (!inView) {
|
if (!inView) {
|
||||||
const adder = -container.offsetTop;
|
const adder = -container.offsetTop
|
||||||
const isUp = breachPoint === "top";
|
const isUp = breachPoint === 'top'
|
||||||
container.scrollTo({
|
container.scrollTo({
|
||||||
top: isUp
|
top: isUp
|
||||||
? adder + element.offsetTop
|
? adder + element.offsetTop
|
||||||
: adder +
|
: adder +
|
||||||
element.offsetTop -
|
element.offsetTop -
|
||||||
container.clientHeight +
|
container.clientHeight +
|
||||||
element.clientHeight,
|
element.clientHeight,
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export const isElementInView = (
|
export const isElementInView = (
|
||||||
element: HTMLElement,
|
element: HTMLElement,
|
||||||
container: HTMLElement,
|
container: HTMLElement,
|
||||||
fullyInView: boolean
|
fullyInView: boolean
|
||||||
): { inView: boolean; breachPoint?: "top" | "bottom" } => {
|
): { inView: boolean; breachPoint?: 'top' | 'bottom' } => {
|
||||||
const containerOfftsetTop = container.offsetTop;
|
const containerOfftsetTop = container.offsetTop
|
||||||
const containerTop = containerOfftsetTop + container.scrollTop;
|
const containerTop = containerOfftsetTop + container.scrollTop
|
||||||
const containerBottom =
|
const containerBottom =
|
||||||
containerTop + container.getBoundingClientRect().height;
|
containerTop + container.getBoundingClientRect().height
|
||||||
const elementTop = element.offsetTop;
|
const elementTop = element.offsetTop
|
||||||
const elementBottom = elementTop + element.getBoundingClientRect().height;
|
const elementBottom = elementTop + element.getBoundingClientRect().height
|
||||||
|
|
||||||
const isAbove = fullyInView
|
const isAbove = fullyInView
|
||||||
? containerTop >= elementTop
|
? containerTop >= elementTop
|
||||||
: elementTop > containerBottom;
|
: elementTop > containerBottom
|
||||||
const isBelow = fullyInView
|
const isBelow = fullyInView
|
||||||
? containerBottom <= elementBottom
|
? containerBottom <= elementBottom
|
||||||
: elementBottom < containerTop;
|
: elementBottom < containerTop
|
||||||
|
|
||||||
if (isAbove) {
|
if (isAbove) {
|
||||||
return { inView: false, breachPoint: "top" };
|
return { inView: false, breachPoint: 'top' }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isBelow) {
|
if (isBelow) {
|
||||||
return { inView: false, breachPoint: "bottom" };
|
return { inView: false, breachPoint: 'bottom' }
|
||||||
}
|
}
|
||||||
|
|
||||||
return { inView: true };
|
return { inView: true }
|
||||||
};
|
}
|
||||||
|
|
||||||
export function isHTMLElement(o: any): o is HTMLElement {
|
export function isHTMLElement(o: any): o is HTMLElement {
|
||||||
if (typeof HTMLElement === "object") {
|
if (typeof HTMLElement === 'object') {
|
||||||
return o instanceof HTMLElement;
|
return o instanceof HTMLElement
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
o &&
|
o &&
|
||||||
typeof o === "object" &&
|
typeof o === 'object' &&
|
||||||
o.nodeType === 1 &&
|
o.nodeType === 1 &&
|
||||||
typeof o.nodeName === "string"
|
typeof o.nodeName === 'string'
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const isInTree = (element: HTMLElement, className: string) => {
|
export const isInTree = (element: HTMLElement, className: string) => {
|
||||||
let _element = element;
|
let _element = element
|
||||||
|
|
||||||
while (_element) {
|
while (_element) {
|
||||||
if (_element.classList.contains(className)) {
|
if (_element.classList.contains(className)) {
|
||||||
return true;
|
return true
|
||||||
|
}
|
||||||
|
_element = _element.parentElement
|
||||||
}
|
}
|
||||||
_element = _element.parentElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false
|
||||||
};
|
}
|
||||||
|
|
||||||
export const removeClasses = (element: HTMLElement, ...classes: string[]) => {
|
export const removeClasses = (element: HTMLElement, ...classes: string[]) => {
|
||||||
for (const classname of classes) {
|
for (const classname of classes) {
|
||||||
if (element.classList.contains(classname)) {
|
if (element.classList.contains(classname)) {
|
||||||
element.classList.remove(classname);
|
element.classList.remove(classname)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
export const addClasses = (element: HTMLElement, ...classes: string[]) => {
|
export const addClasses = (element: HTMLElement, ...classes: string[]) => {
|
||||||
for (const classname of classes) {
|
for (const classname of classes) {
|
||||||
if (!element.classList.contains(classname)) {
|
if (!element.classList.contains(classname)) {
|
||||||
element.classList.add(classname);
|
element.classList.add(classname)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
export const toggleClass = (
|
export const toggleClass = (
|
||||||
element: HTMLElement,
|
element: HTMLElement,
|
||||||
className: string,
|
className: string,
|
||||||
isToggled: boolean
|
isToggled: boolean
|
||||||
) => {
|
) => {
|
||||||
const hasClass = element.classList.contains(className);
|
const hasClass = element.classList.contains(className)
|
||||||
if (isToggled && !hasClass) {
|
if (isToggled && !hasClass) {
|
||||||
element.classList.add(className);
|
element.classList.add(className)
|
||||||
}
|
}
|
||||||
if (!isToggled && hasClass) {
|
if (!isToggled && hasClass) {
|
||||||
element.classList.remove(className);
|
element.classList.remove(className)
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export function firstIndex<T>(
|
export function firstIndex<T>(
|
||||||
array: T[] | ReadonlyArray<T>,
|
array: T[] | ReadonlyArray<T>,
|
||||||
fn: (item: T) => boolean
|
fn: (item: T) => boolean
|
||||||
): number {
|
): number {
|
||||||
for (let i = 0; i < array.length; i++) {
|
for (let i = 0; i < array.length; i++) {
|
||||||
const element = array[i];
|
const element = array[i]
|
||||||
|
|
||||||
if (fn(element)) {
|
if (fn(element)) {
|
||||||
return i;
|
return i
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isAncestor(
|
export function isAncestor(
|
||||||
testChild: Node | null,
|
testChild: Node | null,
|
||||||
testAncestor: Node | null
|
testAncestor: Node | null
|
||||||
): boolean {
|
): boolean {
|
||||||
while (testChild) {
|
while (testChild) {
|
||||||
if (testChild === testAncestor) {
|
if (testChild === testAncestor) {
|
||||||
return true;
|
return true
|
||||||
|
}
|
||||||
|
testChild = testChild.parentNode
|
||||||
}
|
}
|
||||||
testChild = testChild.parentNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IFocusTracker extends IDisposable {
|
export interface IFocusTracker extends IDisposable {
|
||||||
onDidFocus: Event<void>;
|
onDidFocus: Event<void>
|
||||||
onDidBlur: Event<void>;
|
onDidBlur: Event<void>
|
||||||
refreshState?(): void;
|
refreshState?(): void
|
||||||
}
|
}
|
||||||
|
|
||||||
export function trackFocus(element: HTMLElement | Window): IFocusTracker {
|
export function trackFocus(element: HTMLElement | Window): IFocusTracker {
|
||||||
return new FocusTracker(element);
|
return new FocusTracker(element)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Track focus on an element. Ensure tabIndex is set when an HTMLElement is not focusable by default
|
* Track focus on an element. Ensure tabIndex is set when an HTMLElement is not focusable by default
|
||||||
*/
|
*/
|
||||||
class FocusTracker extends CompositeDisposable implements IFocusTracker {
|
class FocusTracker extends CompositeDisposable implements IFocusTracker {
|
||||||
private readonly _onDidFocus = new Emitter<void>();
|
private readonly _onDidFocus = new Emitter<void>()
|
||||||
public readonly onDidFocus: Event<void> = this._onDidFocus.event;
|
public readonly onDidFocus: Event<void> = this._onDidFocus.event
|
||||||
|
|
||||||
private readonly _onDidBlur = new Emitter<void>();
|
private readonly _onDidBlur = new Emitter<void>()
|
||||||
public readonly onDidBlur: Event<void> = this._onDidBlur.event;
|
public readonly onDidBlur: Event<void> = this._onDidBlur.event
|
||||||
|
|
||||||
private _refreshStateHandler: () => void;
|
private _refreshStateHandler: () => void
|
||||||
|
|
||||||
constructor(element: HTMLElement | Window) {
|
constructor(element: HTMLElement | Window) {
|
||||||
super();
|
super()
|
||||||
|
|
||||||
let hasFocus = isAncestor(document.activeElement, <HTMLElement>element);
|
let hasFocus = isAncestor(document.activeElement, <HTMLElement>element)
|
||||||
let loosingFocus = false;
|
let loosingFocus = false
|
||||||
|
|
||||||
const onFocus = () => {
|
const onFocus = () => {
|
||||||
loosingFocus = false;
|
loosingFocus = false
|
||||||
if (!hasFocus) {
|
if (!hasFocus) {
|
||||||
hasFocus = true;
|
hasFocus = true
|
||||||
this._onDidFocus.fire();
|
this._onDidFocus.fire()
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
const onBlur = () => {
|
|
||||||
if (hasFocus) {
|
|
||||||
loosingFocus = true;
|
|
||||||
window.setTimeout(() => {
|
|
||||||
if (loosingFocus) {
|
|
||||||
loosingFocus = false;
|
|
||||||
hasFocus = false;
|
|
||||||
this._onDidBlur.fire();
|
|
||||||
}
|
|
||||||
}, 0);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this._refreshStateHandler = () => {
|
|
||||||
let currentNodeHasFocus = isAncestor(
|
|
||||||
document.activeElement,
|
|
||||||
<HTMLElement>element
|
|
||||||
);
|
|
||||||
if (currentNodeHasFocus !== hasFocus) {
|
|
||||||
if (hasFocus) {
|
|
||||||
onBlur();
|
|
||||||
} else {
|
|
||||||
onFocus();
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.addDisposables(addDisposableListener(element, "focus", onFocus, true));
|
const onBlur = () => {
|
||||||
this.addDisposables(addDisposableListener(element, "blur", onBlur, true));
|
if (hasFocus) {
|
||||||
}
|
loosingFocus = true
|
||||||
|
window.setTimeout(() => {
|
||||||
|
if (loosingFocus) {
|
||||||
|
loosingFocus = false
|
||||||
|
hasFocus = false
|
||||||
|
this._onDidBlur.fire()
|
||||||
|
}
|
||||||
|
}, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
refreshState() {
|
this._refreshStateHandler = () => {
|
||||||
this._refreshStateHandler();
|
let currentNodeHasFocus = isAncestor(
|
||||||
}
|
document.activeElement,
|
||||||
|
<HTMLElement>element
|
||||||
|
)
|
||||||
|
if (currentNodeHasFocus !== hasFocus) {
|
||||||
|
if (hasFocus) {
|
||||||
|
onBlur()
|
||||||
|
} else {
|
||||||
|
onFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public dispose() {
|
this.addDisposables(
|
||||||
super.dispose();
|
addDisposableListener(element, 'focus', onFocus, true)
|
||||||
|
)
|
||||||
|
this.addDisposables(
|
||||||
|
addDisposableListener(element, 'blur', onBlur, true)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
this._onDidBlur.dispose();
|
refreshState() {
|
||||||
this._onDidFocus.dispose();
|
this._refreshStateHandler()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public dispose() {
|
||||||
|
super.dispose()
|
||||||
|
|
||||||
|
this._onDidBlur.dispose()
|
||||||
|
this._onDidFocus.dispose()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,88 +1,88 @@
|
|||||||
import { IDisposable } from "./lifecycle";
|
import { IDisposable } from './lifecycle'
|
||||||
|
|
||||||
export interface Event<T> {
|
export interface Event<T> {
|
||||||
(listener: (e: T) => any): IDisposable;
|
(listener: (e: T) => any): IDisposable
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EmitterOptions {
|
export interface EmitterOptions {
|
||||||
emitLastValue?: boolean;
|
emitLastValue?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace Event {
|
export namespace Event {
|
||||||
export const any = <T>(...children: Event<T>[]): Event<T> => {
|
export const any = <T>(...children: Event<T>[]): Event<T> => {
|
||||||
return (listener: (e: T) => void) => {
|
return (listener: (e: T) => void) => {
|
||||||
const disposables = children.map((child) => child(listener));
|
const disposables = children.map((child) => child(listener))
|
||||||
|
|
||||||
return {
|
return {
|
||||||
dispose: () => {
|
dispose: () => {
|
||||||
disposables.forEach((d) => {
|
disposables.forEach((d) => {
|
||||||
d.dispose();
|
d.dispose()
|
||||||
});
|
})
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// dumb event emitter with better typings than nodes event emitter
|
// dumb event emitter with better typings than nodes event emitter
|
||||||
// https://github.com/microsoft/vscode/blob/master/src/vs/base/common/event.ts
|
// https://github.com/microsoft/vscode/blob/master/src/vs/base/common/event.ts
|
||||||
export class Emitter<T> implements IDisposable {
|
export class Emitter<T> implements IDisposable {
|
||||||
private _event: Event<T>;
|
private _event: Event<T>
|
||||||
|
|
||||||
private _last: T;
|
private _last: T
|
||||||
private _listeners: Array<(e: T) => any> = [];
|
private _listeners: Array<(e: T) => any> = []
|
||||||
private _disposed: boolean = false;
|
private _disposed: boolean = false
|
||||||
|
|
||||||
constructor(private readonly options?: EmitterOptions) {}
|
constructor(private readonly options?: EmitterOptions) {}
|
||||||
|
|
||||||
get event() {
|
get event() {
|
||||||
if (!this._event) {
|
if (!this._event) {
|
||||||
this._event = (listener: (e: T) => void): IDisposable => {
|
this._event = (listener: (e: T) => void): IDisposable => {
|
||||||
if (this.options?.emitLastValue && this._last !== undefined) {
|
if (this.options?.emitLastValue && this._last !== undefined) {
|
||||||
listener(this._last);
|
listener(this._last)
|
||||||
}
|
}
|
||||||
|
|
||||||
this._listeners.push(listener);
|
this._listeners.push(listener)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
dispose: () => {
|
dispose: () => {
|
||||||
const index = this._listeners.indexOf(listener);
|
const index = this._listeners.indexOf(listener)
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
this._listeners.splice(index, 1);
|
this._listeners.splice(index, 1)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
};
|
return this._event
|
||||||
};
|
|
||||||
}
|
}
|
||||||
return this._event;
|
|
||||||
}
|
|
||||||
|
|
||||||
public fire(e: T) {
|
public fire(e: T) {
|
||||||
this._last = e;
|
this._last = e
|
||||||
this._listeners.forEach((listener) => {
|
this._listeners.forEach((listener) => {
|
||||||
listener(e);
|
listener(e)
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public dispose() {
|
public dispose() {
|
||||||
this._listeners = [];
|
this._listeners = []
|
||||||
this._disposed = true;
|
this._disposed = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type EventHandler = HTMLElement | HTMLDocument | Window;
|
export type EventHandler = HTMLElement | HTMLDocument | Window
|
||||||
|
|
||||||
export const addDisposableListener = <K extends keyof HTMLElementEventMap>(
|
export const addDisposableListener = <K extends keyof HTMLElementEventMap>(
|
||||||
element: EventHandler,
|
element: EventHandler,
|
||||||
type: K,
|
type: K,
|
||||||
listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any,
|
listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any,
|
||||||
options?: boolean | AddEventListenerOptions
|
options?: boolean | AddEventListenerOptions
|
||||||
): IDisposable => {
|
): IDisposable => {
|
||||||
element.addEventListener(type, listener, options);
|
element.addEventListener(type, listener, options)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
dispose: () => {
|
dispose: () => {
|
||||||
element.removeEventListener(type, listener);
|
element.removeEventListener(type, listener)
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
export function debounce<T extends Function>(cb: T, wait: number) {
|
export function debounce<T extends Function>(cb: T, wait: number) {
|
||||||
let timeout: NodeJS.Timeout;
|
let timeout: NodeJS.Timeout
|
||||||
|
|
||||||
const callable = (...args: any) => {
|
const callable = (...args: any) => {
|
||||||
clearTimeout(timeout);
|
clearTimeout(timeout)
|
||||||
timeout = setTimeout(() => cb(...args), wait);
|
timeout = setTimeout(() => cb(...args), wait)
|
||||||
};
|
}
|
||||||
return <T>(<any>callable);
|
return <T>(<any>callable)
|
||||||
}
|
}
|
||||||
|
@ -1,244 +1,246 @@
|
|||||||
import {
|
import {
|
||||||
IView,
|
IView,
|
||||||
SplitView,
|
SplitView,
|
||||||
Orientation,
|
Orientation,
|
||||||
Sizing,
|
Sizing,
|
||||||
LayoutPriority,
|
LayoutPriority,
|
||||||
} from "../splitview/splitview";
|
} from '../splitview/splitview'
|
||||||
import { Emitter, Event } from "../events";
|
import { Emitter, Event } from '../events'
|
||||||
import { INodeDescriptor } from "./gridview";
|
import { INodeDescriptor } from './gridview'
|
||||||
import { Node } from "./types";
|
import { Node } from './types'
|
||||||
import { CompositeDisposable, IDisposable, Disposable } from "../lifecycle";
|
import { CompositeDisposable, IDisposable, Disposable } from '../lifecycle'
|
||||||
|
|
||||||
export class BranchNode extends CompositeDisposable implements IView {
|
export class BranchNode extends CompositeDisposable implements IView {
|
||||||
readonly element: HTMLElement;
|
readonly element: HTMLElement
|
||||||
private splitview: SplitView;
|
private splitview: SplitView
|
||||||
private _orthogonalSize: number;
|
private _orthogonalSize: number
|
||||||
private _size: number;
|
private _size: number
|
||||||
public readonly children: Node[] = [];
|
public readonly children: Node[] = []
|
||||||
|
|
||||||
private readonly _onDidChange = new Emitter<number | undefined>();
|
private readonly _onDidChange = new Emitter<number | undefined>()
|
||||||
readonly onDidChange: Event<number | undefined> = this._onDidChange.event;
|
readonly onDidChange: Event<number | undefined> = this._onDidChange.event
|
||||||
|
|
||||||
get width(): number {
|
get width(): number {
|
||||||
return this.orientation === Orientation.HORIZONTAL
|
return this.orientation === Orientation.HORIZONTAL
|
||||||
? this.size
|
? this.size
|
||||||
: this.orthogonalSize;
|
: this.orthogonalSize
|
||||||
}
|
|
||||||
|
|
||||||
get height(): number {
|
|
||||||
return this.orientation === Orientation.HORIZONTAL
|
|
||||||
? this.orthogonalSize
|
|
||||||
: this.size;
|
|
||||||
}
|
|
||||||
|
|
||||||
get minimumSize(): number {
|
|
||||||
return this.children.length === 0
|
|
||||||
? 0
|
|
||||||
: Math.max(...this.children.map((c) => c.minimumOrthogonalSize));
|
|
||||||
}
|
|
||||||
|
|
||||||
get maximumSize(): number {
|
|
||||||
return Math.min(...this.children.map((c) => c.maximumOrthogonalSize));
|
|
||||||
}
|
|
||||||
|
|
||||||
get minimumOrthogonalSize(): number {
|
|
||||||
return this.splitview.minimumSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
get maximumOrthogonalSize(): number {
|
|
||||||
return this.splitview.maximumSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
get orthogonalSize() {
|
|
||||||
return this._orthogonalSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
get size() {
|
|
||||||
return this._size;
|
|
||||||
}
|
|
||||||
|
|
||||||
get minimumWidth(): number {
|
|
||||||
return this.orientation === Orientation.HORIZONTAL
|
|
||||||
? this.minimumOrthogonalSize
|
|
||||||
: this.minimumSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
get snapSize() {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
get minimumHeight(): number {
|
|
||||||
return this.orientation === Orientation.HORIZONTAL
|
|
||||||
? this.minimumSize
|
|
||||||
: this.minimumOrthogonalSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
get maximumWidth(): number {
|
|
||||||
return this.orientation === Orientation.HORIZONTAL
|
|
||||||
? this.maximumOrthogonalSize
|
|
||||||
: this.maximumSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
get maximumHeight(): number {
|
|
||||||
return this.orientation === Orientation.HORIZONTAL
|
|
||||||
? this.maximumSize
|
|
||||||
: this.maximumOrthogonalSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
get priority(): LayoutPriority {
|
|
||||||
if (this.children.length === 0) {
|
|
||||||
return LayoutPriority.Normal;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const priorities = this.children.map((c) =>
|
get height(): number {
|
||||||
typeof c.priority === "undefined" ? LayoutPriority.Normal : c.priority
|
return this.orientation === Orientation.HORIZONTAL
|
||||||
);
|
? this.orthogonalSize
|
||||||
|
: this.size
|
||||||
if (priorities.some((p) => p === LayoutPriority.High)) {
|
|
||||||
return LayoutPriority.High;
|
|
||||||
} else if (priorities.some((p) => p === LayoutPriority.Low)) {
|
|
||||||
return LayoutPriority.Low;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return LayoutPriority.Normal;
|
get minimumSize(): number {
|
||||||
}
|
return this.children.length === 0
|
||||||
|
? 0
|
||||||
constructor(
|
: Math.max(...this.children.map((c) => c.minimumOrthogonalSize))
|
||||||
readonly orientation: Orientation,
|
|
||||||
readonly proportionalLayout: boolean,
|
|
||||||
size: number = 0,
|
|
||||||
orthogonalSize: number,
|
|
||||||
|
|
||||||
childDescriptors?: INodeDescriptor[]
|
|
||||||
) {
|
|
||||||
super();
|
|
||||||
this._orthogonalSize = orthogonalSize;
|
|
||||||
this._size = size;
|
|
||||||
this.element = document.createElement("div");
|
|
||||||
this.element.className = "branch-node";
|
|
||||||
|
|
||||||
if (!childDescriptors) {
|
|
||||||
this.splitview = new SplitView(this.element, {
|
|
||||||
orientation: this.orientation,
|
|
||||||
proportionalLayout,
|
|
||||||
});
|
|
||||||
this.splitview.layout(this.size, this.orthogonalSize);
|
|
||||||
} else {
|
|
||||||
const descriptor = {
|
|
||||||
views: childDescriptors.map((childDescriptor) => {
|
|
||||||
return {
|
|
||||||
view: childDescriptor.node,
|
|
||||||
size: childDescriptor.node.size,
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
size: this.orthogonalSize,
|
|
||||||
};
|
|
||||||
|
|
||||||
this.children = childDescriptors.map((c) => c.node);
|
|
||||||
this.splitview = new SplitView(this.element, {
|
|
||||||
orientation: this.orientation,
|
|
||||||
descriptor,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.addDisposables(
|
get maximumSize(): number {
|
||||||
this.splitview.onDidSashEnd(() => {
|
return Math.min(...this.children.map((c) => c.maximumOrthogonalSize))
|
||||||
this._onDidChange.fire(undefined);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
moveChild(from: number, to: number): void {
|
|
||||||
if (from === to) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (from < 0 || from >= this.children.length) {
|
get minimumOrthogonalSize(): number {
|
||||||
throw new Error("Invalid from index");
|
return this.splitview.minimumSize
|
||||||
}
|
}
|
||||||
|
|
||||||
if (from < to) {
|
get maximumOrthogonalSize(): number {
|
||||||
to--;
|
return this.splitview.maximumSize
|
||||||
}
|
}
|
||||||
|
|
||||||
this.splitview.moveView(from, to);
|
get orthogonalSize() {
|
||||||
|
return this._orthogonalSize
|
||||||
const child = this._removeChild(from);
|
|
||||||
this._addChild(child, to);
|
|
||||||
}
|
|
||||||
|
|
||||||
getChildSize(index: number): number {
|
|
||||||
if (index < 0 || index >= this.children.length) {
|
|
||||||
throw new Error("Invalid index");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.splitview.getViewSize(index);
|
get size() {
|
||||||
}
|
return this._size
|
||||||
|
|
||||||
resizeChild(index: number, size: number): void {
|
|
||||||
if (index < 0 || index >= this.children.length) {
|
|
||||||
throw new Error("Invalid index");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.splitview.resizeView(index, size);
|
get minimumWidth(): number {
|
||||||
}
|
return this.orientation === Orientation.HORIZONTAL
|
||||||
|
? this.minimumOrthogonalSize
|
||||||
public layout(size: number, orthogonalSize: number) {
|
: this.minimumSize
|
||||||
this._size = orthogonalSize;
|
|
||||||
this._orthogonalSize = size;
|
|
||||||
|
|
||||||
this.splitview.layout(this.size, this.orthogonalSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
public addChild(node: Node, size: number | Sizing, index: number): void {
|
|
||||||
if (index < 0 || index > this.children.length) {
|
|
||||||
throw new Error("Invalid index");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.splitview.addView(node, size, index);
|
get snapSize() {
|
||||||
this._addChild(node, index);
|
return undefined
|
||||||
}
|
|
||||||
|
|
||||||
public removeChild(index: number, sizing?: Sizing) {
|
|
||||||
if (index < 0 || index >= this.children.length) {
|
|
||||||
throw new Error("Invalid index");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.splitview.removeView(index, sizing);
|
get minimumHeight(): number {
|
||||||
this._removeChild(index);
|
return this.orientation === Orientation.HORIZONTAL
|
||||||
}
|
? this.minimumSize
|
||||||
|
: this.minimumOrthogonalSize
|
||||||
|
}
|
||||||
|
|
||||||
private _addChild(node: Node, index: number): void {
|
get maximumWidth(): number {
|
||||||
this.children.splice(index, 0, node);
|
return this.orientation === Orientation.HORIZONTAL
|
||||||
this.setupChildrenEvents();
|
? this.maximumOrthogonalSize
|
||||||
}
|
: this.maximumSize
|
||||||
|
}
|
||||||
|
|
||||||
private _removeChild(index: number): Node {
|
get maximumHeight(): number {
|
||||||
const first = index === 0;
|
return this.orientation === Orientation.HORIZONTAL
|
||||||
const last = index === this.children.length - 1;
|
? this.maximumSize
|
||||||
const [child] = this.children.splice(index, 1);
|
: this.maximumOrthogonalSize
|
||||||
this.setupChildrenEvents();
|
}
|
||||||
|
|
||||||
return child;
|
get priority(): LayoutPriority {
|
||||||
}
|
if (this.children.length === 0) {
|
||||||
|
return LayoutPriority.Normal
|
||||||
|
}
|
||||||
|
|
||||||
private _childrenDisposable: IDisposable = Disposable.NONE;
|
const priorities = this.children.map((c) =>
|
||||||
|
typeof c.priority === 'undefined'
|
||||||
|
? LayoutPriority.Normal
|
||||||
|
: c.priority
|
||||||
|
)
|
||||||
|
|
||||||
private setupChildrenEvents() {
|
if (priorities.some((p) => p === LayoutPriority.High)) {
|
||||||
this._childrenDisposable.dispose();
|
return LayoutPriority.High
|
||||||
|
} else if (priorities.some((p) => p === LayoutPriority.Low)) {
|
||||||
|
return LayoutPriority.Low
|
||||||
|
}
|
||||||
|
|
||||||
this._childrenDisposable = Event.any(
|
return LayoutPriority.Normal
|
||||||
...this.children.map((c) => c.onDidChange)
|
}
|
||||||
)((e) => {
|
|
||||||
this._onDidChange.fire(e);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public dispose() {
|
constructor(
|
||||||
super.dispose();
|
readonly orientation: Orientation,
|
||||||
this._childrenDisposable.dispose();
|
readonly proportionalLayout: boolean,
|
||||||
this.splitview.dispose();
|
size: number = 0,
|
||||||
this.children.forEach((child) => child.dispose());
|
orthogonalSize: number,
|
||||||
}
|
|
||||||
|
childDescriptors?: INodeDescriptor[]
|
||||||
|
) {
|
||||||
|
super()
|
||||||
|
this._orthogonalSize = orthogonalSize
|
||||||
|
this._size = size
|
||||||
|
this.element = document.createElement('div')
|
||||||
|
this.element.className = 'branch-node'
|
||||||
|
|
||||||
|
if (!childDescriptors) {
|
||||||
|
this.splitview = new SplitView(this.element, {
|
||||||
|
orientation: this.orientation,
|
||||||
|
proportionalLayout,
|
||||||
|
})
|
||||||
|
this.splitview.layout(this.size, this.orthogonalSize)
|
||||||
|
} else {
|
||||||
|
const descriptor = {
|
||||||
|
views: childDescriptors.map((childDescriptor) => {
|
||||||
|
return {
|
||||||
|
view: childDescriptor.node,
|
||||||
|
size: childDescriptor.node.size,
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
size: this.orthogonalSize,
|
||||||
|
}
|
||||||
|
|
||||||
|
this.children = childDescriptors.map((c) => c.node)
|
||||||
|
this.splitview = new SplitView(this.element, {
|
||||||
|
orientation: this.orientation,
|
||||||
|
descriptor,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
this.addDisposables(
|
||||||
|
this.splitview.onDidSashEnd(() => {
|
||||||
|
this._onDidChange.fire(undefined)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
moveChild(from: number, to: number): void {
|
||||||
|
if (from === to) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (from < 0 || from >= this.children.length) {
|
||||||
|
throw new Error('Invalid from index')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (from < to) {
|
||||||
|
to--
|
||||||
|
}
|
||||||
|
|
||||||
|
this.splitview.moveView(from, to)
|
||||||
|
|
||||||
|
const child = this._removeChild(from)
|
||||||
|
this._addChild(child, to)
|
||||||
|
}
|
||||||
|
|
||||||
|
getChildSize(index: number): number {
|
||||||
|
if (index < 0 || index >= this.children.length) {
|
||||||
|
throw new Error('Invalid index')
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.splitview.getViewSize(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
resizeChild(index: number, size: number): void {
|
||||||
|
if (index < 0 || index >= this.children.length) {
|
||||||
|
throw new Error('Invalid index')
|
||||||
|
}
|
||||||
|
|
||||||
|
this.splitview.resizeView(index, size)
|
||||||
|
}
|
||||||
|
|
||||||
|
public layout(size: number, orthogonalSize: number) {
|
||||||
|
this._size = orthogonalSize
|
||||||
|
this._orthogonalSize = size
|
||||||
|
|
||||||
|
this.splitview.layout(this.size, this.orthogonalSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
public addChild(node: Node, size: number | Sizing, index: number): void {
|
||||||
|
if (index < 0 || index > this.children.length) {
|
||||||
|
throw new Error('Invalid index')
|
||||||
|
}
|
||||||
|
|
||||||
|
this.splitview.addView(node, size, index)
|
||||||
|
this._addChild(node, index)
|
||||||
|
}
|
||||||
|
|
||||||
|
public removeChild(index: number, sizing?: Sizing) {
|
||||||
|
if (index < 0 || index >= this.children.length) {
|
||||||
|
throw new Error('Invalid index')
|
||||||
|
}
|
||||||
|
|
||||||
|
this.splitview.removeView(index, sizing)
|
||||||
|
this._removeChild(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
private _addChild(node: Node, index: number): void {
|
||||||
|
this.children.splice(index, 0, node)
|
||||||
|
this.setupChildrenEvents()
|
||||||
|
}
|
||||||
|
|
||||||
|
private _removeChild(index: number): Node {
|
||||||
|
const first = index === 0
|
||||||
|
const last = index === this.children.length - 1
|
||||||
|
const [child] = this.children.splice(index, 1)
|
||||||
|
this.setupChildrenEvents()
|
||||||
|
|
||||||
|
return child
|
||||||
|
}
|
||||||
|
|
||||||
|
private _childrenDisposable: IDisposable = Disposable.NONE
|
||||||
|
|
||||||
|
private setupChildrenEvents() {
|
||||||
|
this._childrenDisposable.dispose()
|
||||||
|
|
||||||
|
this._childrenDisposable = Event.any(
|
||||||
|
...this.children.map((c) => c.onDidChange)
|
||||||
|
)((e) => {
|
||||||
|
this._onDidChange.fire(e)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public dispose() {
|
||||||
|
super.dispose()
|
||||||
|
this._childrenDisposable.dispose()
|
||||||
|
this.splitview.dispose()
|
||||||
|
this.children.forEach((child) => child.dispose())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,94 +1,94 @@
|
|||||||
import { IView, LayoutPriority, Orientation } from "../splitview/splitview";
|
import { IView, LayoutPriority, Orientation } from '../splitview/splitview'
|
||||||
import { Emitter, Event } from "../events";
|
import { Emitter, Event } from '../events'
|
||||||
import { IGridView } from "./gridview";
|
import { IGridView } from './gridview'
|
||||||
|
|
||||||
export class LeafNode implements IView {
|
export class LeafNode implements IView {
|
||||||
private readonly _onDidChange = new Emitter<number | undefined>();
|
private readonly _onDidChange = new Emitter<number | undefined>()
|
||||||
readonly onDidChange: Event<number | undefined> = this._onDidChange.event;
|
readonly onDidChange: Event<number | undefined> = this._onDidChange.event
|
||||||
private _size: number;
|
private _size: number
|
||||||
private _orthogonalSize: number;
|
private _orthogonalSize: number
|
||||||
|
|
||||||
public dispose() {}
|
public dispose() {}
|
||||||
|
|
||||||
private get minimumWidth(): number {
|
private get minimumWidth(): number {
|
||||||
return this.view.minimumWidth;
|
return this.view.minimumWidth
|
||||||
}
|
}
|
||||||
|
|
||||||
private get maximumWidth(): number {
|
private get maximumWidth(): number {
|
||||||
return this.view.maximumWidth;
|
return this.view.maximumWidth
|
||||||
}
|
}
|
||||||
|
|
||||||
private get minimumHeight(): number {
|
private get minimumHeight(): number {
|
||||||
return this.view.minimumHeight;
|
return this.view.minimumHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
private get maximumHeight(): number {
|
private get maximumHeight(): number {
|
||||||
return this.view.maximumHeight;
|
return this.view.maximumHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
get priority(): LayoutPriority | undefined {
|
get priority(): LayoutPriority | undefined {
|
||||||
return this.view.priority;
|
return this.view.priority
|
||||||
}
|
}
|
||||||
|
|
||||||
get snapSize() {
|
get snapSize() {
|
||||||
return this.view.snap ? this.minimumSize / 2 : undefined;
|
return this.view.snap ? this.minimumSize / 2 : undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
get minimumSize(): number {
|
get minimumSize(): number {
|
||||||
return this.orientation === Orientation.HORIZONTAL
|
return this.orientation === Orientation.HORIZONTAL
|
||||||
? this.minimumHeight
|
? this.minimumHeight
|
||||||
: this.minimumWidth;
|
: this.minimumWidth
|
||||||
}
|
}
|
||||||
|
|
||||||
get maximumSize(): number {
|
get maximumSize(): number {
|
||||||
return this.orientation === Orientation.HORIZONTAL
|
return this.orientation === Orientation.HORIZONTAL
|
||||||
? this.maximumHeight
|
? this.maximumHeight
|
||||||
: this.maximumWidth;
|
: this.maximumWidth
|
||||||
}
|
}
|
||||||
|
|
||||||
get minimumOrthogonalSize(): number {
|
get minimumOrthogonalSize(): number {
|
||||||
return this.orientation === Orientation.HORIZONTAL
|
return this.orientation === Orientation.HORIZONTAL
|
||||||
? this.minimumWidth
|
? this.minimumWidth
|
||||||
: this.minimumHeight;
|
: this.minimumHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
get maximumOrthogonalSize(): number {
|
get maximumOrthogonalSize(): number {
|
||||||
return this.orientation === Orientation.HORIZONTAL
|
return this.orientation === Orientation.HORIZONTAL
|
||||||
? this.maximumWidth
|
? this.maximumWidth
|
||||||
: this.maximumHeight;
|
: this.maximumHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
get orthogonalSize() {
|
get orthogonalSize() {
|
||||||
return this._orthogonalSize;
|
return this._orthogonalSize
|
||||||
}
|
}
|
||||||
|
|
||||||
get size() {
|
get size() {
|
||||||
return this._size;
|
return this._size
|
||||||
}
|
}
|
||||||
|
|
||||||
get element() {
|
get element() {
|
||||||
return this.view.element;
|
return this.view.element
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public readonly view: IGridView,
|
public readonly view: IGridView,
|
||||||
readonly orientation: Orientation,
|
readonly orientation: Orientation,
|
||||||
orthogonalSize: number,
|
orthogonalSize: number,
|
||||||
size: number = 0
|
size: number = 0
|
||||||
) {
|
) {
|
||||||
this._orthogonalSize = orthogonalSize;
|
this._orthogonalSize = orthogonalSize
|
||||||
this._size = size;
|
this._size = size
|
||||||
}
|
}
|
||||||
|
|
||||||
public layout(size: number, orthogonalSize: number) {
|
public layout(size: number, orthogonalSize: number) {
|
||||||
this._size = size;
|
this._size = size
|
||||||
this._orthogonalSize = orthogonalSize;
|
this._orthogonalSize = orthogonalSize
|
||||||
|
|
||||||
const [width, height] =
|
const [width, height] =
|
||||||
this.orientation === Orientation.HORIZONTAL
|
this.orientation === Orientation.HORIZONTAL
|
||||||
? [orthogonalSize, size]
|
? [orthogonalSize, size]
|
||||||
: [size, orthogonalSize];
|
: [size, orthogonalSize]
|
||||||
|
|
||||||
this.view.layout(width, height, 0, 0);
|
this.view.layout(width, height, 0, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { BranchNode } from "./branchNode";
|
import { BranchNode } from './branchNode'
|
||||||
import { LeafNode } from "./leafNode";
|
import { LeafNode } from './leafNode'
|
||||||
|
|
||||||
export type Node = BranchNode | LeafNode;
|
export type Node = BranchNode | LeafNode
|
||||||
|
@ -1,29 +1,29 @@
|
|||||||
.actions-bar {
|
.actions-bar {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
width: 28px;
|
width: 28px;
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
.actions-container {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: 0px;
|
align-items: center;
|
||||||
margin: 0px;
|
|
||||||
justify-content: flex-end;
|
|
||||||
|
|
||||||
a:active {
|
.actions-container {
|
||||||
-webkit-mask-size: 100% 100% !important;
|
display: flex;
|
||||||
mask-size: 100% 100% !important;
|
padding: 0px;
|
||||||
}
|
margin: 0px;
|
||||||
|
justify-content: flex-end;
|
||||||
|
|
||||||
.close-action {
|
a:active {
|
||||||
background-color: white;
|
-webkit-mask-size: 100% 100% !important;
|
||||||
height: 16px;
|
mask-size: 100% 100% !important;
|
||||||
width: 16px;
|
}
|
||||||
display: block;
|
|
||||||
-webkit-mask: var(--tab-close-icon) 50% 50% / 90% 90% no-repeat;
|
.close-action {
|
||||||
mask: var(--tab-close-icon) 50% 50% / 90% 90% no-repeat;
|
background-color: white;
|
||||||
margin-right: "0.5em";
|
height: 16px;
|
||||||
cursor: pointer;
|
width: 16px;
|
||||||
|
display: block;
|
||||||
|
-webkit-mask: var(--tab-close-icon) 50% 50% / 90% 90% no-repeat;
|
||||||
|
mask: var(--tab-close-icon) 50% 50% / 90% 90% no-repeat;
|
||||||
|
margin-right: '0.5em';
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
export class ActionContainer {
|
export class ActionContainer {
|
||||||
private _element: HTMLElement;
|
private _element: HTMLElement
|
||||||
private _list: HTMLElement;
|
private _list: HTMLElement
|
||||||
|
|
||||||
get element() {
|
get element() {
|
||||||
return this._element;
|
return this._element
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this._element = document.createElement("div");
|
this._element = document.createElement('div')
|
||||||
this._element.className = "actions-bar";
|
this._element.className = 'actions-bar'
|
||||||
|
|
||||||
this._list = document.createElement("ul");
|
this._list = document.createElement('ul')
|
||||||
this._list.className = "actions-container";
|
this._list.className = 'actions-container'
|
||||||
|
|
||||||
this._element.appendChild(this._list);
|
this._element.appendChild(this._list)
|
||||||
}
|
}
|
||||||
|
|
||||||
public add(element: HTMLElement) {
|
public add(element: HTMLElement) {
|
||||||
this._list.appendChild(element);
|
this._list.appendChild(element)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,124 +1,124 @@
|
|||||||
import { PanelOptions } from "../../layout/options";
|
import { PanelOptions } from '../../layout/options'
|
||||||
|
|
||||||
export const DATA_KEY = "splitview/transfer";
|
export const DATA_KEY = 'splitview/transfer'
|
||||||
|
|
||||||
export const isPanelTransferEvent = (event: DragEvent) => {
|
export const isPanelTransferEvent = (event: DragEvent) => {
|
||||||
return event.dataTransfer.types.includes(DATA_KEY);
|
return event.dataTransfer.types.includes(DATA_KEY)
|
||||||
};
|
}
|
||||||
|
|
||||||
export enum DragType {
|
export enum DragType {
|
||||||
ITEM = "group_drag",
|
ITEM = 'group_drag',
|
||||||
EXTERNAL = "external_group_drag",
|
EXTERNAL = 'external_group_drag',
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DragItem {
|
export interface DragItem {
|
||||||
itemId: string;
|
itemId: string
|
||||||
groupId: string;
|
groupId: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ExternalDragItem extends PanelOptions {}
|
export interface ExternalDragItem extends PanelOptions {}
|
||||||
|
|
||||||
export type DataObject = DragItem | ExternalDragItem;
|
export type DataObject = DragItem | ExternalDragItem
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine whether this data belong to that of an event that was started by
|
* Determine whether this data belong to that of an event that was started by
|
||||||
* dragging a tab component
|
* dragging a tab component
|
||||||
*/
|
*/
|
||||||
export const isTabDragEvent = (data: any): data is DragItem => {
|
export const isTabDragEvent = (data: any): data is DragItem => {
|
||||||
return data.type === DragType.ITEM;
|
return data.type === DragType.ITEM
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine whether this data belong to that of an event that was started by
|
* Determine whether this data belong to that of an event that was started by
|
||||||
* a custom drag-enable component
|
* a custom drag-enable component
|
||||||
*/
|
*/
|
||||||
export const isCustomDragEvent = (data: any): data is ExternalDragItem => {
|
export const isCustomDragEvent = (data: any): data is ExternalDragItem => {
|
||||||
return data.type === DragType.EXTERNAL;
|
return data.type === DragType.EXTERNAL
|
||||||
};
|
|
||||||
|
|
||||||
export const extractData = (event: DragEvent): DataObject => {
|
|
||||||
const data = JSON.parse(event.dataTransfer.getData(DATA_KEY));
|
|
||||||
|
|
||||||
if (!data) {
|
|
||||||
console.warn(`[dragEvent] ${DATA_KEY} data is missing`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof data.type !== "string") {
|
|
||||||
console.warn(`[dragEvent] invalid type ${data.type}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
};
|
|
||||||
|
|
||||||
class DataTransfer {
|
|
||||||
private map = new Map<string, string>();
|
|
||||||
|
|
||||||
public setData(format: string, data: string) {
|
|
||||||
this.map.set(format, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
public getData(format: string) {
|
|
||||||
const data = this.map.get(format);
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public has(format: string) {
|
|
||||||
return this.map.has(format);
|
|
||||||
}
|
|
||||||
|
|
||||||
public removeData(format: string) {
|
|
||||||
const data = this.getData(format);
|
|
||||||
this.map.delete(format);
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
get size() {
|
|
||||||
return this.map.size;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DataTransferSingleton = new DataTransfer();
|
export const extractData = (event: DragEvent): DataObject => {
|
||||||
|
const data = JSON.parse(event.dataTransfer.getData(DATA_KEY))
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
console.warn(`[dragEvent] ${DATA_KEY} data is missing`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof data.type !== 'string') {
|
||||||
|
console.warn(`[dragEvent] invalid type ${data.type}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
class DataTransfer {
|
||||||
|
private map = new Map<string, string>()
|
||||||
|
|
||||||
|
public setData(format: string, data: string) {
|
||||||
|
this.map.set(format, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
public getData(format: string) {
|
||||||
|
const data = this.map.get(format)
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
public has(format: string) {
|
||||||
|
return this.map.has(format)
|
||||||
|
}
|
||||||
|
|
||||||
|
public removeData(format: string) {
|
||||||
|
const data = this.getData(format)
|
||||||
|
this.map.delete(format)
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
get size() {
|
||||||
|
return this.map.size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DataTransferSingleton = new DataTransfer()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A singleton to store transfer data during drag & drop operations that are only valid within the application.
|
* A singleton to store transfer data during drag & drop operations that are only valid within the application.
|
||||||
*/
|
*/
|
||||||
export class LocalSelectionTransfer<T> {
|
export class LocalSelectionTransfer<T> {
|
||||||
private static readonly INSTANCE = new LocalSelectionTransfer();
|
private static readonly INSTANCE = new LocalSelectionTransfer()
|
||||||
|
|
||||||
private data?: T[];
|
private data?: T[]
|
||||||
private proto?: T;
|
private proto?: T
|
||||||
|
|
||||||
private constructor() {
|
private constructor() {
|
||||||
// protect against external instantiation
|
// protect against external instantiation
|
||||||
}
|
|
||||||
|
|
||||||
static getInstance<T>(): LocalSelectionTransfer<T> {
|
|
||||||
return LocalSelectionTransfer.INSTANCE as LocalSelectionTransfer<T>;
|
|
||||||
}
|
|
||||||
|
|
||||||
hasData(proto: T): boolean {
|
|
||||||
return proto && proto === this.proto;
|
|
||||||
}
|
|
||||||
|
|
||||||
clearData(proto: T): void {
|
|
||||||
if (this.hasData(proto)) {
|
|
||||||
this.proto = undefined;
|
|
||||||
this.data = undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getData(proto: T): T[] | undefined {
|
|
||||||
if (this.hasData(proto)) {
|
|
||||||
return this.data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined;
|
static getInstance<T>(): LocalSelectionTransfer<T> {
|
||||||
}
|
return LocalSelectionTransfer.INSTANCE as LocalSelectionTransfer<T>
|
||||||
|
}
|
||||||
setData(data: T[], proto: T): void {
|
|
||||||
if (proto) {
|
hasData(proto: T): boolean {
|
||||||
this.data = data;
|
return proto && proto === this.proto
|
||||||
this.proto = proto;
|
}
|
||||||
|
|
||||||
|
clearData(proto: T): void {
|
||||||
|
if (this.hasData(proto)) {
|
||||||
|
this.proto = undefined
|
||||||
|
this.data = undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getData(proto: T): T[] | undefined {
|
||||||
|
if (this.hasData(proto)) {
|
||||||
|
return this.data
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
setData(data: T[], proto: T): void {
|
||||||
|
if (proto) {
|
||||||
|
this.data = data
|
||||||
|
this.proto = proto
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,38 +1,38 @@
|
|||||||
.drop-target {
|
.drop-target {
|
||||||
position: relative;
|
|
||||||
|
|
||||||
.drop-target-dropzone {
|
|
||||||
position: absolute;
|
|
||||||
left: 0px;
|
|
||||||
top: 0px;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
z-index: 10000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.drop-target-selection {
|
|
||||||
position: relative;
|
position: relative;
|
||||||
pointer-events: none;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
background-color: var(--drag-over-background-color);
|
|
||||||
|
|
||||||
transition-duration: 0.15s;
|
.drop-target-dropzone {
|
||||||
transition-timing-function: ease-out;
|
position: absolute;
|
||||||
|
left: 0px;
|
||||||
|
top: 0px;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
z-index: 10000;
|
||||||
|
}
|
||||||
|
|
||||||
&.left,
|
.drop-target-selection {
|
||||||
&.right {
|
position: relative;
|
||||||
width: 50%;
|
pointer-events: none;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
background-color: var(--drag-over-background-color);
|
||||||
|
|
||||||
|
transition-duration: 0.15s;
|
||||||
|
transition-timing-function: ease-out;
|
||||||
|
|
||||||
|
&.left,
|
||||||
|
&.right {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
&.right {
|
||||||
|
transform: translate(100%, 0%);
|
||||||
|
}
|
||||||
|
&.bottom {
|
||||||
|
transform: translate(0%, 100%);
|
||||||
|
}
|
||||||
|
&.top,
|
||||||
|
&.bottom {
|
||||||
|
height: 50%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
&.right {
|
|
||||||
transform: translate(100%, 0%);
|
|
||||||
}
|
|
||||||
&.bottom {
|
|
||||||
transform: translate(0%, 100%);
|
|
||||||
}
|
|
||||||
&.top,
|
|
||||||
&.bottom {
|
|
||||||
height: 50%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,170 +1,170 @@
|
|||||||
import { Emitter, Event } from "../../events";
|
import { Emitter, Event } from '../../events'
|
||||||
import { DataTransferSingleton } from "./dataTransfer";
|
import { DataTransferSingleton } from './dataTransfer'
|
||||||
|
|
||||||
export enum Position {
|
export enum Position {
|
||||||
Top = "Top",
|
Top = 'Top',
|
||||||
Left = "Left",
|
Left = 'Left',
|
||||||
Bottom = "Bottom",
|
Bottom = 'Bottom',
|
||||||
Right = "Right",
|
Right = 'Right',
|
||||||
Center = "Center",
|
Center = 'Center',
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DroptargetEvent {
|
export interface DroptargetEvent {
|
||||||
position: Position;
|
position: Position
|
||||||
event: DragEvent;
|
event: DragEvent
|
||||||
}
|
}
|
||||||
|
|
||||||
const HAS_PROCESSED_KEY = "__drop_target_processed__";
|
const HAS_PROCESSED_KEY = '__drop_target_processed__'
|
||||||
|
|
||||||
export const hasProcessed = (event: DragEvent) =>
|
export const hasProcessed = (event: DragEvent) =>
|
||||||
!!(event as any)[HAS_PROCESSED_KEY];
|
!!(event as any)[HAS_PROCESSED_KEY]
|
||||||
|
|
||||||
// tagging events as processed is better than calling .stopPropagation() which is the root of all evil
|
// tagging events as processed is better than calling .stopPropagation() which is the root of all evil
|
||||||
const setEventAsProcessed = (event: DragEvent) => {
|
const setEventAsProcessed = (event: DragEvent) => {
|
||||||
event[HAS_PROCESSED_KEY] = true;
|
event[HAS_PROCESSED_KEY] = true
|
||||||
};
|
}
|
||||||
|
|
||||||
const toggleClassName = (
|
const toggleClassName = (
|
||||||
element: HTMLElement,
|
element: HTMLElement,
|
||||||
className: string,
|
className: string,
|
||||||
addOrRemove: boolean
|
addOrRemove: boolean
|
||||||
) => {
|
) => {
|
||||||
if (addOrRemove && !element.classList.contains(className)) {
|
if (addOrRemove && !element.classList.contains(className)) {
|
||||||
element.classList.add(className);
|
element.classList.add(className)
|
||||||
} else if (!addOrRemove && element.classList.contains(className)) {
|
} else if (!addOrRemove && element.classList.contains(className)) {
|
||||||
element.classList.remove(className);
|
element.classList.remove(className)
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export class Droptarget {
|
export class Droptarget {
|
||||||
private target: HTMLElement;
|
private target: HTMLElement
|
||||||
private overlay: HTMLElement;
|
private overlay: HTMLElement
|
||||||
private state: Position | undefined;
|
private state: Position | undefined
|
||||||
|
|
||||||
private readonly _onDidChange = new Emitter<DroptargetEvent>();
|
private readonly _onDidChange = new Emitter<DroptargetEvent>()
|
||||||
readonly onDidChange: Event<DroptargetEvent> = this._onDidChange.event;
|
readonly onDidChange: Event<DroptargetEvent> = this._onDidChange.event
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private element: HTMLElement,
|
private element: HTMLElement,
|
||||||
private options: {
|
private options: {
|
||||||
isDisabled: () => boolean;
|
isDisabled: () => boolean
|
||||||
isDirectional: boolean;
|
isDirectional: boolean
|
||||||
id: string;
|
id: string
|
||||||
enableExternalDragEvents?: boolean;
|
enableExternalDragEvents?: boolean
|
||||||
}
|
}
|
||||||
) {
|
|
||||||
this.element.addEventListener("dragenter", this.onDragEnter);
|
|
||||||
}
|
|
||||||
|
|
||||||
public dispose() {
|
|
||||||
this._onDidChange.dispose();
|
|
||||||
this.removeDropTarget();
|
|
||||||
this.element.removeEventListener("dragenter", this.onDragEnter);
|
|
||||||
}
|
|
||||||
|
|
||||||
private onDragEnter = (event: DragEvent) => {
|
|
||||||
if (
|
|
||||||
!this.options.enableExternalDragEvents &&
|
|
||||||
!DataTransferSingleton.has(this.options.id)
|
|
||||||
) {
|
) {
|
||||||
console.debug("[droptarget] invalid event");
|
this.element.addEventListener('dragenter', this.onDragEnter)
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.options.isDisabled()) {
|
public dispose() {
|
||||||
return;
|
this._onDidChange.dispose()
|
||||||
|
this.removeDropTarget()
|
||||||
|
this.element.removeEventListener('dragenter', this.onDragEnter)
|
||||||
}
|
}
|
||||||
|
|
||||||
event.preventDefault();
|
private onDragEnter = (event: DragEvent) => {
|
||||||
if (!this.target) {
|
if (
|
||||||
console.debug("[droptarget] created");
|
!this.options.enableExternalDragEvents &&
|
||||||
this.target = document.createElement("div");
|
!DataTransferSingleton.has(this.options.id)
|
||||||
this.target.className = "drop-target-dropzone";
|
) {
|
||||||
this.overlay = document.createElement("div");
|
console.debug('[droptarget] invalid event')
|
||||||
this.overlay.className = "drop-target-selection";
|
return
|
||||||
//
|
}
|
||||||
this.target.addEventListener("dragover", this.onDragOver);
|
|
||||||
this.target.addEventListener("dragleave", this.onDragLeave);
|
|
||||||
this.target.addEventListener("drop", this.onDrop);
|
|
||||||
this.target.appendChild(this.overlay);
|
|
||||||
|
|
||||||
this.element.classList.add("drop-target");
|
if (this.options.isDisabled()) {
|
||||||
this.element.append(this.target);
|
return
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
private onDrop = (event: DragEvent) => {
|
event.preventDefault()
|
||||||
if (
|
if (!this.target) {
|
||||||
!this.options.enableExternalDragEvents &&
|
console.debug('[droptarget] created')
|
||||||
!DataTransferSingleton.has(this.options.id)
|
this.target = document.createElement('div')
|
||||||
) {
|
this.target.className = 'drop-target-dropzone'
|
||||||
console.debug("[dragtarget] invalid");
|
this.overlay = document.createElement('div')
|
||||||
return;
|
this.overlay.className = 'drop-target-selection'
|
||||||
|
//
|
||||||
|
this.target.addEventListener('dragover', this.onDragOver)
|
||||||
|
this.target.addEventListener('dragleave', this.onDragLeave)
|
||||||
|
this.target.addEventListener('drop', this.onDrop)
|
||||||
|
this.target.appendChild(this.overlay)
|
||||||
|
|
||||||
|
this.element.classList.add('drop-target')
|
||||||
|
this.element.append(this.target)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.debug("[dragtarget] drop");
|
private onDrop = (event: DragEvent) => {
|
||||||
this.removeDropTarget();
|
if (
|
||||||
|
!this.options.enableExternalDragEvents &&
|
||||||
|
!DataTransferSingleton.has(this.options.id)
|
||||||
|
) {
|
||||||
|
console.debug('[dragtarget] invalid')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (!hasProcessed(event)) {
|
console.debug('[dragtarget] drop')
|
||||||
this._onDidChange.fire({ position: this.state, event });
|
this.removeDropTarget()
|
||||||
} else {
|
|
||||||
console.debug("[dragtarget] already processed");
|
|
||||||
}
|
|
||||||
this.state = undefined;
|
|
||||||
|
|
||||||
setEventAsProcessed(event);
|
if (!hasProcessed(event)) {
|
||||||
};
|
this._onDidChange.fire({ position: this.state, event })
|
||||||
|
} else {
|
||||||
|
console.debug('[dragtarget] already processed')
|
||||||
|
}
|
||||||
|
this.state = undefined
|
||||||
|
|
||||||
private onDragOver = (event: DragEvent) => {
|
setEventAsProcessed(event)
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
if (!this.options.isDirectional) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const width = this.target.clientWidth;
|
private onDragOver = (event: DragEvent) => {
|
||||||
const height = this.target.clientHeight;
|
event.preventDefault()
|
||||||
const x = event.offsetX;
|
|
||||||
const y = event.offsetY;
|
|
||||||
const xp = (100 * x) / width;
|
|
||||||
const yp = (100 * y) / height;
|
|
||||||
|
|
||||||
const isRight = xp > 80;
|
if (!this.options.isDirectional) {
|
||||||
const isLeft = xp < 20;
|
return
|
||||||
const isTop = !isRight && !isLeft && yp < 20;
|
}
|
||||||
const isBottom = !isRight && !isLeft && yp > 80;
|
|
||||||
|
|
||||||
toggleClassName(this.overlay, "right", isRight);
|
const width = this.target.clientWidth
|
||||||
toggleClassName(this.overlay, "left", isLeft);
|
const height = this.target.clientHeight
|
||||||
toggleClassName(this.overlay, "top", isTop);
|
const x = event.offsetX
|
||||||
toggleClassName(this.overlay, "bottom", isBottom);
|
const y = event.offsetY
|
||||||
|
const xp = (100 * x) / width
|
||||||
|
const yp = (100 * y) / height
|
||||||
|
|
||||||
if (isRight) {
|
const isRight = xp > 80
|
||||||
this.state = Position.Right;
|
const isLeft = xp < 20
|
||||||
} else if (isLeft) {
|
const isTop = !isRight && !isLeft && yp < 20
|
||||||
this.state = Position.Left;
|
const isBottom = !isRight && !isLeft && yp > 80
|
||||||
} else if (isTop) {
|
|
||||||
this.state = Position.Top;
|
toggleClassName(this.overlay, 'right', isRight)
|
||||||
} else if (isBottom) {
|
toggleClassName(this.overlay, 'left', isLeft)
|
||||||
this.state = Position.Bottom;
|
toggleClassName(this.overlay, 'top', isTop)
|
||||||
} else {
|
toggleClassName(this.overlay, 'bottom', isBottom)
|
||||||
this.state = Position.Center;
|
|
||||||
|
if (isRight) {
|
||||||
|
this.state = Position.Right
|
||||||
|
} else if (isLeft) {
|
||||||
|
this.state = Position.Left
|
||||||
|
} else if (isTop) {
|
||||||
|
this.state = Position.Top
|
||||||
|
} else if (isBottom) {
|
||||||
|
this.state = Position.Bottom
|
||||||
|
} else {
|
||||||
|
this.state = Position.Center
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
private onDragLeave = (event: DragEvent) => {
|
private onDragLeave = (event: DragEvent) => {
|
||||||
console.debug("[droptarget] leave");
|
console.debug('[droptarget] leave')
|
||||||
this.removeDropTarget();
|
this.removeDropTarget()
|
||||||
};
|
}
|
||||||
|
|
||||||
private removeDropTarget() {
|
private removeDropTarget() {
|
||||||
if (this.target) {
|
if (this.target) {
|
||||||
this.target.removeEventListener("dragover", this.onDragOver);
|
this.target.removeEventListener('dragover', this.onDragOver)
|
||||||
this.target.removeEventListener("dragleave", this.onDragLeave);
|
this.target.removeEventListener('dragleave', this.onDragLeave)
|
||||||
this.target.removeEventListener("drop", this.onDrop);
|
this.target.removeEventListener('drop', this.onDrop)
|
||||||
this.element.removeChild(this.target);
|
this.element.removeChild(this.target)
|
||||||
this.target = undefined;
|
this.target = undefined
|
||||||
this.element.classList.remove("drop-target");
|
this.element.classList.remove('drop-target')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
import { DroptargetEvent } from "./droptarget/droptarget";
|
import { DroptargetEvent } from './droptarget/droptarget'
|
||||||
import { IGroupPanel } from "./panel/types";
|
import { IGroupPanel } from './panel/types'
|
||||||
|
|
||||||
export interface TabDropEvent {
|
export interface TabDropEvent {
|
||||||
event: DroptargetEvent;
|
event: DroptargetEvent
|
||||||
index?: number;
|
index?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum MouseEventKind {
|
export enum MouseEventKind {
|
||||||
CLICK = "CLICK",
|
CLICK = 'CLICK',
|
||||||
CONTEXT_MENU = "CONTEXT_MENU",
|
CONTEXT_MENU = 'CONTEXT_MENU',
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LayoutMouseEvent {
|
export interface LayoutMouseEvent {
|
||||||
kind: MouseEventKind;
|
kind: MouseEventKind
|
||||||
event: MouseEvent;
|
event: MouseEvent
|
||||||
panel?: IGroupPanel;
|
panel?: IGroupPanel
|
||||||
tab?: boolean;
|
tab?: boolean
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
.groupview {
|
.groupview {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-color: var(--group-view-background-color);
|
background-color: var(--group-view-background-color);
|
||||||
|
|
||||||
&:focus {
|
&:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
|
||||||
|
|
||||||
&.empty {
|
|
||||||
.title-container {
|
|
||||||
display: none;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.content-container {
|
&.empty {
|
||||||
flex-grow: 1;
|
.title-container {
|
||||||
overflow: hidden;
|
display: none;
|
||||||
outline: none;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.content-container {
|
||||||
|
flex-grow: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,76 +1,76 @@
|
|||||||
import { IGroupview } from "../groupview";
|
import { IGroupview } from '../groupview'
|
||||||
import { Emitter, Event } from "../../events";
|
import { Emitter, Event } from '../../events'
|
||||||
import { ClosePanelResult } from "./parts";
|
import { ClosePanelResult } from './parts'
|
||||||
import { IGroupPanel } from "./types";
|
import { IGroupPanel } from './types'
|
||||||
import { IBaseViewApi, BaseViewApi } from "../../panel/api";
|
import { IBaseViewApi, BaseViewApi } from '../../panel/api'
|
||||||
|
|
||||||
interface ChangeVisibilityEvent {
|
interface ChangeVisibilityEvent {
|
||||||
isVisible: boolean;
|
isVisible: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IGroupPanelApi extends IBaseViewApi {
|
export interface IGroupPanelApi extends IBaseViewApi {
|
||||||
// events
|
// events
|
||||||
onDidDirtyChange: Event<boolean>;
|
onDidDirtyChange: Event<boolean>
|
||||||
onDidChangeVisibility: Event<ChangeVisibilityEvent>;
|
onDidChangeVisibility: Event<ChangeVisibilityEvent>
|
||||||
// misc
|
// misc
|
||||||
readonly isVisible: boolean;
|
readonly isVisible: boolean
|
||||||
group: IGroupview;
|
group: IGroupview
|
||||||
close: () => Promise<boolean>;
|
close: () => Promise<boolean>
|
||||||
canClose: () => Promise<ClosePanelResult>;
|
canClose: () => Promise<ClosePanelResult>
|
||||||
setClosePanelHook(callback: () => Promise<ClosePanelResult>): void;
|
setClosePanelHook(callback: () => Promise<ClosePanelResult>): void
|
||||||
}
|
}
|
||||||
|
|
||||||
export class GroupPanelApi extends BaseViewApi implements IGroupPanelApi {
|
export class GroupPanelApi extends BaseViewApi implements IGroupPanelApi {
|
||||||
private _isVisible: boolean;
|
private _isVisible: boolean
|
||||||
private _group: IGroupview;
|
private _group: IGroupview
|
||||||
private _closePanelCallback: () => Promise<ClosePanelResult>;
|
private _closePanelCallback: () => Promise<ClosePanelResult>
|
||||||
|
|
||||||
readonly _onDidDirtyChange = new Emitter<boolean>();
|
readonly _onDidDirtyChange = new Emitter<boolean>()
|
||||||
readonly onDidDirtyChange = this._onDidDirtyChange.event;
|
readonly onDidDirtyChange = this._onDidDirtyChange.event
|
||||||
readonly _onDidChangeVisibility = new Emitter<ChangeVisibilityEvent>({
|
readonly _onDidChangeVisibility = new Emitter<ChangeVisibilityEvent>({
|
||||||
emitLastValue: true,
|
emitLastValue: true,
|
||||||
});
|
})
|
||||||
readonly onDidChangeVisibility: Event<ChangeVisibilityEvent> = this
|
readonly onDidChangeVisibility: Event<ChangeVisibilityEvent> = this
|
||||||
._onDidChangeVisibility.event;
|
._onDidChangeVisibility.event
|
||||||
|
|
||||||
get isVisible() {
|
get isVisible() {
|
||||||
return this._isVisible;
|
return this._isVisible
|
||||||
}
|
}
|
||||||
|
|
||||||
get canClose() {
|
get canClose() {
|
||||||
return this._closePanelCallback;
|
return this._closePanelCallback
|
||||||
}
|
}
|
||||||
|
|
||||||
set group(value: IGroupview) {
|
set group(value: IGroupview) {
|
||||||
this._group = value;
|
this._group = value
|
||||||
}
|
}
|
||||||
|
|
||||||
get group() {
|
get group() {
|
||||||
return this._group;
|
return this._group
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(private panel: IGroupPanel, group: IGroupview) {
|
constructor(private panel: IGroupPanel, group: IGroupview) {
|
||||||
super();
|
super()
|
||||||
this._group = group;
|
this._group = group
|
||||||
|
|
||||||
this.addDisposables(
|
this.addDisposables(
|
||||||
this._onDidChangeVisibility,
|
this._onDidChangeVisibility,
|
||||||
this._onDidDirtyChange,
|
this._onDidDirtyChange,
|
||||||
this.onDidChangeVisibility((event) => {
|
this.onDidChangeVisibility((event) => {
|
||||||
this._isVisible = event.isVisible;
|
this._isVisible = event.isVisible
|
||||||
})
|
})
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
public close() {
|
public close() {
|
||||||
return this.group.closePanel(this.panel);
|
return this.group.closePanel(this.panel)
|
||||||
}
|
}
|
||||||
|
|
||||||
public setClosePanelHook(callback: () => Promise<ClosePanelResult>) {
|
public setClosePanelHook(callback: () => Promise<ClosePanelResult>) {
|
||||||
this._closePanelCallback = callback;
|
this._closePanelCallback = callback
|
||||||
}
|
}
|
||||||
|
|
||||||
public dispose() {
|
public dispose() {
|
||||||
super.dispose();
|
super.dispose()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,54 +1,55 @@
|
|||||||
import { CompositeDisposable, IDisposable } from "../../../lifecycle";
|
import { CompositeDisposable, IDisposable } from '../../../lifecycle'
|
||||||
import { Emitter, Event } from "../../../events";
|
import { Emitter, Event } from '../../../events'
|
||||||
import { trackFocus } from "../../../dom";
|
import { trackFocus } from '../../../dom'
|
||||||
|
|
||||||
export interface IContentContainer extends IDisposable {
|
export interface IContentContainer extends IDisposable {
|
||||||
onDidFocus: Event<void>;
|
onDidFocus: Event<void>
|
||||||
element: HTMLElement;
|
element: HTMLElement
|
||||||
openPanel: (panel: HTMLElement) => void;
|
openPanel: (panel: HTMLElement) => void
|
||||||
closePanel: () => void;
|
closePanel: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ContentContainer extends CompositeDisposable
|
export class ContentContainer
|
||||||
implements IContentContainer {
|
extends CompositeDisposable
|
||||||
private _element: HTMLElement;
|
implements IContentContainer {
|
||||||
private content: HTMLElement;
|
private _element: HTMLElement
|
||||||
|
private content: HTMLElement
|
||||||
|
|
||||||
private readonly _onDidFocus = new Emitter<void>();
|
private readonly _onDidFocus = new Emitter<void>()
|
||||||
readonly onDidFocus: Event<void> = this._onDidFocus.event;
|
readonly onDidFocus: Event<void> = this._onDidFocus.event
|
||||||
|
|
||||||
get element() {
|
get element() {
|
||||||
return this._element;
|
return this._element
|
||||||
}
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
this._element = document.createElement("div");
|
|
||||||
this._element.className = "content-container";
|
|
||||||
this._element.tabIndex = -1;
|
|
||||||
|
|
||||||
const { onDidBlur, onDidFocus } = trackFocus(this._element);
|
|
||||||
|
|
||||||
this.addDisposables(onDidFocus(() => this._onDidFocus.fire()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public openPanel(panel: HTMLElement) {
|
|
||||||
if (this.content) {
|
|
||||||
this._element.removeChild(this.content);
|
|
||||||
this.content = undefined;
|
|
||||||
}
|
}
|
||||||
this.content = panel;
|
|
||||||
this._element.appendChild(this.content);
|
|
||||||
}
|
|
||||||
|
|
||||||
public closePanel() {
|
constructor() {
|
||||||
if (this.content) {
|
super()
|
||||||
this._element.removeChild(this.content);
|
this._element = document.createElement('div')
|
||||||
this.content = undefined;
|
this._element.className = 'content-container'
|
||||||
|
this._element.tabIndex = -1
|
||||||
|
|
||||||
|
const { onDidBlur, onDidFocus } = trackFocus(this._element)
|
||||||
|
|
||||||
|
this.addDisposables(onDidFocus(() => this._onDidFocus.fire()))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public dispose() {
|
public openPanel(panel: HTMLElement) {
|
||||||
super.dispose();
|
if (this.content) {
|
||||||
}
|
this._element.removeChild(this.content)
|
||||||
|
this.content = undefined
|
||||||
|
}
|
||||||
|
this.content = panel
|
||||||
|
this._element.appendChild(this.content)
|
||||||
|
}
|
||||||
|
|
||||||
|
public closePanel() {
|
||||||
|
if (this.content) {
|
||||||
|
this._element.removeChild(this.content)
|
||||||
|
this.content = undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public dispose() {
|
||||||
|
super.dispose()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,141 +1,141 @@
|
|||||||
import { IGroupPanel, PanelInitParameters } from "./types";
|
import { IGroupPanel, PanelInitParameters } from './types'
|
||||||
import { GroupPanelApi } from "./api";
|
import { GroupPanelApi } from './api'
|
||||||
import { Event } from "../../events";
|
import { Event } from '../../events'
|
||||||
import { IGroupview, GroupChangeKind } from "../groupview";
|
import { IGroupview, GroupChangeKind } from '../groupview'
|
||||||
import { MutableDisposable, CompositeDisposable } from "../../lifecycle";
|
import { MutableDisposable, CompositeDisposable } from '../../lifecycle'
|
||||||
import { PanelContentPart, PanelHeaderPart, ClosePanelResult } from "./parts";
|
import { PanelContentPart, PanelHeaderPart, ClosePanelResult } from './parts'
|
||||||
import { PanelUpdateEvent } from "../../panel/types";
|
import { PanelUpdateEvent } from '../../panel/types'
|
||||||
|
|
||||||
export class DefaultPanel extends CompositeDisposable implements IGroupPanel {
|
export class DefaultPanel extends CompositeDisposable implements IGroupPanel {
|
||||||
private readonly mutableDisposable = new MutableDisposable();
|
private readonly mutableDisposable = new MutableDisposable()
|
||||||
|
|
||||||
private readonly api: GroupPanelApi;
|
private readonly api: GroupPanelApi
|
||||||
private _group: IGroupview;
|
private _group: IGroupview
|
||||||
private params: PanelInitParameters;
|
private params: PanelInitParameters
|
||||||
|
|
||||||
readonly onDidStateChange: Event<any>;
|
readonly onDidStateChange: Event<any>
|
||||||
|
|
||||||
get group() {
|
get group() {
|
||||||
return this._group;
|
return this._group
|
||||||
}
|
|
||||||
|
|
||||||
get header() {
|
|
||||||
return this.headerPart;
|
|
||||||
}
|
|
||||||
|
|
||||||
get content() {
|
|
||||||
return this.contentPart;
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
public readonly id: string,
|
|
||||||
private readonly headerPart: PanelHeaderPart,
|
|
||||||
private readonly contentPart: PanelContentPart
|
|
||||||
) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this.api = new GroupPanelApi(this, this._group);
|
|
||||||
this.onDidStateChange = this.api.onDidStateChange;
|
|
||||||
}
|
|
||||||
|
|
||||||
public setDirty(isDirty: boolean) {
|
|
||||||
this.api._onDidDirtyChange.fire(isDirty);
|
|
||||||
}
|
|
||||||
|
|
||||||
public close(): Promise<ClosePanelResult> {
|
|
||||||
if (this.api.canClose) {
|
|
||||||
return this.api.canClose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.resolve(ClosePanelResult.CLOSE);
|
get header() {
|
||||||
}
|
return this.headerPart
|
||||||
|
|
||||||
public toJSON(): object {
|
|
||||||
return {
|
|
||||||
id: this.id,
|
|
||||||
content: this.contentPart.toJSON(),
|
|
||||||
tab: this.headerPart.toJSON(),
|
|
||||||
props: this.params.params,
|
|
||||||
title: this.params.title,
|
|
||||||
suppressClosable: this.params.suppressClosable,
|
|
||||||
state: this.api.getState(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public fromJSON(data: object) {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
public update(params: PanelUpdateEvent): void {
|
|
||||||
this.params.params = { ...this.params.params, ...params };
|
|
||||||
|
|
||||||
this.contentPart.update(params.params);
|
|
||||||
this.api._onDidStateChange.fire();
|
|
||||||
}
|
|
||||||
|
|
||||||
public init(params: PanelInitParameters): void {
|
|
||||||
this.params = params;
|
|
||||||
this.api.setState(this.params.state);
|
|
||||||
if (this.content.init) {
|
|
||||||
this.content.init({ ...params, api: this.api });
|
|
||||||
}
|
}
|
||||||
if (this.header.init) {
|
|
||||||
this.header.init({ ...params, api: this.api });
|
get content() {
|
||||||
|
return this.contentPart
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public onHide() {
|
constructor(
|
||||||
//
|
public readonly id: string,
|
||||||
}
|
private readonly headerPart: PanelHeaderPart,
|
||||||
|
private readonly contentPart: PanelContentPart
|
||||||
|
) {
|
||||||
|
super()
|
||||||
|
|
||||||
public focus() {
|
this.api = new GroupPanelApi(this, this._group)
|
||||||
//
|
this.onDidStateChange = this.api.onDidStateChange
|
||||||
}
|
}
|
||||||
|
|
||||||
public setVisible(isGroupActive: boolean, group: IGroupview) {
|
public setDirty(isDirty: boolean) {
|
||||||
this._group = group;
|
this.api._onDidDirtyChange.fire(isDirty)
|
||||||
this.api.group = group;
|
}
|
||||||
|
|
||||||
this.mutableDisposable.value = this._group.onDidGroupChange((ev) => {
|
public close(): Promise<ClosePanelResult> {
|
||||||
if (ev.kind === GroupChangeKind.GROUP_ACTIVE) {
|
if (this.api.canClose) {
|
||||||
|
return this.api.canClose()
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve(ClosePanelResult.CLOSE)
|
||||||
|
}
|
||||||
|
|
||||||
|
public toJSON(): object {
|
||||||
|
return {
|
||||||
|
id: this.id,
|
||||||
|
content: this.contentPart.toJSON(),
|
||||||
|
tab: this.headerPart.toJSON(),
|
||||||
|
props: this.params.params,
|
||||||
|
title: this.params.title,
|
||||||
|
suppressClosable: this.params.suppressClosable,
|
||||||
|
state: this.api.getState(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public fromJSON(data: object) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
public update(params: PanelUpdateEvent): void {
|
||||||
|
this.params.params = { ...this.params.params, ...params }
|
||||||
|
|
||||||
|
this.contentPart.update(params.params)
|
||||||
|
this.api._onDidStateChange.fire()
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(params: PanelInitParameters): void {
|
||||||
|
this.params = params
|
||||||
|
this.api.setState(this.params.state)
|
||||||
|
if (this.content.init) {
|
||||||
|
this.content.init({ ...params, api: this.api })
|
||||||
|
}
|
||||||
|
if (this.header.init) {
|
||||||
|
this.header.init({ ...params, api: this.api })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public onHide() {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
public focus() {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
public setVisible(isGroupActive: boolean, group: IGroupview) {
|
||||||
|
this._group = group
|
||||||
|
this.api.group = group
|
||||||
|
|
||||||
|
this.mutableDisposable.value = this._group.onDidGroupChange((ev) => {
|
||||||
|
if (ev.kind === GroupChangeKind.GROUP_ACTIVE) {
|
||||||
|
this.api._onDidChangeVisibility.fire({
|
||||||
|
isVisible: this._group.isPanelActive(this),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
this.api._onDidChangeFocus.fire({ isFocused: isGroupActive })
|
||||||
this.api._onDidChangeVisibility.fire({
|
this.api._onDidChangeVisibility.fire({
|
||||||
isVisible: this._group.isPanelActive(this),
|
isVisible: this._group.isPanelActive(this),
|
||||||
});
|
})
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.api._onDidChangeFocus.fire({ isFocused: isGroupActive });
|
if (this.headerPart.setVisible) {
|
||||||
this.api._onDidChangeVisibility.fire({
|
this.headerPart.setVisible(
|
||||||
isVisible: this._group.isPanelActive(this),
|
this._group.isPanelActive(this),
|
||||||
});
|
isGroupActive
|
||||||
|
)
|
||||||
if (this.headerPart.setVisible) {
|
}
|
||||||
this.headerPart.setVisible(
|
if (this.contentPart.setVisible) {
|
||||||
this._group.isPanelActive(this),
|
this.contentPart.setVisible(
|
||||||
isGroupActive
|
this._group.isPanelActive(this),
|
||||||
);
|
isGroupActive
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (this.contentPart.setVisible) {
|
|
||||||
this.contentPart.setVisible(
|
public layout(width: number, height: number) {
|
||||||
this._group.isPanelActive(this),
|
// thw height of the panel excluded the height of the title/tab
|
||||||
isGroupActive
|
this.api._onDidPanelDimensionChange.fire({
|
||||||
);
|
width,
|
||||||
|
height: height - (this.group?.tabHeight || 0),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public layout(width: number, height: number) {
|
public dispose() {
|
||||||
// thw height of the panel excluded the height of the title/tab
|
this.api.dispose()
|
||||||
this.api._onDidPanelDimensionChange.fire({
|
this.mutableDisposable.dispose()
|
||||||
width,
|
|
||||||
height: height - (this.group?.tabHeight || 0),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public dispose() {
|
this.headerPart.dispose()
|
||||||
this.api.dispose();
|
this.contentPart.dispose()
|
||||||
this.mutableDisposable.dispose();
|
}
|
||||||
|
|
||||||
this.headerPart.dispose();
|
|
||||||
this.contentPart.dispose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,57 +1,57 @@
|
|||||||
import { IDisposable } from "../../lifecycle";
|
import { IDisposable } from '../../lifecycle'
|
||||||
import { IGroupview } from "../groupview";
|
import { IGroupview } from '../groupview'
|
||||||
import { IGroupAccessor } from "../../layout";
|
import { IGroupAccessor } from '../../layout'
|
||||||
import { IGroupPanelApi } from "./api";
|
import { IGroupPanelApi } from './api'
|
||||||
import { PanelInitParameters } from "./types";
|
import { PanelInitParameters } from './types'
|
||||||
import { Constructor } from "../../types";
|
import { Constructor } from '../../types'
|
||||||
|
|
||||||
export enum ClosePanelResult {
|
export enum ClosePanelResult {
|
||||||
CLOSE = "CLOSE",
|
CLOSE = 'CLOSE',
|
||||||
DONT_CLOSE = "DONT_CLOSE",
|
DONT_CLOSE = 'DONT_CLOSE',
|
||||||
}
|
}
|
||||||
|
|
||||||
interface BasePart extends IDisposable {
|
interface BasePart extends IDisposable {
|
||||||
init?(params: PartInitParameters): void;
|
init?(params: PartInitParameters): void
|
||||||
setVisible(isPanelVisible: boolean, isGroupVisible: boolean): void;
|
setVisible(isPanelVisible: boolean, isGroupVisible: boolean): void
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WatermarkPartInitParameters {
|
export interface WatermarkPartInitParameters {
|
||||||
accessor: IGroupAccessor;
|
accessor: IGroupAccessor
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PartInitParameters extends PanelInitParameters {
|
export interface PartInitParameters extends PanelInitParameters {
|
||||||
api: IGroupPanelApi;
|
api: IGroupPanelApi
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PanelHeaderPart extends BasePart {
|
export interface PanelHeaderPart extends BasePart {
|
||||||
id: string;
|
id: string
|
||||||
element: HTMLElement;
|
element: HTMLElement
|
||||||
layout?(height: string): void;
|
layout?(height: string): void
|
||||||
toJSON(): {};
|
toJSON(): {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PanelContentPart extends BasePart {
|
export interface PanelContentPart extends BasePart {
|
||||||
id: string;
|
id: string
|
||||||
element: HTMLElement;
|
element: HTMLElement
|
||||||
layout?(width: number, height: number): void;
|
layout?(width: number, height: number): void
|
||||||
close?(): Promise<ClosePanelResult>;
|
close?(): Promise<ClosePanelResult>
|
||||||
focus(): void;
|
focus(): void
|
||||||
onHide(): void;
|
onHide(): void
|
||||||
update(params: {}): void;
|
update(params: {}): void
|
||||||
toJSON(): {};
|
toJSON(): {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WatermarkPart extends IDisposable {
|
export interface WatermarkPart extends IDisposable {
|
||||||
init?: (params: WatermarkPartInitParameters) => void;
|
init?: (params: WatermarkPartInitParameters) => void
|
||||||
setVisible?(visible: boolean, group: IGroupview): void;
|
setVisible?(visible: boolean, group: IGroupview): void
|
||||||
element: HTMLElement;
|
element: HTMLElement
|
||||||
}
|
}
|
||||||
|
|
||||||
// constructors
|
// constructors
|
||||||
|
|
||||||
export interface PanelHeaderPartConstructor
|
export interface PanelHeaderPartConstructor
|
||||||
extends Constructor<PanelHeaderPart> {}
|
extends Constructor<PanelHeaderPart> {}
|
||||||
export interface PanelContentPartConstructor
|
export interface PanelContentPartConstructor
|
||||||
extends Constructor<PanelContentPart> {}
|
extends Constructor<PanelContentPart> {}
|
||||||
|
|
||||||
export interface WatermarkConstructor extends Constructor<WatermarkPart> {}
|
export interface WatermarkConstructor extends Constructor<WatermarkPart> {}
|
||||||
|
@ -1,155 +1,161 @@
|
|||||||
import { addDisposableListener, Emitter, Event } from "../../../events";
|
import { addDisposableListener, Emitter, Event } from '../../../events'
|
||||||
import { Droptarget, DroptargetEvent } from "../../droptarget/droptarget";
|
import { Droptarget, DroptargetEvent } from '../../droptarget/droptarget'
|
||||||
import { CompositeDisposable } from "../../../lifecycle";
|
import { CompositeDisposable } from '../../../lifecycle'
|
||||||
import { IGroupview } from "../../groupview";
|
import { IGroupview } from '../../groupview'
|
||||||
import {
|
import {
|
||||||
DataTransferSingleton,
|
DataTransferSingleton,
|
||||||
DATA_KEY,
|
DATA_KEY,
|
||||||
DragType,
|
DragType,
|
||||||
} from "../../droptarget/dataTransfer";
|
} from '../../droptarget/dataTransfer'
|
||||||
import { toggleClass } from "../../../dom";
|
import { toggleClass } from '../../../dom'
|
||||||
import { IGroupAccessor } from "../../../layout";
|
import { IGroupAccessor } from '../../../layout'
|
||||||
import {LayoutMouseEvent, MouseEventKind} from "../../events"
|
import { LayoutMouseEvent, MouseEventKind } from '../../events'
|
||||||
|
|
||||||
|
|
||||||
export interface ITab {
|
export interface ITab {
|
||||||
id: string;
|
id: string
|
||||||
element: HTMLElement;
|
element: HTMLElement
|
||||||
hasActiveDragEvent: boolean;
|
hasActiveDragEvent: boolean
|
||||||
setContent: (element: HTMLElement) => void;
|
setContent: (element: HTMLElement) => void
|
||||||
onChanged: Event<LayoutMouseEvent>;
|
onChanged: Event<LayoutMouseEvent>
|
||||||
onDropped: Event<DroptargetEvent>;
|
onDropped: Event<DroptargetEvent>
|
||||||
setActive(isActive: boolean): void;
|
setActive(isActive: boolean): void
|
||||||
startDragEvent(): void;
|
startDragEvent(): void
|
||||||
stopDragEvent(): void;
|
stopDragEvent(): void
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Tab extends CompositeDisposable implements ITab {
|
export class Tab extends CompositeDisposable implements ITab {
|
||||||
private _element: HTMLElement;
|
private _element: HTMLElement
|
||||||
private dragInPlayDetails: { id?: string; isDragging: boolean } = {
|
private dragInPlayDetails: { id?: string; isDragging: boolean } = {
|
||||||
isDragging: false,
|
isDragging: false,
|
||||||
};
|
|
||||||
private droptarget: Droptarget;
|
|
||||||
private content: HTMLElement;
|
|
||||||
|
|
||||||
private readonly _onChanged = new Emitter<LayoutMouseEvent>();
|
|
||||||
readonly onChanged: Event<LayoutMouseEvent> = this._onChanged.event;
|
|
||||||
|
|
||||||
private readonly _onDropped = new Emitter<DroptargetEvent>();
|
|
||||||
readonly onDropped: Event<DroptargetEvent> = this._onDropped.event;
|
|
||||||
|
|
||||||
public get element() {
|
|
||||||
return this._element;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get hasActiveDragEvent() {
|
|
||||||
return this.dragInPlayDetails?.isDragging;
|
|
||||||
}
|
|
||||||
|
|
||||||
public startDragEvent() {
|
|
||||||
this.dragInPlayDetails = { isDragging: true, id: this.accessor.id };
|
|
||||||
}
|
|
||||||
|
|
||||||
public stopDragEvent() {
|
|
||||||
this.dragInPlayDetails = { isDragging: false, id: undefined };
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
public id: string,
|
|
||||||
private readonly accessor: IGroupAccessor,
|
|
||||||
private group: IGroupview
|
|
||||||
) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this.addDisposables(this._onChanged, this._onDropped);
|
|
||||||
|
|
||||||
this._element = document.createElement("div");
|
|
||||||
this._element.className = "tab";
|
|
||||||
this._element.draggable = true;
|
|
||||||
|
|
||||||
this.addDisposables(
|
|
||||||
addDisposableListener(this._element, "mousedown", (event) => {
|
|
||||||
if (event.defaultPrevented) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this._onChanged.fire({ kind: MouseEventKind.CLICK,event });
|
|
||||||
}),
|
|
||||||
addDisposableListener(this._element, "contextmenu", (event) => {
|
|
||||||
this._onChanged.fire({ kind: MouseEventKind.CONTEXT_MENU, event });
|
|
||||||
}),
|
|
||||||
addDisposableListener(this._element, "dragstart", (event) => {
|
|
||||||
this.dragInPlayDetails = { isDragging: true, id: this.accessor.id };
|
|
||||||
|
|
||||||
// set up a custom ghost image
|
|
||||||
const dragImage = this._element.cloneNode(true) as HTMLElement;
|
|
||||||
|
|
||||||
const box = this._element.getBoundingClientRect();
|
|
||||||
|
|
||||||
// if the style of the tab is determined by CSS by a parent element that style will lost
|
|
||||||
// therefore we must explicility re-add the style features that we know will be lost
|
|
||||||
dragImage.style.height = `${box.height}px`;
|
|
||||||
dragImage.style.width = `${box.width}px`;
|
|
||||||
dragImage.style.position = "absolute";
|
|
||||||
dragImage.classList.add("dragging");
|
|
||||||
|
|
||||||
document.body.appendChild(dragImage);
|
|
||||||
event.dataTransfer.setDragImage(
|
|
||||||
dragImage,
|
|
||||||
event.offsetX,
|
|
||||||
event.offsetY
|
|
||||||
);
|
|
||||||
setTimeout(() => document.body.removeChild(dragImage), 0);
|
|
||||||
// configure the data-transfer object
|
|
||||||
|
|
||||||
const data = JSON.stringify({
|
|
||||||
type: DragType.ITEM,
|
|
||||||
itemId: this.id,
|
|
||||||
groupId: this.group.id,
|
|
||||||
});
|
|
||||||
DataTransferSingleton.setData(this.dragInPlayDetails.id, data);
|
|
||||||
|
|
||||||
event.dataTransfer.setData(DATA_KEY, data);
|
|
||||||
event.dataTransfer.effectAllowed = "move";
|
|
||||||
}),
|
|
||||||
addDisposableListener(this._element, "dragend", (ev) => {
|
|
||||||
// drop events fire before dragend so we can remove this safely
|
|
||||||
DataTransferSingleton.removeData(this.dragInPlayDetails.id);
|
|
||||||
this.dragInPlayDetails = {
|
|
||||||
isDragging: false,
|
|
||||||
id: undefined,
|
|
||||||
};
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
this.droptarget = new Droptarget(this._element, {
|
|
||||||
isDirectional: false,
|
|
||||||
isDisabled: () => this.dragInPlayDetails.isDragging,
|
|
||||||
id: this.accessor.id,
|
|
||||||
enableExternalDragEvents: this.accessor.options.enableExternalDragEvents,
|
|
||||||
});
|
|
||||||
|
|
||||||
this.addDisposables(
|
|
||||||
this.droptarget.onDidChange((event) => {
|
|
||||||
this._onDropped.fire(event);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public setActive(isActive: boolean) {
|
|
||||||
toggleClass(this.element, "active-tab", isActive);
|
|
||||||
toggleClass(this.element, "inactive-tab", !isActive);
|
|
||||||
}
|
|
||||||
|
|
||||||
public setContent(element: HTMLElement) {
|
|
||||||
if (this.content) {
|
|
||||||
this._element.removeChild(this.content);
|
|
||||||
}
|
}
|
||||||
this.content = element;
|
private droptarget: Droptarget
|
||||||
this._element.appendChild(this.content);
|
private content: HTMLElement
|
||||||
}
|
|
||||||
|
|
||||||
public dispose() {
|
private readonly _onChanged = new Emitter<LayoutMouseEvent>()
|
||||||
super.dispose();
|
readonly onChanged: Event<LayoutMouseEvent> = this._onChanged.event
|
||||||
this.droptarget.dispose();
|
|
||||||
}
|
private readonly _onDropped = new Emitter<DroptargetEvent>()
|
||||||
|
readonly onDropped: Event<DroptargetEvent> = this._onDropped.event
|
||||||
|
|
||||||
|
public get element() {
|
||||||
|
return this._element
|
||||||
|
}
|
||||||
|
|
||||||
|
public get hasActiveDragEvent() {
|
||||||
|
return this.dragInPlayDetails?.isDragging
|
||||||
|
}
|
||||||
|
|
||||||
|
public startDragEvent() {
|
||||||
|
this.dragInPlayDetails = { isDragging: true, id: this.accessor.id }
|
||||||
|
}
|
||||||
|
|
||||||
|
public stopDragEvent() {
|
||||||
|
this.dragInPlayDetails = { isDragging: false, id: undefined }
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public id: string,
|
||||||
|
private readonly accessor: IGroupAccessor,
|
||||||
|
private group: IGroupview
|
||||||
|
) {
|
||||||
|
super()
|
||||||
|
|
||||||
|
this.addDisposables(this._onChanged, this._onDropped)
|
||||||
|
|
||||||
|
this._element = document.createElement('div')
|
||||||
|
this._element.className = 'tab'
|
||||||
|
this._element.draggable = true
|
||||||
|
|
||||||
|
this.addDisposables(
|
||||||
|
addDisposableListener(this._element, 'mousedown', (event) => {
|
||||||
|
if (event.defaultPrevented) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this._onChanged.fire({ kind: MouseEventKind.CLICK, event })
|
||||||
|
}),
|
||||||
|
addDisposableListener(this._element, 'contextmenu', (event) => {
|
||||||
|
this._onChanged.fire({
|
||||||
|
kind: MouseEventKind.CONTEXT_MENU,
|
||||||
|
event,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
addDisposableListener(this._element, 'dragstart', (event) => {
|
||||||
|
this.dragInPlayDetails = {
|
||||||
|
isDragging: true,
|
||||||
|
id: this.accessor.id,
|
||||||
|
}
|
||||||
|
|
||||||
|
// set up a custom ghost image
|
||||||
|
const dragImage = this._element.cloneNode(true) as HTMLElement
|
||||||
|
|
||||||
|
const box = this._element.getBoundingClientRect()
|
||||||
|
|
||||||
|
// if the style of the tab is determined by CSS by a parent element that style will lost
|
||||||
|
// therefore we must explicility re-add the style features that we know will be lost
|
||||||
|
dragImage.style.height = `${box.height}px`
|
||||||
|
dragImage.style.width = `${box.width}px`
|
||||||
|
dragImage.style.position = 'absolute'
|
||||||
|
dragImage.classList.add('dragging')
|
||||||
|
|
||||||
|
document.body.appendChild(dragImage)
|
||||||
|
event.dataTransfer.setDragImage(
|
||||||
|
dragImage,
|
||||||
|
event.offsetX,
|
||||||
|
event.offsetY
|
||||||
|
)
|
||||||
|
setTimeout(() => document.body.removeChild(dragImage), 0)
|
||||||
|
// configure the data-transfer object
|
||||||
|
|
||||||
|
const data = JSON.stringify({
|
||||||
|
type: DragType.ITEM,
|
||||||
|
itemId: this.id,
|
||||||
|
groupId: this.group.id,
|
||||||
|
})
|
||||||
|
DataTransferSingleton.setData(this.dragInPlayDetails.id, data)
|
||||||
|
|
||||||
|
event.dataTransfer.setData(DATA_KEY, data)
|
||||||
|
event.dataTransfer.effectAllowed = 'move'
|
||||||
|
}),
|
||||||
|
addDisposableListener(this._element, 'dragend', (ev) => {
|
||||||
|
// drop events fire before dragend so we can remove this safely
|
||||||
|
DataTransferSingleton.removeData(this.dragInPlayDetails.id)
|
||||||
|
this.dragInPlayDetails = {
|
||||||
|
isDragging: false,
|
||||||
|
id: undefined,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
this.droptarget = new Droptarget(this._element, {
|
||||||
|
isDirectional: false,
|
||||||
|
isDisabled: () => this.dragInPlayDetails.isDragging,
|
||||||
|
id: this.accessor.id,
|
||||||
|
enableExternalDragEvents: this.accessor.options
|
||||||
|
.enableExternalDragEvents,
|
||||||
|
})
|
||||||
|
|
||||||
|
this.addDisposables(
|
||||||
|
this.droptarget.onDidChange((event) => {
|
||||||
|
this._onDropped.fire(event)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public setActive(isActive: boolean) {
|
||||||
|
toggleClass(this.element, 'active-tab', isActive)
|
||||||
|
toggleClass(this.element, 'inactive-tab', !isActive)
|
||||||
|
}
|
||||||
|
|
||||||
|
public setContent(element: HTMLElement) {
|
||||||
|
if (this.content) {
|
||||||
|
this._element.removeChild(this.content)
|
||||||
|
}
|
||||||
|
this.content = element
|
||||||
|
this._element.appendChild(this.content)
|
||||||
|
}
|
||||||
|
|
||||||
|
public dispose() {
|
||||||
|
super.dispose()
|
||||||
|
this.droptarget.dispose()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
import { IGroupview } from "../groupview";
|
import { IGroupview } from '../groupview'
|
||||||
import { IDisposable, ISerializable } from "../../lifecycle";
|
import { IDisposable, ISerializable } from '../../lifecycle'
|
||||||
import { Event } from "../../events";
|
import { Event } from '../../events'
|
||||||
import { PanelHeaderPart, PanelContentPart, ClosePanelResult } from "./parts";
|
import { PanelHeaderPart, PanelContentPart, ClosePanelResult } from './parts'
|
||||||
import { InitParameters, IPanel } from "../../panel/types";
|
import { InitParameters, IPanel } from '../../panel/types'
|
||||||
|
|
||||||
// init parameters
|
// init parameters
|
||||||
|
|
||||||
export interface PanelInitParameters extends InitParameters {
|
export interface PanelInitParameters extends InitParameters {
|
||||||
title: string;
|
title: string
|
||||||
suppressClosable?: boolean;
|
suppressClosable?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
// constructors
|
// constructors
|
||||||
@ -16,15 +16,15 @@ export interface PanelInitParameters extends InitParameters {
|
|||||||
// panel
|
// panel
|
||||||
|
|
||||||
export interface IGroupPanel extends IDisposable, ISerializable, IPanel {
|
export interface IGroupPanel extends IDisposable, ISerializable, IPanel {
|
||||||
id: string;
|
id: string
|
||||||
header: PanelHeaderPart;
|
header: PanelHeaderPart
|
||||||
content: PanelContentPart;
|
content: PanelContentPart
|
||||||
group: IGroupview;
|
group: IGroupview
|
||||||
focus(): void;
|
focus(): void
|
||||||
onHide(): void;
|
onHide(): void
|
||||||
setVisible(isGroupActive: boolean, group: IGroupview): void;
|
setVisible(isGroupActive: boolean, group: IGroupview): void
|
||||||
setDirty(isDirty: boolean): void;
|
setDirty(isDirty: boolean): void
|
||||||
close?(): Promise<ClosePanelResult>;
|
close?(): Promise<ClosePanelResult>
|
||||||
init?(params: PanelInitParameters & { [index: string]: string }): void;
|
init?(params: PanelInitParameters & { [index: string]: string }): void
|
||||||
onDidStateChange: Event<any>;
|
onDidStateChange: Event<any>
|
||||||
}
|
}
|
||||||
|
@ -1,57 +1,57 @@
|
|||||||
.title-container {
|
.title-container {
|
||||||
display: flex;
|
|
||||||
background-color: var(--title-bar-background-color);
|
|
||||||
overflow: overlay;
|
|
||||||
flex-shrink: 0;
|
|
||||||
box-sizing: border-box;
|
|
||||||
|
|
||||||
&.hidden {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::-webkit-scrollbar {
|
|
||||||
height: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Track */
|
|
||||||
&::-webkit-scrollbar-track {
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Handle */
|
|
||||||
&::-webkit-scrollbar-thumb {
|
|
||||||
background: var(--title-bar-scroll-bar-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.tab-container {
|
|
||||||
flex-shrink: 0;
|
|
||||||
flex-grow: 1;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
font-size: 13px;
|
background-color: var(--title-bar-background-color);
|
||||||
overflow-x: overlay;
|
overflow: overlay;
|
||||||
overflow-y: hidden;
|
flex-shrink: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
&.drag-over-target {
|
&.hidden {
|
||||||
background-color: var(--drag-over-background-color);
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab {
|
&::-webkit-scrollbar {
|
||||||
min-width: 75px;
|
height: 3px;
|
||||||
cursor: pointer;
|
}
|
||||||
position: relative;
|
|
||||||
box-sizing: border-box;
|
/* Track */
|
||||||
|
&::-webkit-scrollbar-track {
|
||||||
&:not(:first-child)::before {
|
background: transparent;
|
||||||
content: " ";
|
}
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
/* Handle */
|
||||||
left: 0;
|
&::-webkit-scrollbar-thumb {
|
||||||
z-index: 5;
|
background: var(--title-bar-scroll-bar-color);
|
||||||
pointer-events: none;
|
}
|
||||||
background-color: var(--tab-divider-color);
|
|
||||||
width: 1px;
|
.tab-container {
|
||||||
height: 100%;
|
flex-shrink: 0;
|
||||||
}
|
flex-grow: 1;
|
||||||
|
display: flex;
|
||||||
|
font-size: 13px;
|
||||||
|
overflow-x: overlay;
|
||||||
|
overflow-y: hidden;
|
||||||
|
|
||||||
|
&.drag-over-target {
|
||||||
|
background-color: var(--drag-over-background-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab {
|
||||||
|
min-width: 75px;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
&:not(:first-child)::before {
|
||||||
|
content: ' ';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 5;
|
||||||
|
pointer-events: none;
|
||||||
|
background-color: var(--tab-divider-color);
|
||||||
|
width: 1px;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,243 +1,252 @@
|
|||||||
import {
|
import {
|
||||||
IDisposable,
|
IDisposable,
|
||||||
CompositeDisposable,
|
CompositeDisposable,
|
||||||
IValueDisposable,
|
IValueDisposable,
|
||||||
} from "../../lifecycle";
|
} from '../../lifecycle'
|
||||||
import { addDisposableListener, Emitter, Event } from "../../events";
|
import { addDisposableListener, Emitter, Event } from '../../events'
|
||||||
import { ITab, Tab } from "../panel/tab/tab";
|
import { ITab, Tab } from '../panel/tab/tab'
|
||||||
import { removeClasses, addClasses, toggleClass } from "../../dom";
|
import { removeClasses, addClasses, toggleClass } from '../../dom'
|
||||||
import { hasProcessed, Position } from "../droptarget/droptarget";
|
import { hasProcessed, Position } from '../droptarget/droptarget'
|
||||||
import { TabDropEvent } from "../events";
|
import { TabDropEvent } from '../events'
|
||||||
|
|
||||||
import { IGroupview } from "../groupview";
|
import { IGroupview } from '../groupview'
|
||||||
import { IGroupAccessor } from "../../layout";
|
import { IGroupAccessor } from '../../layout'
|
||||||
import { last } from "../../array";
|
import { last } from '../../array'
|
||||||
import { DataTransferSingleton } from "../droptarget/dataTransfer";
|
import { DataTransferSingleton } from '../droptarget/dataTransfer'
|
||||||
import { IGroupPanel } from "../panel/types";
|
import { IGroupPanel } from '../panel/types'
|
||||||
import {MouseEventKind} from "../events"
|
import { MouseEventKind } from '../events'
|
||||||
|
|
||||||
export interface ITabContainer extends IDisposable {
|
export interface ITabContainer extends IDisposable {
|
||||||
element: HTMLElement;
|
element: HTMLElement
|
||||||
visible: boolean;
|
visible: boolean
|
||||||
height: number;
|
height: number
|
||||||
hasActiveDragEvent: boolean;
|
hasActiveDragEvent: boolean
|
||||||
delete: (id: string) => void;
|
delete: (id: string) => void
|
||||||
indexOf: (tabOrId: ITab | string) => number;
|
indexOf: (tabOrId: ITab | string) => number
|
||||||
at: (index: number) => ITab;
|
at: (index: number) => ITab
|
||||||
onDropEvent: Event<TabDropEvent>;
|
onDropEvent: Event<TabDropEvent>
|
||||||
setActive: (isGroupActive: boolean) => void;
|
setActive: (isGroupActive: boolean) => void
|
||||||
setActivePanel: (panel: IGroupPanel) => void;
|
setActivePanel: (panel: IGroupPanel) => void
|
||||||
isActive: (tab: ITab) => boolean;
|
isActive: (tab: ITab) => boolean
|
||||||
closePanel: (panel: IGroupPanel) => void;
|
closePanel: (panel: IGroupPanel) => void
|
||||||
openPanel: (panel: IGroupPanel, index?: number) => void;
|
openPanel: (panel: IGroupPanel, index?: number) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TabContainer extends CompositeDisposable implements ITabContainer {
|
export class TabContainer extends CompositeDisposable implements ITabContainer {
|
||||||
private tabContainer: HTMLElement;
|
private tabContainer: HTMLElement
|
||||||
private _element: HTMLElement;
|
private _element: HTMLElement
|
||||||
private actionContainer: HTMLElement;
|
private actionContainer: HTMLElement
|
||||||
|
|
||||||
private tabs: IValueDisposable<ITab>[] = [];
|
private tabs: IValueDisposable<ITab>[] = []
|
||||||
private selectedIndex: number = -1;
|
private selectedIndex: number = -1
|
||||||
private active: boolean;
|
private active: boolean
|
||||||
private activePanel: IGroupPanel;
|
private activePanel: IGroupPanel
|
||||||
|
|
||||||
private _visible: boolean = true;
|
private _visible: boolean = true
|
||||||
private _height: number;
|
private _height: number
|
||||||
|
|
||||||
private readonly _onDropped = new Emitter<TabDropEvent>();
|
private readonly _onDropped = new Emitter<TabDropEvent>()
|
||||||
readonly onDropEvent: Event<TabDropEvent> = this._onDropped.event;
|
readonly onDropEvent: Event<TabDropEvent> = this._onDropped.event
|
||||||
|
|
||||||
get visible() {
|
get visible() {
|
||||||
return this._visible;
|
return this._visible
|
||||||
}
|
|
||||||
|
|
||||||
set visible(value: boolean) {
|
|
||||||
this._visible = value;
|
|
||||||
|
|
||||||
toggleClass(this.element, "hidden", !this._visible);
|
|
||||||
}
|
|
||||||
|
|
||||||
get height() {
|
|
||||||
return this._height;
|
|
||||||
}
|
|
||||||
|
|
||||||
set height(value: number) {
|
|
||||||
this._height = value;
|
|
||||||
this._element.style.height = `${this.height}px`;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get element() {
|
|
||||||
return this._element;
|
|
||||||
}
|
|
||||||
|
|
||||||
public isActive(tab: ITab) {
|
|
||||||
return (
|
|
||||||
this.selectedIndex > -1 && this.tabs[this.selectedIndex].value === tab
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public get hasActiveDragEvent() {
|
|
||||||
return !!this.tabs.find((tab) => tab.value.hasActiveDragEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
public at(index: number) {
|
|
||||||
return this.tabs[index]?.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public indexOf(tabOrId: ITab) {
|
|
||||||
const id = typeof tabOrId === "string" ? tabOrId : tabOrId.id;
|
|
||||||
return this.tabs.findIndex((tab) => tab.value.id === id);
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(private accessor: IGroupAccessor, private group: IGroupview) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this.addDisposables(this._onDropped);
|
|
||||||
|
|
||||||
this._element = document.createElement("div");
|
|
||||||
this._element.className = "title-container";
|
|
||||||
|
|
||||||
this.height = 35;
|
|
||||||
|
|
||||||
this.actionContainer = document.createElement("div");
|
|
||||||
this.actionContainer.className = "action-container";
|
|
||||||
|
|
||||||
const list = document.createElement("ul");
|
|
||||||
list.className = "action-list";
|
|
||||||
|
|
||||||
this.tabContainer = document.createElement("div");
|
|
||||||
this.tabContainer.className = "tab-container";
|
|
||||||
|
|
||||||
this._element.appendChild(this.tabContainer);
|
|
||||||
this._element.appendChild(this.actionContainer);
|
|
||||||
|
|
||||||
this.addDisposables(
|
|
||||||
addDisposableListener(this.tabContainer, "dragenter", (event) => {
|
|
||||||
if (!DataTransferSingleton.has(this.accessor.id)) {
|
|
||||||
console.debug("[tabs] invalid drop event");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!last(this.tabs).value.hasActiveDragEvent) {
|
|
||||||
addClasses(this.tabContainer, "drag-over-target");
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
addDisposableListener(this.tabContainer, "dragover", (event) => {
|
|
||||||
event.preventDefault();
|
|
||||||
}),
|
|
||||||
addDisposableListener(this.tabContainer, "dragleave", (event) => {
|
|
||||||
removeClasses(this.tabContainer, "drag-over-target");
|
|
||||||
}),
|
|
||||||
addDisposableListener(this.tabContainer, "drop", (event) => {
|
|
||||||
if (!DataTransferSingleton.has(this.accessor.id)) {
|
|
||||||
console.debug("[tabs] invalid drop event");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (hasProcessed(event)) {
|
|
||||||
console.debug("[tab] drop event already processed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
removeClasses(this.tabContainer, "drag-over-target");
|
|
||||||
|
|
||||||
const activetab = this.tabs.find((tab) => tab.value.hasActiveDragEvent);
|
|
||||||
|
|
||||||
const ignore = !!(
|
|
||||||
activetab &&
|
|
||||||
event.composedPath().find((x) => activetab.value.element === x)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (ignore) {
|
|
||||||
console.debug("[tabs] ignore event");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._onDropped.fire({
|
|
||||||
event: { event, position: Position.Center },
|
|
||||||
index: this.tabs.length - 1,
|
|
||||||
});
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public setActive(isGroupActive: boolean) {
|
|
||||||
this.active = isGroupActive;
|
|
||||||
}
|
|
||||||
|
|
||||||
private addTab(
|
|
||||||
tab: IValueDisposable<ITab>,
|
|
||||||
index: number = this.tabs.length
|
|
||||||
) {
|
|
||||||
if (index < 0 || index > this.tabs.length) {
|
|
||||||
throw new Error("invalid location");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.tabContainer.insertBefore(
|
set visible(value: boolean) {
|
||||||
tab.value.element,
|
this._visible = value
|
||||||
this.tabContainer.children[index]
|
|
||||||
);
|
|
||||||
|
|
||||||
this.tabs = [...this.tabs.slice(0, index), tab, ...this.tabs.slice(index)];
|
toggleClass(this.element, 'hidden', !this._visible)
|
||||||
|
|
||||||
if (this.selectedIndex < 0) {
|
|
||||||
this.selectedIndex = index;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public delete(id: string) {
|
get height() {
|
||||||
const index = this.tabs.findIndex((tab) => tab.value.id === id);
|
return this._height
|
||||||
|
|
||||||
const tab = this.tabs.splice(index, 1)[0];
|
|
||||||
|
|
||||||
const { value, disposable } = tab;
|
|
||||||
|
|
||||||
disposable.dispose();
|
|
||||||
value.element.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
public setActivePanel(panel: IGroupPanel) {
|
|
||||||
this.tabs.forEach((tab) => {
|
|
||||||
const isActivePanel = panel.id === tab.value.id;
|
|
||||||
tab.value.setActive(isActivePanel);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public openPanel(panel: IGroupPanel, index: number = this.tabs.length) {
|
|
||||||
if (this.tabs.find((tab) => tab.value.id === panel.id)) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
const tab = new Tab(panel.id, this.accessor, this.group);
|
|
||||||
tab.setContent(panel.header.element);
|
|
||||||
|
|
||||||
const disposable = CompositeDisposable.from(
|
set height(value: number) {
|
||||||
tab.onChanged((event) => {
|
this._height = value
|
||||||
switch (event.kind) {
|
this._element.style.height = `${this.height}px`
|
||||||
case MouseEventKind.CLICK:
|
}
|
||||||
this.group.openPanel(panel);
|
|
||||||
break;
|
public get element() {
|
||||||
|
return this._element
|
||||||
|
}
|
||||||
|
|
||||||
|
public isActive(tab: ITab) {
|
||||||
|
return (
|
||||||
|
this.selectedIndex > -1 &&
|
||||||
|
this.tabs[this.selectedIndex].value === tab
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public get hasActiveDragEvent() {
|
||||||
|
return !!this.tabs.find((tab) => tab.value.hasActiveDragEvent)
|
||||||
|
}
|
||||||
|
|
||||||
|
public at(index: number) {
|
||||||
|
return this.tabs[index]?.value
|
||||||
|
}
|
||||||
|
|
||||||
|
public indexOf(tabOrId: ITab) {
|
||||||
|
const id = typeof tabOrId === 'string' ? tabOrId : tabOrId.id
|
||||||
|
return this.tabs.findIndex((tab) => tab.value.id === id)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(private accessor: IGroupAccessor, private group: IGroupview) {
|
||||||
|
super()
|
||||||
|
|
||||||
|
this.addDisposables(this._onDropped)
|
||||||
|
|
||||||
|
this._element = document.createElement('div')
|
||||||
|
this._element.className = 'title-container'
|
||||||
|
|
||||||
|
this.height = 35
|
||||||
|
|
||||||
|
this.actionContainer = document.createElement('div')
|
||||||
|
this.actionContainer.className = 'action-container'
|
||||||
|
|
||||||
|
const list = document.createElement('ul')
|
||||||
|
list.className = 'action-list'
|
||||||
|
|
||||||
|
this.tabContainer = document.createElement('div')
|
||||||
|
this.tabContainer.className = 'tab-container'
|
||||||
|
|
||||||
|
this._element.appendChild(this.tabContainer)
|
||||||
|
this._element.appendChild(this.actionContainer)
|
||||||
|
|
||||||
|
this.addDisposables(
|
||||||
|
addDisposableListener(this.tabContainer, 'dragenter', (event) => {
|
||||||
|
if (!DataTransferSingleton.has(this.accessor.id)) {
|
||||||
|
console.debug('[tabs] invalid drop event')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!last(this.tabs).value.hasActiveDragEvent) {
|
||||||
|
addClasses(this.tabContainer, 'drag-over-target')
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
addDisposableListener(this.tabContainer, 'dragover', (event) => {
|
||||||
|
event.preventDefault()
|
||||||
|
}),
|
||||||
|
addDisposableListener(this.tabContainer, 'dragleave', (event) => {
|
||||||
|
removeClasses(this.tabContainer, 'drag-over-target')
|
||||||
|
}),
|
||||||
|
addDisposableListener(this.tabContainer, 'drop', (event) => {
|
||||||
|
if (!DataTransferSingleton.has(this.accessor.id)) {
|
||||||
|
console.debug('[tabs] invalid drop event')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (hasProcessed(event)) {
|
||||||
|
console.debug('[tab] drop event already processed')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
removeClasses(this.tabContainer, 'drag-over-target')
|
||||||
|
|
||||||
|
const activetab = this.tabs.find(
|
||||||
|
(tab) => tab.value.hasActiveDragEvent
|
||||||
|
)
|
||||||
|
|
||||||
|
const ignore = !!(
|
||||||
|
activetab &&
|
||||||
|
event
|
||||||
|
.composedPath()
|
||||||
|
.find((x) => activetab.value.element === x)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (ignore) {
|
||||||
|
console.debug('[tabs] ignore event')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this._onDropped.fire({
|
||||||
|
event: { event, position: Position.Center },
|
||||||
|
index: this.tabs.length - 1,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public setActive(isGroupActive: boolean) {
|
||||||
|
this.active = isGroupActive
|
||||||
|
}
|
||||||
|
|
||||||
|
private addTab(
|
||||||
|
tab: IValueDisposable<ITab>,
|
||||||
|
index: number = this.tabs.length
|
||||||
|
) {
|
||||||
|
if (index < 0 || index > this.tabs.length) {
|
||||||
|
throw new Error('invalid location')
|
||||||
}
|
}
|
||||||
this.accessor.fireMouseEvent({...event, panel, tab:true});
|
|
||||||
}),
|
|
||||||
tab.onDropped((event) => {
|
|
||||||
this._onDropped.fire({ event, index: this.indexOf(tab) });
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
const value: IValueDisposable<ITab> = { value: tab, disposable };
|
this.tabContainer.insertBefore(
|
||||||
|
tab.value.element,
|
||||||
|
this.tabContainer.children[index]
|
||||||
|
)
|
||||||
|
|
||||||
this.addTab(value, index);
|
this.tabs = [
|
||||||
this.activePanel = panel;
|
...this.tabs.slice(0, index),
|
||||||
}
|
tab,
|
||||||
|
...this.tabs.slice(index),
|
||||||
|
]
|
||||||
|
|
||||||
public closePanel(panel: IGroupPanel) {
|
if (this.selectedIndex < 0) {
|
||||||
this.delete(panel.id);
|
this.selectedIndex = index
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public dispose() {
|
public delete(id: string) {
|
||||||
super.dispose();
|
const index = this.tabs.findIndex((tab) => tab.value.id === id)
|
||||||
|
|
||||||
this.tabs.forEach((tab) => {
|
const tab = this.tabs.splice(index, 1)[0]
|
||||||
tab.disposable.dispose();
|
|
||||||
});
|
const { value, disposable } = tab
|
||||||
this.tabs = [];
|
|
||||||
}
|
disposable.dispose()
|
||||||
|
value.element.remove()
|
||||||
|
}
|
||||||
|
|
||||||
|
public setActivePanel(panel: IGroupPanel) {
|
||||||
|
this.tabs.forEach((tab) => {
|
||||||
|
const isActivePanel = panel.id === tab.value.id
|
||||||
|
tab.value.setActive(isActivePanel)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public openPanel(panel: IGroupPanel, index: number = this.tabs.length) {
|
||||||
|
if (this.tabs.find((tab) => tab.value.id === panel.id)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const tab = new Tab(panel.id, this.accessor, this.group)
|
||||||
|
tab.setContent(panel.header.element)
|
||||||
|
|
||||||
|
const disposable = CompositeDisposable.from(
|
||||||
|
tab.onChanged((event) => {
|
||||||
|
switch (event.kind) {
|
||||||
|
case MouseEventKind.CLICK:
|
||||||
|
this.group.openPanel(panel)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
this.accessor.fireMouseEvent({ ...event, panel, tab: true })
|
||||||
|
}),
|
||||||
|
tab.onDropped((event) => {
|
||||||
|
this._onDropped.fire({ event, index: this.indexOf(tab) })
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
const value: IValueDisposable<ITab> = { value: tab, disposable }
|
||||||
|
|
||||||
|
this.addTab(value, index)
|
||||||
|
this.activePanel = panel
|
||||||
|
}
|
||||||
|
|
||||||
|
public closePanel(panel: IGroupPanel) {
|
||||||
|
this.delete(panel.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
public dispose() {
|
||||||
|
super.dispose()
|
||||||
|
|
||||||
|
this.tabs.forEach((tab) => {
|
||||||
|
tab.disposable.dispose()
|
||||||
|
})
|
||||||
|
this.tabs = []
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
export * from "./splitview/splitview";
|
export * from './splitview/splitview'
|
||||||
export * from "./paneview/paneview";
|
export * from './paneview/paneview'
|
||||||
export * from "./gridview/gridview";
|
export * from './gridview/gridview'
|
||||||
export * from "./groupview/groupview";
|
export * from './groupview/groupview'
|
||||||
export * from "./groupview/panel/content/content";
|
export * from './groupview/panel/content/content'
|
||||||
export * from "./groupview/panel/tab/tab";
|
export * from './groupview/panel/tab/tab'
|
||||||
export * from "./events";
|
export * from './events'
|
||||||
export * from "./lifecycle";
|
export * from './lifecycle'
|
||||||
export * from "./groupview/panel/panel";
|
export * from './groupview/panel/panel'
|
||||||
export * from "./groupview/panel/api";
|
export * from './groupview/panel/api'
|
||||||
export * from "./react/react";
|
export * from './react/react'
|
||||||
export * from "./groupview/panel/types";
|
export * from './groupview/panel/types'
|
||||||
export * from "./groupview/panel/parts";
|
export * from './groupview/panel/parts'
|
||||||
export * from "./react/layout";
|
export * from './react/layout'
|
||||||
export * from "./react/splitview";
|
export * from './react/splitview'
|
||||||
export * from "./react/gridview";
|
export * from './react/gridview'
|
||||||
export * from "./react/reactContentPart";
|
export * from './react/reactContentPart'
|
||||||
export * from "./react/reactHeaderPart";
|
export * from './react/reactHeaderPart'
|
||||||
export * from "./react/reactComponentGridView";
|
export * from './react/reactComponentGridView'
|
||||||
|
|
||||||
export * from "./layout";
|
export * from './layout'
|
||||||
|
@ -1,89 +1,89 @@
|
|||||||
import {
|
import {
|
||||||
PanelContentPart,
|
PanelContentPart,
|
||||||
PanelContentPartConstructor,
|
PanelContentPartConstructor,
|
||||||
PanelHeaderPart,
|
PanelHeaderPart,
|
||||||
PanelHeaderPartConstructor,
|
PanelHeaderPartConstructor,
|
||||||
} from "../groupview/panel/parts";
|
} from '../groupview/panel/parts'
|
||||||
import { FrameworkFactory } from "../types";
|
import { FrameworkFactory } from '../types'
|
||||||
import { DefaultTab } from "./components/tab/defaultTab";
|
import { DefaultTab } from './components/tab/defaultTab'
|
||||||
|
|
||||||
export function createContentComponent(
|
export function createContentComponent(
|
||||||
componentName: string | PanelContentPartConstructor | any,
|
componentName: string | PanelContentPartConstructor | any,
|
||||||
components: {
|
components: {
|
||||||
[componentName: string]: PanelContentPartConstructor;
|
[componentName: string]: PanelContentPartConstructor
|
||||||
},
|
},
|
||||||
frameworkComponents: {
|
frameworkComponents: {
|
||||||
[componentName: string]: any;
|
[componentName: string]: any
|
||||||
},
|
},
|
||||||
createFrameworkComponent: FrameworkFactory<PanelContentPart>
|
createFrameworkComponent: FrameworkFactory<PanelContentPart>
|
||||||
): PanelContentPart {
|
): PanelContentPart {
|
||||||
const Component =
|
const Component =
|
||||||
typeof componentName === "string"
|
typeof componentName === 'string'
|
||||||
? components[componentName]
|
? components[componentName]
|
||||||
: componentName;
|
: componentName
|
||||||
const FrameworkComponent =
|
const FrameworkComponent =
|
||||||
typeof componentName === "string"
|
typeof componentName === 'string'
|
||||||
? frameworkComponents[componentName]
|
? frameworkComponents[componentName]
|
||||||
: componentName;
|
: componentName
|
||||||
if (Component && FrameworkComponent) {
|
if (Component && FrameworkComponent) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`cannot register component ${componentName} as both a component and frameworkComponent`
|
`cannot register component ${componentName} as both a component and frameworkComponent`
|
||||||
);
|
)
|
||||||
}
|
|
||||||
if (FrameworkComponent) {
|
|
||||||
if (!createFrameworkComponent) {
|
|
||||||
throw new Error(
|
|
||||||
"you must register a frameworkPanelWrapper to use framework components"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
const wrappedComponent = createFrameworkComponent.createComponent(
|
if (FrameworkComponent) {
|
||||||
componentName,
|
if (!createFrameworkComponent) {
|
||||||
FrameworkComponent
|
throw new Error(
|
||||||
);
|
'you must register a frameworkPanelWrapper to use framework components'
|
||||||
return wrappedComponent;
|
)
|
||||||
}
|
}
|
||||||
return new Component() as PanelContentPart;
|
const wrappedComponent = createFrameworkComponent.createComponent(
|
||||||
|
componentName,
|
||||||
|
FrameworkComponent
|
||||||
|
)
|
||||||
|
return wrappedComponent
|
||||||
|
}
|
||||||
|
return new Component() as PanelContentPart
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createTabComponent(
|
export function createTabComponent(
|
||||||
componentName: string | PanelHeaderPartConstructor | any,
|
componentName: string | PanelHeaderPartConstructor | any,
|
||||||
components: {
|
components: {
|
||||||
[componentName: string]: PanelHeaderPartConstructor;
|
[componentName: string]: PanelHeaderPartConstructor
|
||||||
},
|
},
|
||||||
frameworkComponents: {
|
frameworkComponents: {
|
||||||
[componentName: string]: any;
|
[componentName: string]: any
|
||||||
},
|
},
|
||||||
createFrameworkComponent: FrameworkFactory<PanelHeaderPart>
|
createFrameworkComponent: FrameworkFactory<PanelHeaderPart>
|
||||||
): PanelHeaderPart {
|
): PanelHeaderPart {
|
||||||
const Component =
|
const Component =
|
||||||
typeof componentName === "string"
|
typeof componentName === 'string'
|
||||||
? components[componentName]
|
? components[componentName]
|
||||||
: componentName;
|
: componentName
|
||||||
const FrameworkComponent =
|
const FrameworkComponent =
|
||||||
typeof componentName === "string"
|
typeof componentName === 'string'
|
||||||
? frameworkComponents[componentName]
|
? frameworkComponents[componentName]
|
||||||
: componentName;
|
: componentName
|
||||||
if (Component && FrameworkComponent) {
|
if (Component && FrameworkComponent) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`cannot register component ${componentName} as both a component and frameworkComponent`
|
`cannot register component ${componentName} as both a component and frameworkComponent`
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
if (FrameworkComponent) {
|
if (FrameworkComponent) {
|
||||||
if (!createFrameworkComponent) {
|
if (!createFrameworkComponent) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"you must register a frameworkPanelWrapper to use framework components"
|
'you must register a frameworkPanelWrapper to use framework components'
|
||||||
);
|
)
|
||||||
|
}
|
||||||
|
const wrappedComponent = createFrameworkComponent.createComponent(
|
||||||
|
componentName,
|
||||||
|
FrameworkComponent
|
||||||
|
)
|
||||||
|
return wrappedComponent
|
||||||
}
|
}
|
||||||
const wrappedComponent = createFrameworkComponent.createComponent(
|
|
||||||
componentName,
|
|
||||||
FrameworkComponent
|
|
||||||
);
|
|
||||||
return wrappedComponent;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Component) {
|
if (!Component) {
|
||||||
return new DefaultTab();
|
return new DefaultTab()
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Component() as PanelHeaderPart;
|
return new Component() as PanelHeaderPart
|
||||||
}
|
}
|
||||||
|
@ -1,408 +1,410 @@
|
|||||||
import { Gridview, getRelativeLocation, IGridView } from "../gridview/gridview";
|
import { Gridview, getRelativeLocation, IGridView } from '../gridview/gridview'
|
||||||
import { Position } from "../groupview/droptarget/droptarget";
|
import { Position } from '../groupview/droptarget/droptarget'
|
||||||
import { getGridLocation } from "../gridview/gridview";
|
import { getGridLocation } from '../gridview/gridview'
|
||||||
import { tail, sequenceEquals } from "../array";
|
import { tail, sequenceEquals } from '../array'
|
||||||
import {
|
import {
|
||||||
GroupChangeKind,
|
GroupChangeKind,
|
||||||
GroupChangeEvent,
|
GroupChangeEvent,
|
||||||
GroupDropEvent,
|
GroupDropEvent,
|
||||||
} from "../groupview/groupview";
|
} from '../groupview/groupview'
|
||||||
import {
|
import { CompositeDisposable, Disposable, IValueDisposable } from '../lifecycle'
|
||||||
CompositeDisposable,
|
import { Event, Emitter } from '../events'
|
||||||
Disposable,
|
|
||||||
IValueDisposable,
|
|
||||||
} from "../lifecycle";
|
|
||||||
import { Event, Emitter } from "../events";
|
|
||||||
|
|
||||||
import { DebugWidget } from "./components/debug/debug";
|
import { DebugWidget } from './components/debug/debug'
|
||||||
|
|
||||||
import { sequentialNumberGenerator } from "../math";
|
import { sequentialNumberGenerator } from '../math'
|
||||||
import { DefaultDeserializer, IPanelDeserializer } from "./deserializer";
|
import { IPanelDeserializer } from './deserializer'
|
||||||
import { MovementOptions } from "./options";
|
|
||||||
|
|
||||||
import { createComponent } from "../splitview/options";
|
import { createComponent } from '../splitview/options'
|
||||||
import { LayoutPriority, Orientation } from "../splitview/splitview";
|
import { LayoutPriority, Orientation } from '../splitview/splitview'
|
||||||
|
|
||||||
const nextGroupId = sequentialNumberGenerator();
|
const nextLayoutId = sequentialNumberGenerator()
|
||||||
const nextLayoutId = sequentialNumberGenerator();
|
|
||||||
|
|
||||||
export interface AddComponentOptions {
|
export interface AddComponentOptions {
|
||||||
component: string;
|
component: string
|
||||||
params?: { [key: string]: any };
|
params?: { [key: string]: any }
|
||||||
id: string;
|
id: string
|
||||||
position?: {
|
position?: {
|
||||||
direction?: "left" | "right" | "above" | "below" | "within";
|
direction?: 'left' | 'right' | 'above' | 'below' | 'within'
|
||||||
reference: string;
|
reference: string
|
||||||
};
|
}
|
||||||
|
size?: number
|
||||||
size?: number;
|
priority?: LayoutPriority
|
||||||
priority?: LayoutPriority;
|
snap?: boolean
|
||||||
snap?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GridComponentOptions {
|
export interface GridComponentOptions {
|
||||||
orientation: Orientation;
|
orientation: Orientation
|
||||||
components?: {
|
components?: {
|
||||||
[componentName: string]: IComponentGridview;
|
[componentName: string]: IComponentGridview
|
||||||
};
|
}
|
||||||
frameworkComponents?: {
|
frameworkComponents?: {
|
||||||
[componentName: string]: any;
|
[componentName: string]: any
|
||||||
};
|
}
|
||||||
frameworkComponentFactory: any;
|
frameworkComponentFactory: any
|
||||||
tabHeight?: number;
|
tabHeight?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IComponentGridview extends IGridView {
|
export interface IComponentGridview extends IGridView {
|
||||||
id: string;
|
id: string
|
||||||
init: (params: { params: any }) => void;
|
init: (params: { params: any }) => void
|
||||||
priority?: LayoutPriority;
|
priority?: LayoutPriority
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MovementOptions2 {
|
export interface MovementOptions2 {
|
||||||
group?: IComponentGridview;
|
group?: IComponentGridview
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IComponentGridviewLayout {
|
export interface IComponentGridviewLayout {
|
||||||
addComponent(options: AddComponentOptions): void;
|
addComponent(options: AddComponentOptions): void
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ComponentGridview
|
export class ComponentGridview
|
||||||
extends CompositeDisposable
|
extends CompositeDisposable
|
||||||
implements IComponentGridviewLayout {
|
implements IComponentGridviewLayout {
|
||||||
private readonly _id = nextLayoutId.next();
|
private readonly _id = nextLayoutId.next()
|
||||||
private readonly groups = new Map<
|
private readonly groups = new Map<
|
||||||
string,
|
string,
|
||||||
IValueDisposable<IComponentGridview>
|
IValueDisposable<IComponentGridview>
|
||||||
>();
|
>()
|
||||||
private readonly gridview: Gridview = new Gridview(false);
|
private readonly gridview: Gridview = new Gridview(false)
|
||||||
// events
|
// events
|
||||||
private readonly _onDidLayoutChange = new Emitter<GroupChangeEvent>();
|
private readonly _onDidLayoutChange = new Emitter<GroupChangeEvent>()
|
||||||
readonly onDidLayoutChange: Event<GroupChangeEvent> = this._onDidLayoutChange
|
readonly onDidLayoutChange: Event<GroupChangeEvent> = this
|
||||||
.event;
|
._onDidLayoutChange.event
|
||||||
// everything else
|
// everything else
|
||||||
private _size: number;
|
private _size: number
|
||||||
private _orthogonalSize: number;
|
private _orthogonalSize: number
|
||||||
private _activeGroup: IComponentGridview;
|
private _activeGroup: IComponentGridview
|
||||||
private _deserializer: IPanelDeserializer;
|
private _deserializer: IPanelDeserializer
|
||||||
private resizeTimer: NodeJS.Timer;
|
private resizeTimer: NodeJS.Timer
|
||||||
private debugContainer: DebugWidget;
|
private debugContainer: DebugWidget
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly element: HTMLElement,
|
private readonly element: HTMLElement,
|
||||||
public readonly options: GridComponentOptions
|
public readonly options: GridComponentOptions
|
||||||
) {
|
) {
|
||||||
super();
|
super()
|
||||||
|
|
||||||
this.element.appendChild(this.gridview.element);
|
this.element.appendChild(this.gridview.element)
|
||||||
|
|
||||||
if (!this.options.components) {
|
if (!this.options.components) {
|
||||||
this.options.components = {};
|
this.options.components = {}
|
||||||
}
|
}
|
||||||
if (!this.options.frameworkComponents) {
|
if (!this.options.frameworkComponents) {
|
||||||
this.options.frameworkComponents = {};
|
this.options.frameworkComponents = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.addDisposables(
|
||||||
|
this.gridview.onDidChange((e) => {
|
||||||
|
this._onDidLayoutChange.fire({ kind: GroupChangeKind.LAYOUT })
|
||||||
|
})
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.addDisposables(
|
get minimumHeight() {
|
||||||
this.gridview.onDidChange((e) => {
|
return this.gridview.minimumHeight
|
||||||
this._onDidLayoutChange.fire({ kind: GroupChangeKind.LAYOUT });
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
get minimumHeight() {
|
|
||||||
return this.gridview.minimumHeight;
|
|
||||||
}
|
|
||||||
get maximumHeight() {
|
|
||||||
return this.gridview.maximumHeight;
|
|
||||||
}
|
|
||||||
get minimumWidth() {
|
|
||||||
return this.gridview.maximumWidth;
|
|
||||||
}
|
|
||||||
get maximumWidth() {
|
|
||||||
return this.gridview.maximumWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
get activeGroup() {
|
|
||||||
return this._activeGroup;
|
|
||||||
}
|
|
||||||
|
|
||||||
get deserializer() {
|
|
||||||
return this._deserializer;
|
|
||||||
}
|
|
||||||
|
|
||||||
set deserializer(value: IPanelDeserializer) {
|
|
||||||
this._deserializer = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
get id() {
|
|
||||||
return this._id;
|
|
||||||
}
|
|
||||||
|
|
||||||
get size() {
|
|
||||||
return this.groups.size;
|
|
||||||
}
|
|
||||||
|
|
||||||
public moveToNext(options?: MovementOptions2) {
|
|
||||||
if (!options) {
|
|
||||||
options = {};
|
|
||||||
}
|
}
|
||||||
if (!options.group) {
|
get maximumHeight() {
|
||||||
options.group = this.activeGroup;
|
return this.gridview.maximumHeight
|
||||||
|
}
|
||||||
|
get minimumWidth() {
|
||||||
|
return this.gridview.maximumWidth
|
||||||
|
}
|
||||||
|
get maximumWidth() {
|
||||||
|
return this.gridview.maximumWidth
|
||||||
}
|
}
|
||||||
|
|
||||||
const location = getGridLocation(options.group.element);
|
get activeGroup() {
|
||||||
const next = this.gridview.next(location)?.view as IComponentGridview;
|
return this._activeGroup
|
||||||
this.doSetGroupActive(next);
|
|
||||||
}
|
|
||||||
|
|
||||||
public moveToPrevious(options?: MovementOptions2) {
|
|
||||||
if (!options) {
|
|
||||||
options = {};
|
|
||||||
}
|
|
||||||
if (!options.group) {
|
|
||||||
options.group = this.activeGroup;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const location = getGridLocation(options.group.element);
|
get deserializer() {
|
||||||
const next = this.gridview.preivous(location)?.view as IComponentGridview;
|
return this._deserializer
|
||||||
this.doSetGroupActive(next);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Serialize the current state of the layout
|
|
||||||
*
|
|
||||||
* @returns A JSON respresentation of the layout
|
|
||||||
*/
|
|
||||||
public toJSON() {
|
|
||||||
const data = this.gridview.serialize();
|
|
||||||
|
|
||||||
return { grid: data };
|
|
||||||
}
|
|
||||||
|
|
||||||
public deserialize(data: any) {
|
|
||||||
this.gridview.clear();
|
|
||||||
this.groups.clear();
|
|
||||||
|
|
||||||
this.fromJSON(data, this.deserializer);
|
|
||||||
this.gridview.layout(this._size, this._orthogonalSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
public fromJSON(data: any, deserializer: IPanelDeserializer) {
|
|
||||||
const { grid, panels } = data;
|
|
||||||
|
|
||||||
// this.gridview.deserialize(
|
|
||||||
// grid,
|
|
||||||
// new DefaultDeserializer(this, {
|
|
||||||
// createPanel: (id) => {
|
|
||||||
// const panelData = panels[id];
|
|
||||||
// const panel = deserializer.fromJSON(panelData);
|
|
||||||
// this.registerPanel(panel);
|
|
||||||
// return panel;
|
|
||||||
// },
|
|
||||||
// })
|
|
||||||
// );
|
|
||||||
this._onDidLayoutChange.fire({ kind: GroupChangeKind.NEW_LAYOUT });
|
|
||||||
}
|
|
||||||
|
|
||||||
public setAutoResizeToFit(enabled: boolean) {
|
|
||||||
if (this.resizeTimer) {
|
|
||||||
clearInterval(this.resizeTimer);
|
|
||||||
}
|
|
||||||
if (enabled) {
|
|
||||||
this.resizeTimer = setInterval(() => {
|
|
||||||
this.resizeToFit();
|
|
||||||
}, 500);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resize the layout to fit the parent container
|
|
||||||
*/
|
|
||||||
public resizeToFit() {
|
|
||||||
const {
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
} = this.element.parentElement.getBoundingClientRect();
|
|
||||||
this.layout(width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
public addComponent(options: AddComponentOptions) {
|
|
||||||
let relativeLocation: number[] = [0];
|
|
||||||
|
|
||||||
if (options.position?.reference) {
|
|
||||||
const referenceGroup = this.groups.get(options.position.reference).value;
|
|
||||||
|
|
||||||
const target = this.toTarget(options.position.direction);
|
|
||||||
if (target === Position.Center) {
|
|
||||||
throw new Error(`${target} not supported as an option`);
|
|
||||||
} else {
|
|
||||||
const location = getGridLocation(referenceGroup.element);
|
|
||||||
relativeLocation = getRelativeLocation(
|
|
||||||
this.gridview.orientation,
|
|
||||||
location,
|
|
||||||
target
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const view = createComponent(
|
set deserializer(value: IPanelDeserializer) {
|
||||||
options.component,
|
this._deserializer = value
|
||||||
this.options.components,
|
|
||||||
this.options.frameworkComponents,
|
|
||||||
this.options.frameworkComponentFactory.createComponent
|
|
||||||
);
|
|
||||||
view.init({ params: {} });
|
|
||||||
view.priority = options.priority;
|
|
||||||
view.snap = options.snap;
|
|
||||||
|
|
||||||
this.groups.set(options.id, { value: view, disposable: Disposable.NONE });
|
|
||||||
|
|
||||||
this.doAddGroup(view, relativeLocation, options.size);
|
|
||||||
}
|
|
||||||
|
|
||||||
public getGroup(id: string) {
|
|
||||||
return this.groups.get(id)?.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public removeGroup(group: IComponentGridview) {
|
|
||||||
if (group === this._activeGroup) {
|
|
||||||
this._activeGroup = undefined;
|
|
||||||
}
|
|
||||||
this.doRemoveGroup(group);
|
|
||||||
}
|
|
||||||
|
|
||||||
private doAddGroup(
|
|
||||||
group: IComponentGridview,
|
|
||||||
location: number[],
|
|
||||||
size?: number
|
|
||||||
) {
|
|
||||||
this.gridview.addView(group, size ?? { type: "distribute" }, location);
|
|
||||||
|
|
||||||
this._onDidLayoutChange.fire({ kind: GroupChangeKind.ADD_GROUP });
|
|
||||||
this.doSetGroupActive(group);
|
|
||||||
}
|
|
||||||
|
|
||||||
private doRemoveGroup(
|
|
||||||
group: IComponentGridview,
|
|
||||||
options?: { skipActive?: boolean; skipDispose?: boolean }
|
|
||||||
) {
|
|
||||||
if (!this.groups.has(group.id)) {
|
|
||||||
throw new Error("invalid operation");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const { disposable } = this.groups.get(group.id);
|
get id() {
|
||||||
|
return this._id
|
||||||
if (!options?.skipDispose) {
|
|
||||||
disposable.dispose();
|
|
||||||
this.groups.delete(group.id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const view = this.gridview.remove(group, { type: "distribute" });
|
get size() {
|
||||||
this._onDidLayoutChange.fire({ kind: GroupChangeKind.REMOVE_GROUP });
|
return this.groups.size
|
||||||
|
|
||||||
if (!options?.skipActive && this.groups.size > 0) {
|
|
||||||
this.doSetGroupActive(Array.from(this.groups.values())[0].value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return view;
|
public moveToNext(options?: MovementOptions2) {
|
||||||
}
|
if (!options) {
|
||||||
|
options = {}
|
||||||
|
}
|
||||||
|
if (!options.group) {
|
||||||
|
options.group = this.activeGroup
|
||||||
|
}
|
||||||
|
|
||||||
public doSetGroupActive(group: IComponentGridview) {
|
const location = getGridLocation(options.group.element)
|
||||||
if (this._activeGroup && this._activeGroup !== group) {
|
const next = this.gridview.next(location)?.view as IComponentGridview
|
||||||
// this._activeGroup.setActive(false);
|
this.doSetGroupActive(next)
|
||||||
}
|
|
||||||
// group.setActive(true);
|
|
||||||
this._activeGroup = group;
|
|
||||||
}
|
|
||||||
|
|
||||||
public moveGroup(
|
|
||||||
referenceGroup: IComponentGridview,
|
|
||||||
groupId: string,
|
|
||||||
itemId: string,
|
|
||||||
target: Position
|
|
||||||
) {
|
|
||||||
const sourceGroup = groupId ? this.groups.get(groupId).value : undefined;
|
|
||||||
|
|
||||||
const referenceLocation = getGridLocation(referenceGroup.element);
|
|
||||||
const targetLocation = getRelativeLocation(
|
|
||||||
this.gridview.orientation,
|
|
||||||
referenceLocation,
|
|
||||||
target
|
|
||||||
);
|
|
||||||
|
|
||||||
const [targetParentLocation, to] = tail(targetLocation);
|
|
||||||
const sourceLocation = getGridLocation(sourceGroup.element);
|
|
||||||
const [sourceParentLocation, from] = tail(sourceLocation);
|
|
||||||
|
|
||||||
if (sequenceEquals(sourceParentLocation, targetParentLocation)) {
|
|
||||||
// special case when 'swapping' two views within same grid location
|
|
||||||
// if a group has one tab - we are essentially moving the 'group'
|
|
||||||
// which is equivalent to swapping two views in this case
|
|
||||||
this.gridview.moveView(sourceParentLocation, from, to);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// source group will become empty so delete the group
|
public moveToPrevious(options?: MovementOptions2) {
|
||||||
const targetGroup = this.doRemoveGroup(sourceGroup, {
|
if (!options) {
|
||||||
skipActive: true,
|
options = {}
|
||||||
skipDispose: true,
|
}
|
||||||
}) as IComponentGridview;
|
if (!options.group) {
|
||||||
|
options.group = this.activeGroup
|
||||||
|
}
|
||||||
|
|
||||||
// after deleting the group we need to re-evaulate the ref location
|
const location = getGridLocation(options.group.element)
|
||||||
const updatedReferenceLocation = getGridLocation(referenceGroup.element);
|
const next = this.gridview.preivous(location)
|
||||||
const location = getRelativeLocation(
|
?.view as IComponentGridview
|
||||||
this.gridview.orientation,
|
this.doSetGroupActive(next)
|
||||||
updatedReferenceLocation,
|
|
||||||
target
|
|
||||||
);
|
|
||||||
this.doAddGroup(targetGroup, location);
|
|
||||||
}
|
|
||||||
|
|
||||||
public layout(size: number, orthogonalSize: number, force?: boolean) {
|
|
||||||
const different =
|
|
||||||
force || size !== this._size || orthogonalSize !== this._orthogonalSize;
|
|
||||||
|
|
||||||
if (!different) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.element.style.height = `${orthogonalSize}px`;
|
/**
|
||||||
this.element.style.width = `${size}px`;
|
* Serialize the current state of the layout
|
||||||
|
*
|
||||||
|
* @returns A JSON respresentation of the layout
|
||||||
|
*/
|
||||||
|
public toJSON() {
|
||||||
|
const data = this.gridview.serialize()
|
||||||
|
|
||||||
this._size = size;
|
return { grid: data }
|
||||||
this._orthogonalSize = orthogonalSize;
|
|
||||||
this.gridview.layout(size, orthogonalSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
private toTarget(direction: "left" | "right" | "above" | "below" | "within") {
|
|
||||||
switch (direction) {
|
|
||||||
case "left":
|
|
||||||
return Position.Left;
|
|
||||||
case "right":
|
|
||||||
return Position.Right;
|
|
||||||
case "above":
|
|
||||||
return Position.Top;
|
|
||||||
case "below":
|
|
||||||
return Position.Bottom;
|
|
||||||
case "within":
|
|
||||||
default:
|
|
||||||
return Position.Center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public dispose() {
|
|
||||||
super.dispose();
|
|
||||||
|
|
||||||
this.gridview.dispose();
|
|
||||||
|
|
||||||
this.debugContainer?.dispose();
|
|
||||||
|
|
||||||
if (this.resizeTimer) {
|
|
||||||
clearInterval(this.resizeTimer);
|
|
||||||
this.resizeTimer = undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this._onDidLayoutChange.dispose();
|
public deserialize(data: any) {
|
||||||
}
|
this.gridview.clear()
|
||||||
|
this.groups.clear()
|
||||||
|
|
||||||
|
this.fromJSON(data, this.deserializer)
|
||||||
|
this.gridview.layout(this._size, this._orthogonalSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
public fromJSON(data: any, deserializer: IPanelDeserializer) {
|
||||||
|
const { grid, panels } = data
|
||||||
|
|
||||||
|
// this.gridview.deserialize(
|
||||||
|
// grid,
|
||||||
|
// new DefaultDeserializer(this, {
|
||||||
|
// createPanel: (id) => {
|
||||||
|
// const panelData = panels[id];
|
||||||
|
// const panel = deserializer.fromJSON(panelData);
|
||||||
|
// this.registerPanel(panel);
|
||||||
|
// return panel;
|
||||||
|
// },
|
||||||
|
// })
|
||||||
|
// );
|
||||||
|
this._onDidLayoutChange.fire({ kind: GroupChangeKind.NEW_LAYOUT })
|
||||||
|
}
|
||||||
|
|
||||||
|
public setAutoResizeToFit(enabled: boolean) {
|
||||||
|
if (this.resizeTimer) {
|
||||||
|
clearInterval(this.resizeTimer)
|
||||||
|
}
|
||||||
|
if (enabled) {
|
||||||
|
this.resizeTimer = setInterval(() => {
|
||||||
|
this.resizeToFit()
|
||||||
|
}, 500)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resize the layout to fit the parent container
|
||||||
|
*/
|
||||||
|
public resizeToFit() {
|
||||||
|
const {
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
} = this.element.parentElement.getBoundingClientRect()
|
||||||
|
this.layout(width, height)
|
||||||
|
}
|
||||||
|
|
||||||
|
public addComponent(options: AddComponentOptions) {
|
||||||
|
let relativeLocation: number[] = [0]
|
||||||
|
|
||||||
|
if (options.position?.reference) {
|
||||||
|
const referenceGroup = this.groups.get(options.position.reference)
|
||||||
|
.value
|
||||||
|
|
||||||
|
const target = this.toTarget(options.position.direction)
|
||||||
|
if (target === Position.Center) {
|
||||||
|
throw new Error(`${target} not supported as an option`)
|
||||||
|
} else {
|
||||||
|
const location = getGridLocation(referenceGroup.element)
|
||||||
|
relativeLocation = getRelativeLocation(
|
||||||
|
this.gridview.orientation,
|
||||||
|
location,
|
||||||
|
target
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const view = createComponent(
|
||||||
|
options.component,
|
||||||
|
this.options.components,
|
||||||
|
this.options.frameworkComponents,
|
||||||
|
this.options.frameworkComponentFactory.createComponent
|
||||||
|
)
|
||||||
|
view.init({ params: {} })
|
||||||
|
view.priority = options.priority
|
||||||
|
view.snap = options.snap
|
||||||
|
|
||||||
|
this.groups.set(options.id, {
|
||||||
|
value: view,
|
||||||
|
disposable: Disposable.NONE,
|
||||||
|
})
|
||||||
|
|
||||||
|
this.doAddGroup(view, relativeLocation, options.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
public getGroup(id: string) {
|
||||||
|
return this.groups.get(id)?.value
|
||||||
|
}
|
||||||
|
|
||||||
|
public removeGroup(group: IComponentGridview) {
|
||||||
|
if (group === this._activeGroup) {
|
||||||
|
this._activeGroup = undefined
|
||||||
|
}
|
||||||
|
this.doRemoveGroup(group)
|
||||||
|
}
|
||||||
|
|
||||||
|
private doAddGroup(
|
||||||
|
group: IComponentGridview,
|
||||||
|
location: number[],
|
||||||
|
size?: number
|
||||||
|
) {
|
||||||
|
this.gridview.addView(group, size ?? { type: 'distribute' }, location)
|
||||||
|
|
||||||
|
this._onDidLayoutChange.fire({ kind: GroupChangeKind.ADD_GROUP })
|
||||||
|
this.doSetGroupActive(group)
|
||||||
|
}
|
||||||
|
|
||||||
|
private doRemoveGroup(
|
||||||
|
group: IComponentGridview,
|
||||||
|
options?: { skipActive?: boolean; skipDispose?: boolean }
|
||||||
|
) {
|
||||||
|
if (!this.groups.has(group.id)) {
|
||||||
|
throw new Error('invalid operation')
|
||||||
|
}
|
||||||
|
|
||||||
|
const { disposable } = this.groups.get(group.id)
|
||||||
|
|
||||||
|
if (!options?.skipDispose) {
|
||||||
|
disposable.dispose()
|
||||||
|
this.groups.delete(group.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
const view = this.gridview.remove(group, { type: 'distribute' })
|
||||||
|
this._onDidLayoutChange.fire({ kind: GroupChangeKind.REMOVE_GROUP })
|
||||||
|
|
||||||
|
if (!options?.skipActive && this.groups.size > 0) {
|
||||||
|
this.doSetGroupActive(Array.from(this.groups.values())[0].value)
|
||||||
|
}
|
||||||
|
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
|
||||||
|
public doSetGroupActive(group: IComponentGridview) {
|
||||||
|
if (this._activeGroup && this._activeGroup !== group) {
|
||||||
|
// this._activeGroup.setActive(false);
|
||||||
|
}
|
||||||
|
// group.setActive(true);
|
||||||
|
this._activeGroup = group
|
||||||
|
}
|
||||||
|
|
||||||
|
public moveGroup(
|
||||||
|
referenceGroup: IComponentGridview,
|
||||||
|
groupId: string,
|
||||||
|
itemId: string,
|
||||||
|
target: Position
|
||||||
|
) {
|
||||||
|
const sourceGroup = groupId ? this.groups.get(groupId).value : undefined
|
||||||
|
|
||||||
|
const referenceLocation = getGridLocation(referenceGroup.element)
|
||||||
|
const targetLocation = getRelativeLocation(
|
||||||
|
this.gridview.orientation,
|
||||||
|
referenceLocation,
|
||||||
|
target
|
||||||
|
)
|
||||||
|
|
||||||
|
const [targetParentLocation, to] = tail(targetLocation)
|
||||||
|
const sourceLocation = getGridLocation(sourceGroup.element)
|
||||||
|
const [sourceParentLocation, from] = tail(sourceLocation)
|
||||||
|
|
||||||
|
if (sequenceEquals(sourceParentLocation, targetParentLocation)) {
|
||||||
|
// special case when 'swapping' two views within same grid location
|
||||||
|
// if a group has one tab - we are essentially moving the 'group'
|
||||||
|
// which is equivalent to swapping two views in this case
|
||||||
|
this.gridview.moveView(sourceParentLocation, from, to)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// source group will become empty so delete the group
|
||||||
|
const targetGroup = this.doRemoveGroup(sourceGroup, {
|
||||||
|
skipActive: true,
|
||||||
|
skipDispose: true,
|
||||||
|
}) as IComponentGridview
|
||||||
|
|
||||||
|
// after deleting the group we need to re-evaulate the ref location
|
||||||
|
const updatedReferenceLocation = getGridLocation(referenceGroup.element)
|
||||||
|
const location = getRelativeLocation(
|
||||||
|
this.gridview.orientation,
|
||||||
|
updatedReferenceLocation,
|
||||||
|
target
|
||||||
|
)
|
||||||
|
this.doAddGroup(targetGroup, location)
|
||||||
|
}
|
||||||
|
|
||||||
|
public layout(size: number, orthogonalSize: number, force?: boolean) {
|
||||||
|
const different =
|
||||||
|
force ||
|
||||||
|
size !== this._size ||
|
||||||
|
orthogonalSize !== this._orthogonalSize
|
||||||
|
|
||||||
|
if (!different) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.element.style.height = `${orthogonalSize}px`
|
||||||
|
this.element.style.width = `${size}px`
|
||||||
|
|
||||||
|
this._size = size
|
||||||
|
this._orthogonalSize = orthogonalSize
|
||||||
|
this.gridview.layout(size, orthogonalSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
private toTarget(
|
||||||
|
direction: 'left' | 'right' | 'above' | 'below' | 'within'
|
||||||
|
) {
|
||||||
|
switch (direction) {
|
||||||
|
case 'left':
|
||||||
|
return Position.Left
|
||||||
|
case 'right':
|
||||||
|
return Position.Right
|
||||||
|
case 'above':
|
||||||
|
return Position.Top
|
||||||
|
case 'below':
|
||||||
|
return Position.Bottom
|
||||||
|
case 'within':
|
||||||
|
default:
|
||||||
|
return Position.Center
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public dispose() {
|
||||||
|
super.dispose()
|
||||||
|
|
||||||
|
this.gridview.dispose()
|
||||||
|
|
||||||
|
this.debugContainer?.dispose()
|
||||||
|
|
||||||
|
if (this.resizeTimer) {
|
||||||
|
clearInterval(this.resizeTimer)
|
||||||
|
this.resizeTimer = undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
this._onDidLayoutChange.dispose()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
.layout-debug-container {
|
.layout-debug-container {
|
||||||
color: white;
|
color: white;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0px;
|
top: 0px;
|
||||||
right: 0px;
|
right: 0px;
|
||||||
z-index: 9999;
|
z-index: 9999;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
width: 100px;
|
width: 100px;
|
||||||
|
|
||||||
.layout-debug-widget {
|
.layout-debug-widget {
|
||||||
background-color: black;
|
background-color: black;
|
||||||
margin: 1px;
|
margin: 1px;
|
||||||
.layout-debug-widget-row {
|
.layout-debug-widget-row {
|
||||||
padding: 0px 5px;
|
padding: 0px 5px;
|
||||||
display: flex;
|
display: flex;
|
||||||
span:first-child {
|
span:first-child {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,59 +1,59 @@
|
|||||||
import { CompositeDisposable } from "../../../lifecycle";
|
import { CompositeDisposable } from '../../../lifecycle'
|
||||||
import { Layout } from "../../layout";
|
import { Layout } from '../../layout'
|
||||||
import { GroupChangeKind } from "../../../groupview/groupview";
|
import { GroupChangeKind } from '../../../groupview/groupview'
|
||||||
|
|
||||||
export class DebugWidget extends CompositeDisposable {
|
export class DebugWidget extends CompositeDisposable {
|
||||||
private _element: HTMLElement;
|
private _element: HTMLElement
|
||||||
|
|
||||||
constructor(private layout: Layout) {
|
constructor(private layout: Layout) {
|
||||||
super();
|
super()
|
||||||
|
|
||||||
let container = document.getElementById("layout-debug-container");
|
let container = document.getElementById('layout-debug-container')
|
||||||
|
|
||||||
if (!container) {
|
if (!container) {
|
||||||
container = document.createElement("div");
|
container = document.createElement('div')
|
||||||
container.id = "layout-debug-container";
|
container.id = 'layout-debug-container'
|
||||||
container.className = "layout-debug-container";
|
container.className = 'layout-debug-container'
|
||||||
document.body.appendChild(container);
|
document.body.appendChild(container)
|
||||||
}
|
|
||||||
|
|
||||||
this._element = document.createElement("div");
|
|
||||||
this._element.innerHTML =
|
|
||||||
`<div class='layout-debug-widget'>` +
|
|
||||||
`<div class='layout-debug-widget-row'><span>Groups:</span><span id='group-count'>0</span></div>` +
|
|
||||||
`<div class='layout-debug-widget-row'><span>Panels:</span><span id='panel-count'>0</span></div>` +
|
|
||||||
`</div>`;
|
|
||||||
|
|
||||||
container.appendChild(this._element);
|
|
||||||
|
|
||||||
const gc = this._element.querySelector("#group-count");
|
|
||||||
const pc = this._element.querySelector("#panel-count");
|
|
||||||
|
|
||||||
const events = [
|
|
||||||
GroupChangeKind.PANEL_CREATED,
|
|
||||||
GroupChangeKind.PANEL_DESTROYED,
|
|
||||||
GroupChangeKind.ADD_GROUP,
|
|
||||||
GroupChangeKind.REMOVE_GROUP,
|
|
||||||
];
|
|
||||||
|
|
||||||
this.addDisposables(
|
|
||||||
this.layout.onDidLayoutChange((event) => {
|
|
||||||
if (events.includes(event.kind)) {
|
|
||||||
gc.textContent = this.layout.size.toString();
|
|
||||||
pc.textContent = this.layout.totalPanels.toString();
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public dispose() {
|
this._element = document.createElement('div')
|
||||||
super.dispose();
|
this._element.innerHTML =
|
||||||
|
`<div class='layout-debug-widget'>` +
|
||||||
|
`<div class='layout-debug-widget-row'><span>Groups:</span><span id='group-count'>0</span></div>` +
|
||||||
|
`<div class='layout-debug-widget-row'><span>Panels:</span><span id='panel-count'>0</span></div>` +
|
||||||
|
`</div>`
|
||||||
|
|
||||||
this._element.remove();
|
container.appendChild(this._element)
|
||||||
|
|
||||||
const container = document.getElementById("layout-debug-container");
|
const gc = this._element.querySelector('#group-count')
|
||||||
if (container && container.children.length === 0) {
|
const pc = this._element.querySelector('#panel-count')
|
||||||
container.remove();
|
|
||||||
|
const events = [
|
||||||
|
GroupChangeKind.PANEL_CREATED,
|
||||||
|
GroupChangeKind.PANEL_DESTROYED,
|
||||||
|
GroupChangeKind.ADD_GROUP,
|
||||||
|
GroupChangeKind.REMOVE_GROUP,
|
||||||
|
]
|
||||||
|
|
||||||
|
this.addDisposables(
|
||||||
|
this.layout.onDidLayoutChange((event) => {
|
||||||
|
if (events.includes(event.kind)) {
|
||||||
|
gc.textContent = this.layout.size.toString()
|
||||||
|
pc.textContent = this.layout.totalPanels.toString()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public dispose() {
|
||||||
|
super.dispose()
|
||||||
|
|
||||||
|
this._element.remove()
|
||||||
|
|
||||||
|
const container = document.getElementById('layout-debug-container')
|
||||||
|
if (container && container.children.length === 0) {
|
||||||
|
container.remove()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,77 +1,79 @@
|
|||||||
.tab {
|
.tab {
|
||||||
&.dragging {
|
&.dragging {
|
||||||
.tab-action {
|
|
||||||
background-color: var(--active-group-visible-panel-color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.active-tab > .default-tab {
|
|
||||||
.tab-action {
|
|
||||||
visibility: visible;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.inactive-tab > .default-tab {
|
|
||||||
.tab-action:not(.dirty) {
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
&:hover {
|
|
||||||
.tab-action {
|
|
||||||
visibility: visible;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.default-tab {
|
|
||||||
position: relative;
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
min-width: 80px;
|
|
||||||
align-items: center;
|
|
||||||
padding-left: 10px;
|
|
||||||
white-space: nowrap;
|
|
||||||
text-overflow: elipsis;
|
|
||||||
font-size: 13px;
|
|
||||||
|
|
||||||
.tab-content {
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.action-container {
|
|
||||||
text-align: right;
|
|
||||||
width: 28px;
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
.tab-list {
|
|
||||||
display: flex;
|
|
||||||
padding: 0px;
|
|
||||||
margin: 0px;
|
|
||||||
justify-content: flex-end;
|
|
||||||
|
|
||||||
a:active:hover {
|
|
||||||
-webkit-mask-size: 100% 100% !important;
|
|
||||||
mask-size: 100% 100% !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tab-action {
|
.tab-action {
|
||||||
height: 16px;
|
background-color: var(--active-group-visible-panel-color);
|
||||||
width: 16px;
|
}
|
||||||
display: block;
|
}
|
||||||
-webkit-mask: var(--tab-close-icon) 50% 50% / 90% 90% no-repeat;
|
|
||||||
mask: var(--tab-close-icon) 50% 50% / 90% 90% no-repeat;
|
&.active-tab > .default-tab {
|
||||||
margin-right: "0.5em";
|
.tab-action {
|
||||||
|
visibility: visible;
|
||||||
&.disable-close {
|
}
|
||||||
display: none;
|
}
|
||||||
}
|
|
||||||
|
&.inactive-tab > .default-tab {
|
||||||
&.dirty:not(:hover) {
|
.tab-action:not(.dirty) {
|
||||||
display: block;
|
visibility: hidden;
|
||||||
-webkit-mask: var(--tab-dirty-icon) 50% 50% / 60% 60% no-repeat;
|
}
|
||||||
mask: var(--tab-dirty-icon) 50% 50% / 60% 60% no-repeat;
|
&:hover {
|
||||||
}
|
.tab-action {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.default-tab {
|
||||||
|
position: relative;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
min-width: 80px;
|
||||||
|
align-items: center;
|
||||||
|
padding-left: 10px;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: elipsis;
|
||||||
|
font-size: 13px;
|
||||||
|
|
||||||
|
.tab-content {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-container {
|
||||||
|
text-align: right;
|
||||||
|
width: 28px;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
.tab-list {
|
||||||
|
display: flex;
|
||||||
|
padding: 0px;
|
||||||
|
margin: 0px;
|
||||||
|
justify-content: flex-end;
|
||||||
|
|
||||||
|
a:active:hover {
|
||||||
|
-webkit-mask-size: 100% 100% !important;
|
||||||
|
mask-size: 100% 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-action {
|
||||||
|
height: 16px;
|
||||||
|
width: 16px;
|
||||||
|
display: block;
|
||||||
|
-webkit-mask: var(--tab-close-icon) 50% 50% / 90% 90%
|
||||||
|
no-repeat;
|
||||||
|
mask: var(--tab-close-icon) 50% 50% / 90% 90% no-repeat;
|
||||||
|
margin-right: '0.5em';
|
||||||
|
|
||||||
|
&.disable-close {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.dirty:not(:hover) {
|
||||||
|
display: block;
|
||||||
|
-webkit-mask: var(--tab-dirty-icon) 50% 50% / 60% 60%
|
||||||
|
no-repeat;
|
||||||
|
mask: var(--tab-dirty-icon) 50% 50% / 60% 60% no-repeat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,97 +1,99 @@
|
|||||||
import { CompositeDisposable, MutableDisposable } from "../../../lifecycle";
|
import { CompositeDisposable, MutableDisposable } from '../../../lifecycle'
|
||||||
import {
|
import {
|
||||||
PanelHeaderPart,
|
PanelHeaderPart,
|
||||||
PartInitParameters,
|
PartInitParameters,
|
||||||
} from "../../../groupview/panel/parts";
|
} from '../../../groupview/panel/parts'
|
||||||
import { addDisposableListener } from "../../../events";
|
import { addDisposableListener } from '../../../events'
|
||||||
import { toggleClass } from "../../../dom";
|
import { toggleClass } from '../../../dom'
|
||||||
|
|
||||||
export class DefaultTab extends CompositeDisposable implements PanelHeaderPart {
|
export class DefaultTab extends CompositeDisposable implements PanelHeaderPart {
|
||||||
private _element: HTMLElement;
|
private _element: HTMLElement
|
||||||
private _isGroupActive: boolean;
|
private _isGroupActive: boolean
|
||||||
private _isPanelVisible: boolean;
|
private _isPanelVisible: boolean
|
||||||
|
|
||||||
//
|
|
||||||
private _content: HTMLElement;
|
|
||||||
private _actionContainer: HTMLElement;
|
|
||||||
private _list: HTMLElement;
|
|
||||||
private action: HTMLElement;
|
|
||||||
//
|
|
||||||
private params: PartInitParameters;
|
|
||||||
//
|
|
||||||
private isDirtyDisposable = new MutableDisposable();
|
|
||||||
|
|
||||||
get element() {
|
|
||||||
return this._element;
|
|
||||||
}
|
|
||||||
|
|
||||||
get id() {
|
|
||||||
return "__DEFAULT_TAB__";
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this._element = document.createElement("div");
|
|
||||||
this._element.className = "default-tab";
|
|
||||||
//
|
//
|
||||||
this._content = document.createElement("div");
|
private _content: HTMLElement
|
||||||
this._content.className = "tab-content";
|
private _actionContainer: HTMLElement
|
||||||
|
private _list: HTMLElement
|
||||||
|
private action: HTMLElement
|
||||||
//
|
//
|
||||||
this._actionContainer = document.createElement("div");
|
private params: PartInitParameters
|
||||||
this._actionContainer.className = "action-container";
|
|
||||||
//
|
//
|
||||||
this._list = document.createElement("ul");
|
private isDirtyDisposable = new MutableDisposable()
|
||||||
this._list.className = "tab-list";
|
|
||||||
//
|
|
||||||
this.action = document.createElement("a");
|
|
||||||
this.action.className = "tab-action";
|
|
||||||
//
|
|
||||||
this._element.appendChild(this._content);
|
|
||||||
this._element.appendChild(this._actionContainer);
|
|
||||||
this._actionContainer.appendChild(this._list);
|
|
||||||
this._list.appendChild(this.action);
|
|
||||||
//
|
|
||||||
this.addDisposables(
|
|
||||||
addDisposableListener(this._actionContainer, "mousedown", (ev) => {
|
|
||||||
ev.preventDefault();
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
this.render();
|
get element() {
|
||||||
}
|
return this._element
|
||||||
|
|
||||||
public toJSON() {
|
|
||||||
return { id: this.id };
|
|
||||||
}
|
|
||||||
|
|
||||||
public init(params: PartInitParameters) {
|
|
||||||
this.params = params;
|
|
||||||
this._content.textContent = params.title;
|
|
||||||
|
|
||||||
this.isDirtyDisposable.value = this.params.api.onDidDirtyChange((event) => {
|
|
||||||
const isDirty = event;
|
|
||||||
toggleClass(this.action, "dirty", isDirty);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!this.params.suppressClosable) {
|
|
||||||
addDisposableListener(this.action, "click", (ev) => {
|
|
||||||
ev.preventDefault(); //
|
|
||||||
this.params.api.close();
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.action.classList.add("disable-close");
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public setVisible(isPanelVisible: boolean, isGroupVisible: boolean) {
|
get id() {
|
||||||
this._isPanelVisible = isPanelVisible;
|
return '__DEFAULT_TAB__'
|
||||||
this._isGroupActive = isGroupVisible;
|
}
|
||||||
|
|
||||||
this.render();
|
constructor() {
|
||||||
}
|
super()
|
||||||
|
|
||||||
private render() {
|
this._element = document.createElement('div')
|
||||||
//
|
this._element.className = 'default-tab'
|
||||||
}
|
//
|
||||||
|
this._content = document.createElement('div')
|
||||||
|
this._content.className = 'tab-content'
|
||||||
|
//
|
||||||
|
this._actionContainer = document.createElement('div')
|
||||||
|
this._actionContainer.className = 'action-container'
|
||||||
|
//
|
||||||
|
this._list = document.createElement('ul')
|
||||||
|
this._list.className = 'tab-list'
|
||||||
|
//
|
||||||
|
this.action = document.createElement('a')
|
||||||
|
this.action.className = 'tab-action'
|
||||||
|
//
|
||||||
|
this._element.appendChild(this._content)
|
||||||
|
this._element.appendChild(this._actionContainer)
|
||||||
|
this._actionContainer.appendChild(this._list)
|
||||||
|
this._list.appendChild(this.action)
|
||||||
|
//
|
||||||
|
this.addDisposables(
|
||||||
|
addDisposableListener(this._actionContainer, 'mousedown', (ev) => {
|
||||||
|
ev.preventDefault()
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
this.render()
|
||||||
|
}
|
||||||
|
|
||||||
|
public toJSON() {
|
||||||
|
return { id: this.id }
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(params: PartInitParameters) {
|
||||||
|
this.params = params
|
||||||
|
this._content.textContent = params.title
|
||||||
|
|
||||||
|
this.isDirtyDisposable.value = this.params.api.onDidDirtyChange(
|
||||||
|
(event) => {
|
||||||
|
const isDirty = event
|
||||||
|
toggleClass(this.action, 'dirty', isDirty)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!this.params.suppressClosable) {
|
||||||
|
addDisposableListener(this.action, 'click', (ev) => {
|
||||||
|
ev.preventDefault() //
|
||||||
|
this.params.api.close()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.action.classList.add('disable-close')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public setVisible(isPanelVisible: boolean, isGroupVisible: boolean) {
|
||||||
|
this._isPanelVisible = isPanelVisible
|
||||||
|
this._isGroupActive = isGroupVisible
|
||||||
|
|
||||||
|
this.render()
|
||||||
|
}
|
||||||
|
|
||||||
|
private render() {
|
||||||
|
//
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
.watermark {
|
.watermark {
|
||||||
display: flex;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
&.has-actions {
|
|
||||||
.watermark-title {
|
|
||||||
.actions-bar {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.watermark-title {
|
|
||||||
height: 35px;
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
width: 100%;
|
||||||
.watermark-content {
|
|
||||||
flex-grow: 1;
|
&.has-actions {
|
||||||
}
|
.watermark-title {
|
||||||
|
.actions-bar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.watermark-title {
|
||||||
|
height: 35px;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.watermark-content {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,81 +1,81 @@
|
|||||||
import {
|
import {
|
||||||
WatermarkPart,
|
WatermarkPart,
|
||||||
WatermarkPartInitParameters,
|
WatermarkPartInitParameters,
|
||||||
} from "../../../groupview/panel/parts";
|
} from '../../../groupview/panel/parts'
|
||||||
import { IGroupAccessor } from "../../layout";
|
import { IGroupAccessor } from '../../layout'
|
||||||
import { IGroupview } from "../../../groupview/groupview";
|
import { IGroupview } from '../../../groupview/groupview'
|
||||||
import { ActionContainer } from "../../../groupview/actions/actionsContainer";
|
import { ActionContainer } from '../../../groupview/actions/actionsContainer'
|
||||||
import { addDisposableListener } from "../../../events";
|
import { addDisposableListener } from '../../../events'
|
||||||
import { toggleClass } from "../../../dom";
|
import { toggleClass } from '../../../dom'
|
||||||
import { CompositeDisposable } from "../../../lifecycle";
|
import { CompositeDisposable } from '../../../lifecycle'
|
||||||
|
|
||||||
export class Watermark extends CompositeDisposable implements WatermarkPart {
|
export class Watermark extends CompositeDisposable implements WatermarkPart {
|
||||||
private _element: HTMLElement;
|
private _element: HTMLElement
|
||||||
private accessor: IGroupAccessor;
|
private accessor: IGroupAccessor
|
||||||
|
|
||||||
private _visible: boolean;
|
private _visible: boolean
|
||||||
private _group: IGroupview;
|
private _group: IGroupview
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super()
|
||||||
this._element = document.createElement("div");
|
this._element = document.createElement('div')
|
||||||
this._element.className = "watermark";
|
this._element.className = 'watermark'
|
||||||
|
|
||||||
const title = document.createElement("div");
|
const title = document.createElement('div')
|
||||||
title.className = "watermark-title";
|
title.className = 'watermark-title'
|
||||||
|
|
||||||
const emptySpace = document.createElement("span");
|
const emptySpace = document.createElement('span')
|
||||||
emptySpace.style.flexGrow = "1";
|
emptySpace.style.flexGrow = '1'
|
||||||
|
|
||||||
const content = document.createElement("div");
|
const content = document.createElement('div')
|
||||||
content.className = "watermark-content";
|
content.className = 'watermark-content'
|
||||||
|
|
||||||
this._element.appendChild(title);
|
this._element.appendChild(title)
|
||||||
this._element.appendChild(content);
|
this._element.appendChild(content)
|
||||||
|
|
||||||
const actions = new ActionContainer();
|
const actions = new ActionContainer()
|
||||||
title.appendChild(emptySpace);
|
title.appendChild(emptySpace)
|
||||||
title.appendChild(actions.element);
|
title.appendChild(actions.element)
|
||||||
|
|
||||||
const closeAnchor = document.createElement("a");
|
const closeAnchor = document.createElement('a')
|
||||||
closeAnchor.className = "close-action";
|
closeAnchor.className = 'close-action'
|
||||||
|
|
||||||
actions.add(closeAnchor);
|
actions.add(closeAnchor)
|
||||||
|
|
||||||
addDisposableListener(closeAnchor, "click", (ev) => {
|
addDisposableListener(closeAnchor, 'click', (ev) => {
|
||||||
ev.preventDefault(); //
|
ev.preventDefault() //
|
||||||
this.accessor.removeGroup(this._group);
|
this.accessor.removeGroup(this._group)
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(params: WatermarkPartInitParameters) {
|
public init(params: WatermarkPartInitParameters) {
|
||||||
this.accessor = params.accessor;
|
this.accessor = params.accessor
|
||||||
|
|
||||||
this.addDisposables(
|
this.addDisposables(
|
||||||
this.accessor.onDidLayoutChange((event) => {
|
this.accessor.onDidLayoutChange((event) => {
|
||||||
this.render();
|
this.render()
|
||||||
})
|
})
|
||||||
);
|
)
|
||||||
|
|
||||||
this.render();
|
this.render()
|
||||||
}
|
}
|
||||||
|
|
||||||
public setVisible(visible: boolean, group: IGroupview): void {
|
public setVisible(visible: boolean, group: IGroupview): void {
|
||||||
this._visible = visible;
|
this._visible = visible
|
||||||
this._group = group;
|
this._group = group
|
||||||
this.render();
|
this.render()
|
||||||
}
|
}
|
||||||
|
|
||||||
get element() {
|
get element() {
|
||||||
return this._element;
|
return this._element
|
||||||
}
|
}
|
||||||
|
|
||||||
private render() {
|
private render() {
|
||||||
const isOneGroup = this.accessor.size <= 1;
|
const isOneGroup = this.accessor.size <= 1
|
||||||
toggleClass(this.element, "has-actions", isOneGroup);
|
toggleClass(this.element, 'has-actions', isOneGroup)
|
||||||
}
|
}
|
||||||
|
|
||||||
public dispose() {
|
public dispose() {
|
||||||
super.dispose();
|
super.dispose()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,34 +1,34 @@
|
|||||||
import { IGridView, IViewDeserializer } from "../gridview/gridview";
|
import { IGridView, IViewDeserializer } from '../gridview/gridview'
|
||||||
import { IGroupPanel } from "../groupview/panel/types";
|
import { IGroupPanel } from '../groupview/panel/types'
|
||||||
import { Layout } from "./layout";
|
import { Layout } from './layout'
|
||||||
|
|
||||||
export interface IPanelDeserializer {
|
export interface IPanelDeserializer {
|
||||||
fromJSON(panelData: { [index: string]: any }): IGroupPanel;
|
fromJSON(panelData: { [index: string]: any }): IGroupPanel
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DefaultDeserializer implements IViewDeserializer {
|
export class DefaultDeserializer implements IViewDeserializer {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly layout: Layout,
|
private readonly layout: Layout,
|
||||||
private panelDeserializer: { createPanel: (id: string) => IGroupPanel }
|
private panelDeserializer: { createPanel: (id: string) => IGroupPanel }
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public fromJSON(data: { [key: string]: any }): IGridView {
|
public fromJSON(data: { [key: string]: any }): IGridView {
|
||||||
const children = data.views;
|
const children = data.views
|
||||||
const active = data.activeView;
|
const active = data.activeView
|
||||||
|
|
||||||
const panels: IGroupPanel[] = [];
|
const panels: IGroupPanel[] = []
|
||||||
|
|
||||||
for (const child of children) {
|
for (const child of children) {
|
||||||
const panel = this.panelDeserializer.createPanel(child);
|
const panel = this.panelDeserializer.createPanel(child)
|
||||||
|
|
||||||
panels.push(panel);
|
panels.push(panel)
|
||||||
|
}
|
||||||
|
|
||||||
|
const group = this.layout.createGroup({
|
||||||
|
panels,
|
||||||
|
activePanel: panels.find((p) => p.id === active),
|
||||||
|
})
|
||||||
|
|
||||||
|
return group
|
||||||
}
|
}
|
||||||
|
|
||||||
const group = this.layout.createGroup({
|
|
||||||
panels,
|
|
||||||
activePanel: panels.find((p) => p.id === active),
|
|
||||||
});
|
|
||||||
|
|
||||||
return group;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
export * from "./layout";
|
export * from './layout'
|
||||||
export * from "./componentGridview";
|
export * from './componentGridview'
|
||||||
export * from "./options";
|
export * from './options'
|
||||||
|
@ -1,63 +1,63 @@
|
|||||||
.custom-dragging {
|
.custom-dragging {
|
||||||
height: 24px;
|
height: 24px;
|
||||||
line-height: 24px;
|
line-height: 24px;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
width: 100px;
|
width: 100px;
|
||||||
background-color: dodgerblue;
|
background-color: dodgerblue;
|
||||||
color: ghostwhite;
|
color: ghostwhite;
|
||||||
border-radius: 11px;
|
border-radius: 11px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.groupview {
|
.groupview {
|
||||||
&.active-group {
|
&.active-group {
|
||||||
> .title-container > .tab-container > .tab {
|
> .title-container > .tab-container > .tab {
|
||||||
&.active-tab {
|
&.active-tab {
|
||||||
background-color: var(--active-tab-background-visible);
|
background-color: var(--active-tab-background-visible);
|
||||||
color: var(--active-group-visible-panel-color);
|
color: var(--active-group-visible-panel-color);
|
||||||
|
|
||||||
.tab-action {
|
.tab-action {
|
||||||
background-color: var(--active-group-visible-panel-color);
|
background-color: var(--active-group-visible-panel-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&.inactive-tab {
|
&.inactive-tab {
|
||||||
background-color: var(--active-tab-background-hidden);
|
background-color: var(--active-tab-background-hidden);
|
||||||
color: var(--active-group-hidden-panel-color);
|
color: var(--active-group-hidden-panel-color);
|
||||||
|
|
||||||
.tab-action {
|
.tab-action {
|
||||||
background-color: var(--active-group-hidden-panel-color);
|
background-color: var(--active-group-hidden-panel-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
&.inactive-group {
|
||||||
&.inactive-group {
|
> .title-container > .tab-container > .tab {
|
||||||
> .title-container > .tab-container > .tab {
|
&.active-tab {
|
||||||
&.active-tab {
|
background-color: var(--inactive-tab-background-visible);
|
||||||
background-color: var(--inactive-tab-background-visible);
|
color: var(--inactive-group-visible-panel-color);
|
||||||
color: var(--inactive-group-visible-panel-color);
|
|
||||||
|
|
||||||
.tab-action {
|
.tab-action {
|
||||||
background-color: var(--inactive-group-visible-panel-color);
|
background-color: var(--inactive-group-visible-panel-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&.inactive-tab {
|
&.inactive-tab {
|
||||||
background-color: var(--inactive-tab-background-hidden);
|
background-color: var(--inactive-tab-background-hidden);
|
||||||
color: var(--inactive-group-hidden-panel-color);
|
color: var(--inactive-group-hidden-panel-color);
|
||||||
|
|
||||||
.tab-action {
|
.tab-action {
|
||||||
background-color: var(--inactive-group-hidden-panel-color);
|
background-color: var(--inactive-group-hidden-panel-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// when a tab is dragged we loss the above stylings because they are conditional on parent elements
|
// when a tab is dragged we loss the above stylings because they are conditional on parent elements
|
||||||
// there we also set some stylings for the dragging event
|
// there we also set some stylings for the dragging event
|
||||||
.tab {
|
.tab {
|
||||||
&.dragging {
|
&.dragging {
|
||||||
background-color: var(--active-tab-background-visible);
|
background-color: var(--active-tab-background-visible);
|
||||||
color: var(--active-group-visible-panel-color);
|
color: var(--active-group-visible-panel-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,72 +1,72 @@
|
|||||||
import { IGroupview } from "../groupview/groupview";
|
import { IGroupview } from '../groupview/groupview'
|
||||||
import {
|
import {
|
||||||
PanelContentPart,
|
PanelContentPart,
|
||||||
PanelContentPartConstructor,
|
PanelContentPartConstructor,
|
||||||
PanelHeaderPart,
|
PanelHeaderPart,
|
||||||
PanelHeaderPartConstructor,
|
PanelHeaderPartConstructor,
|
||||||
WatermarkConstructor,
|
WatermarkConstructor,
|
||||||
} from "../groupview/panel/parts";
|
} from '../groupview/panel/parts'
|
||||||
import { IGroupPanel } from "../groupview/panel/types";
|
import { IGroupPanel } from '../groupview/panel/types'
|
||||||
import { FrameworkFactory } from "../types";
|
import { FrameworkFactory } from '../types'
|
||||||
import { Api } from "./layout";
|
import { Api } from './layout'
|
||||||
|
|
||||||
export interface GroupPanelFrameworkComponentFactory {
|
export interface GroupPanelFrameworkComponentFactory {
|
||||||
content: FrameworkFactory<PanelContentPart>;
|
content: FrameworkFactory<PanelContentPart>
|
||||||
tab: FrameworkFactory<PanelHeaderPart>;
|
tab: FrameworkFactory<PanelHeaderPart>
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TabContextMenuEvent {
|
export interface TabContextMenuEvent {
|
||||||
event: MouseEvent;
|
event: MouseEvent
|
||||||
api: Api;
|
api: Api
|
||||||
panel: IGroupPanel;
|
panel: IGroupPanel
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LayoutOptions {
|
export interface LayoutOptions {
|
||||||
tabComponents?: {
|
tabComponents?: {
|
||||||
[componentName: string]: PanelHeaderPartConstructor;
|
[componentName: string]: PanelHeaderPartConstructor
|
||||||
};
|
}
|
||||||
components?: {
|
components?: {
|
||||||
[componentName: string]: PanelContentPartConstructor;
|
[componentName: string]: PanelContentPartConstructor
|
||||||
};
|
}
|
||||||
frameworkTabComponents?: {
|
frameworkTabComponents?: {
|
||||||
[componentName: string]: any;
|
[componentName: string]: any
|
||||||
};
|
}
|
||||||
frameworkComponents?: {
|
frameworkComponents?: {
|
||||||
[componentName: string]: any;
|
[componentName: string]: any
|
||||||
};
|
}
|
||||||
watermarkComponent?: WatermarkConstructor;
|
watermarkComponent?: WatermarkConstructor
|
||||||
watermarkFrameworkComponent?: any;
|
watermarkFrameworkComponent?: any
|
||||||
frameworkComponentFactory: GroupPanelFrameworkComponentFactory;
|
frameworkComponentFactory: GroupPanelFrameworkComponentFactory
|
||||||
tabHeight?: number;
|
tabHeight?: number
|
||||||
debug?: boolean;
|
debug?: boolean
|
||||||
enableExternalDragEvents?: boolean;
|
enableExternalDragEvents?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PanelOptions {
|
export interface PanelOptions {
|
||||||
componentName: string;
|
componentName: string
|
||||||
tabComponentName?: string;
|
tabComponentName?: string
|
||||||
params?: { [key: string]: any };
|
params?: { [key: string]: any }
|
||||||
id: string;
|
id: string
|
||||||
title?: string;
|
title?: string
|
||||||
suppressClosable?: boolean;
|
suppressClosable?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AddPanelOptions
|
export interface AddPanelOptions
|
||||||
extends Omit<PanelOptions, "componentName" | "tabComponentName"> {
|
extends Omit<PanelOptions, 'componentName' | 'tabComponentName'> {
|
||||||
componentName: string | PanelContentPartConstructor;
|
componentName: string | PanelContentPartConstructor
|
||||||
tabComponentName?: string | PanelHeaderPartConstructor;
|
tabComponentName?: string | PanelHeaderPartConstructor
|
||||||
position?: {
|
position?: {
|
||||||
direction?: "left" | "right" | "above" | "below" | "within";
|
direction?: 'left' | 'right' | 'above' | 'below' | 'within'
|
||||||
referencePanel: string;
|
referencePanel: string
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AddGroupOptions {
|
export interface AddGroupOptions {
|
||||||
direction?: "left" | "right" | "above" | "below";
|
direction?: 'left' | 'right' | 'above' | 'below'
|
||||||
referencePanel: string;
|
referencePanel: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MovementOptions {
|
export interface MovementOptions {
|
||||||
group?: IGroupview;
|
group?: IGroupview
|
||||||
includePanel?: boolean;
|
includePanel?: boolean
|
||||||
}
|
}
|
||||||
|
@ -1,56 +1,56 @@
|
|||||||
export interface IDisposable {
|
export interface IDisposable {
|
||||||
dispose: () => void;
|
dispose: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IValueDisposable<T> {
|
export interface IValueDisposable<T> {
|
||||||
value: T;
|
value: T
|
||||||
disposable: IDisposable;
|
disposable: IDisposable
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISerializable {
|
export interface ISerializable {
|
||||||
toJSON(): object;
|
toJSON(): object
|
||||||
fromJSON(data: object): void;
|
fromJSON(data: object): void
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace Disposable {
|
export namespace Disposable {
|
||||||
export const NONE: IDisposable = { dispose: () => {} };
|
export const NONE: IDisposable = { dispose: () => {} }
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CompositeDisposable {
|
export class CompositeDisposable {
|
||||||
private disposables: IDisposable[];
|
private disposables: IDisposable[]
|
||||||
|
|
||||||
public static from(...args: IDisposable[]) {
|
public static from(...args: IDisposable[]) {
|
||||||
return new CompositeDisposable(...args);
|
return new CompositeDisposable(...args)
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(...args: IDisposable[]) {
|
constructor(...args: IDisposable[]) {
|
||||||
this.disposables = args;
|
this.disposables = args
|
||||||
}
|
}
|
||||||
|
|
||||||
public addDisposables(...args: IDisposable[]) {
|
public addDisposables(...args: IDisposable[]) {
|
||||||
args?.forEach((arg) => this.disposables.push(arg));
|
args?.forEach((arg) => this.disposables.push(arg))
|
||||||
}
|
}
|
||||||
|
|
||||||
public dispose() {
|
public dispose() {
|
||||||
this.disposables.forEach((arg) => arg.dispose());
|
this.disposables.forEach((arg) => arg.dispose())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class MutableDisposable implements IDisposable {
|
export class MutableDisposable implements IDisposable {
|
||||||
private _disposable: IDisposable;
|
private _disposable: IDisposable
|
||||||
|
|
||||||
constructor() {}
|
constructor() {}
|
||||||
|
|
||||||
set value(disposable: IDisposable) {
|
set value(disposable: IDisposable) {
|
||||||
if (this._disposable) {
|
if (this._disposable) {
|
||||||
this._disposable.dispose();
|
this._disposable.dispose()
|
||||||
|
}
|
||||||
|
this._disposable = disposable
|
||||||
}
|
}
|
||||||
this._disposable = disposable;
|
|
||||||
}
|
|
||||||
|
|
||||||
public dispose() {
|
public dispose() {
|
||||||
if (this._disposable) {
|
if (this._disposable) {
|
||||||
this._disposable.dispose();
|
this._disposable.dispose()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
export const clamp = (value: number, min: number, max: number) => {
|
export const clamp = (value: number, min: number, max: number) => {
|
||||||
return Math.min(max, Math.max(value, min));
|
return Math.min(max, Math.max(value, min))
|
||||||
};
|
}
|
||||||
|
|
||||||
export const sequentialNumberGenerator = () => {
|
export const sequentialNumberGenerator = () => {
|
||||||
let value = 1;
|
let value = 1
|
||||||
return { next: () => (value++).toString() };
|
return { next: () => (value++).toString() }
|
||||||
};
|
}
|
||||||
|
@ -1,161 +1,163 @@
|
|||||||
import { PanelDimensionChangeEvent } from "./types";
|
import { PanelDimensionChangeEvent } from './types'
|
||||||
import { Emitter, Event } from "../events";
|
import { Emitter, Event } from '../events'
|
||||||
import { CompositeDisposable, IDisposable } from "../lifecycle";
|
import { CompositeDisposable, IDisposable } from '../lifecycle'
|
||||||
import { FunctionOrValue } from "../types";
|
import { FunctionOrValue } from '../types'
|
||||||
|
|
||||||
// we've tried to do a bit better than the 'any' type.
|
// we've tried to do a bit better than the 'any' type.
|
||||||
// anything that is serializable JSON should be valid here
|
// anything that is serializable JSON should be valid here
|
||||||
type StateObject =
|
type StateObject =
|
||||||
| number
|
| number
|
||||||
| string
|
| string
|
||||||
| boolean
|
| boolean
|
||||||
| undefined
|
| undefined
|
||||||
| null
|
| null
|
||||||
| object
|
| object
|
||||||
| StateObject[]
|
| StateObject[]
|
||||||
| { [key: string]: StateObject };
|
| { [key: string]: StateObject }
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
[key: string]: StateObject;
|
[key: string]: StateObject
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ChangeFocusEvent {
|
interface ChangeFocusEvent {
|
||||||
isFocused: boolean;
|
isFocused: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
interface PanelConstraintChangeEvent {
|
interface PanelConstraintChangeEvent {
|
||||||
minimumSize?: number | (() => number);
|
minimumSize?: number | (() => number)
|
||||||
maximumSize?: number | (() => number);
|
maximumSize?: number | (() => number)
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IBaseViewApi extends IDisposable {
|
export interface IBaseViewApi extends IDisposable {
|
||||||
// events
|
// events
|
||||||
onDidDimensionsChange: Event<PanelDimensionChangeEvent>;
|
onDidDimensionsChange: Event<PanelDimensionChangeEvent>
|
||||||
onDidStateChange: Event<void>;
|
onDidStateChange: Event<void>
|
||||||
onDidFocusChange: Event<ChangeFocusEvent>;
|
onDidFocusChange: Event<ChangeFocusEvent>
|
||||||
// state
|
// state
|
||||||
setState(key: string, value: StateObject): void;
|
setState(key: string, value: StateObject): void
|
||||||
setState(state: State): void;
|
setState(state: State): void
|
||||||
getState: () => State;
|
getState: () => State
|
||||||
getStateKey: <T extends StateObject>(key: string) => T;
|
getStateKey: <T extends StateObject>(key: string) => T
|
||||||
//
|
//
|
||||||
readonly isFocused: boolean;
|
readonly isFocused: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A core api implementation that should be used across all panel-like objects
|
* A core api implementation that should be used across all panel-like objects
|
||||||
*/
|
*/
|
||||||
export class BaseViewApi extends CompositeDisposable implements IBaseViewApi {
|
export class BaseViewApi extends CompositeDisposable implements IBaseViewApi {
|
||||||
private _state: State = {};
|
private _state: State = {}
|
||||||
private _isFocused: boolean;
|
private _isFocused: boolean
|
||||||
|
|
||||||
readonly _onDidStateChange = new Emitter<void>();
|
readonly _onDidStateChange = new Emitter<void>()
|
||||||
readonly onDidStateChange: Event<void> = this._onDidStateChange.event;
|
readonly onDidStateChange: Event<void> = this._onDidStateChange.event
|
||||||
//
|
//
|
||||||
readonly _onDidPanelDimensionChange = new Emitter<PanelDimensionChangeEvent>({
|
readonly _onDidPanelDimensionChange = new Emitter<
|
||||||
emitLastValue: true,
|
PanelDimensionChangeEvent
|
||||||
});
|
>({
|
||||||
readonly onDidDimensionsChange = this._onDidPanelDimensionChange.event;
|
emitLastValue: true,
|
||||||
//
|
})
|
||||||
readonly _onDidChangeFocus = new Emitter<ChangeFocusEvent>({
|
readonly onDidDimensionsChange = this._onDidPanelDimensionChange.event
|
||||||
emitLastValue: true,
|
//
|
||||||
});
|
readonly _onDidChangeFocus = new Emitter<ChangeFocusEvent>({
|
||||||
readonly onDidFocusChange: Event<ChangeFocusEvent> = this._onDidChangeFocus
|
emitLastValue: true,
|
||||||
.event;
|
})
|
||||||
//
|
readonly onDidFocusChange: Event<ChangeFocusEvent> = this._onDidChangeFocus
|
||||||
|
.event
|
||||||
|
//
|
||||||
|
|
||||||
get isFocused() {
|
get isFocused() {
|
||||||
return this._isFocused;
|
return this._isFocused
|
||||||
}
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this.addDisposables(
|
|
||||||
this._onDidStateChange,
|
|
||||||
this._onDidChangeFocus,
|
|
||||||
this._onDidPanelDimensionChange,
|
|
||||||
this.onDidFocusChange((event) => {
|
|
||||||
this._isFocused = event.isFocused;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public setState(
|
|
||||||
key: string | { [key: string]: StateObject },
|
|
||||||
value?: StateObject
|
|
||||||
) {
|
|
||||||
if (typeof key === "object") {
|
|
||||||
this._state = key;
|
|
||||||
} else {
|
|
||||||
this._state[key] = value;
|
|
||||||
}
|
}
|
||||||
this._onDidStateChange.fire(undefined);
|
|
||||||
}
|
|
||||||
|
|
||||||
public getState(): State {
|
constructor() {
|
||||||
return this._state;
|
super()
|
||||||
}
|
|
||||||
|
|
||||||
public getStateKey<T extends StateObject>(key: string): T {
|
this.addDisposables(
|
||||||
return this._state[key] as T;
|
this._onDidStateChange,
|
||||||
}
|
this._onDidChangeFocus,
|
||||||
|
this._onDidPanelDimensionChange,
|
||||||
|
this.onDidFocusChange((event) => {
|
||||||
|
this._isFocused = event.isFocused
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
public dispose() {
|
public setState(
|
||||||
super.dispose();
|
key: string | { [key: string]: StateObject },
|
||||||
}
|
value?: StateObject
|
||||||
|
) {
|
||||||
|
if (typeof key === 'object') {
|
||||||
|
this._state = key
|
||||||
|
} else {
|
||||||
|
this._state[key] = value
|
||||||
|
}
|
||||||
|
this._onDidStateChange.fire(undefined)
|
||||||
|
}
|
||||||
|
|
||||||
|
public getState(): State {
|
||||||
|
return this._state
|
||||||
|
}
|
||||||
|
|
||||||
|
public getStateKey<T extends StateObject>(key: string): T {
|
||||||
|
return this._state[key] as T
|
||||||
|
}
|
||||||
|
|
||||||
|
public dispose() {
|
||||||
|
super.dispose()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface PanelConstraintChangeEvent {
|
interface PanelConstraintChangeEvent {
|
||||||
minimumSize?: FunctionOrValue<number>;
|
minimumSize?: FunctionOrValue<number>
|
||||||
maximumSize?: FunctionOrValue<number>;
|
maximumSize?: FunctionOrValue<number>
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPanelApi extends IBaseViewApi {
|
export interface IPanelApi extends IBaseViewApi {
|
||||||
onDidConstraintsChange: Event<PanelConstraintChangeEvent>;
|
onDidConstraintsChange: Event<PanelConstraintChangeEvent>
|
||||||
setConstraints(value: PanelConstraintChangeEvent): void;
|
setConstraints(value: PanelConstraintChangeEvent): void
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PanelApi extends BaseViewApi implements IBaseViewApi {
|
export class PanelApi extends BaseViewApi implements IBaseViewApi {
|
||||||
readonly _onDidConstraintsChange = new Emitter<PanelConstraintChangeEvent>({
|
readonly _onDidConstraintsChange = new Emitter<PanelConstraintChangeEvent>({
|
||||||
emitLastValue: true,
|
emitLastValue: true,
|
||||||
});
|
})
|
||||||
readonly onDidConstraintsChange: Event<PanelConstraintChangeEvent> = this
|
readonly onDidConstraintsChange: Event<PanelConstraintChangeEvent> = this
|
||||||
._onDidConstraintsChange.event;
|
._onDidConstraintsChange.event
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super()
|
||||||
}
|
}
|
||||||
|
|
||||||
public setConstraints(value: PanelConstraintChangeEvent) {
|
public setConstraints(value: PanelConstraintChangeEvent) {
|
||||||
this._onDidConstraintsChange.fire(value);
|
this._onDidConstraintsChange.fire(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface GridConstraintChangeEvent {
|
interface GridConstraintChangeEvent {
|
||||||
minimumWidth?: FunctionOrValue<number>;
|
minimumWidth?: FunctionOrValue<number>
|
||||||
minimumHeight?: FunctionOrValue<number>;
|
minimumHeight?: FunctionOrValue<number>
|
||||||
maximumWidth?: FunctionOrValue<number>;
|
maximumWidth?: FunctionOrValue<number>
|
||||||
maximumHeight?: FunctionOrValue<number>;
|
maximumHeight?: FunctionOrValue<number>
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IGridApi extends IBaseViewApi {
|
export interface IGridApi extends IBaseViewApi {
|
||||||
onDidConstraintsChange: Event<GridConstraintChangeEvent>;
|
onDidConstraintsChange: Event<GridConstraintChangeEvent>
|
||||||
setConstraints(value: GridConstraintChangeEvent): void;
|
setConstraints(value: GridConstraintChangeEvent): void
|
||||||
}
|
}
|
||||||
|
|
||||||
export class GridApi extends BaseViewApi implements IBaseViewApi {
|
export class GridApi extends BaseViewApi implements IBaseViewApi {
|
||||||
readonly _onDidConstraintsChange = new Emitter<GridConstraintChangeEvent>({
|
readonly _onDidConstraintsChange = new Emitter<GridConstraintChangeEvent>({
|
||||||
emitLastValue: true,
|
emitLastValue: true,
|
||||||
});
|
})
|
||||||
readonly onDidConstraintsChange: Event<GridConstraintChangeEvent> = this
|
readonly onDidConstraintsChange: Event<GridConstraintChangeEvent> = this
|
||||||
._onDidConstraintsChange.event;
|
._onDidConstraintsChange.event
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super()
|
||||||
}
|
}
|
||||||
|
|
||||||
public setConstraints(value: GridConstraintChangeEvent) {
|
public setConstraints(value: GridConstraintChangeEvent) {
|
||||||
this._onDidConstraintsChange.fire(value);
|
this._onDidConstraintsChange.fire(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
export interface InitParameters {
|
export interface InitParameters {
|
||||||
params: { [index: string]: any };
|
params: { [index: string]: any }
|
||||||
state?: { [index: string]: any };
|
state?: { [index: string]: any }
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PanelUpdateEvent {
|
export interface PanelUpdateEvent {
|
||||||
params: { [index: string]: any };
|
params: { [index: string]: any }
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPanel {
|
export interface IPanel {
|
||||||
init?(params: InitParameters): void;
|
init?(params: InitParameters): void
|
||||||
layout?(width: number, height: number): void;
|
layout?(width: number, height: number): void
|
||||||
update?(event: PanelUpdateEvent): void;
|
update?(event: PanelUpdateEvent): void
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PanelDimensionChangeEvent {
|
export interface PanelDimensionChangeEvent {
|
||||||
width: number;
|
width: number
|
||||||
height: number;
|
height: number
|
||||||
}
|
}
|
||||||
|
@ -1,41 +1,41 @@
|
|||||||
.pane-container {
|
.pane-container {
|
||||||
&.animated {
|
&.animated {
|
||||||
|
.view {
|
||||||
|
transition-duration: 0.15s;
|
||||||
|
transition-timing-function: ease-out;
|
||||||
|
}
|
||||||
|
}
|
||||||
.view {
|
.view {
|
||||||
transition-duration: 0.15s;
|
overflow: hidden;
|
||||||
transition-timing-function: ease-out;
|
display: flex;
|
||||||
}
|
flex-direction: column;
|
||||||
}
|
|
||||||
.view {
|
|
||||||
overflow: hidden;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
&:not(:first-child)::before {
|
&:not(:first-child)::before {
|
||||||
background-color: transparent !important;
|
background-color: transparent !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.pane {
|
.pane {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
.pane-header {
|
.pane-header {
|
||||||
background-color: #383838;
|
background-color: #383838;
|
||||||
color: white;
|
color: white;
|
||||||
|
|
||||||
&:focus,
|
&:focus,
|
||||||
:focus-within {
|
:focus-within {
|
||||||
outline-width: 1px;
|
outline-width: 1px;
|
||||||
outline-style: solid;
|
outline-style: solid;
|
||||||
outline-offset: -1px;
|
outline-offset: -1px;
|
||||||
opacity: 1 !important;
|
opacity: 1 !important;
|
||||||
outline-color: dodgerblue;
|
outline-color: dodgerblue;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
.pane-body {
|
||||||
|
overflow: auto;
|
||||||
|
background-color: #252526;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.pane-body {
|
|
||||||
overflow: auto;
|
|
||||||
background-color: #252526;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,274 +1,276 @@
|
|||||||
import { SplitView, IView, Orientation } from "../splitview/splitview";
|
import { SplitView, IView, Orientation } from '../splitview/splitview'
|
||||||
import { IDisposable } from "../lifecycle";
|
import { IDisposable } from '../lifecycle'
|
||||||
import { Emitter } from "../events";
|
import { Emitter } from '../events'
|
||||||
import { addClasses, removeClasses } from "../dom";
|
import { addClasses, removeClasses } from '../dom'
|
||||||
|
|
||||||
export interface IPaneOptions {
|
export interface IPaneOptions {
|
||||||
minimumBodySize?: number;
|
minimumBodySize?: number
|
||||||
maximumBodySize?: number;
|
maximumBodySize?: number
|
||||||
orientation?: Orientation;
|
orientation?: Orientation
|
||||||
isExpanded?: boolean;
|
isExpanded?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class Pane implements IView {
|
export abstract class Pane implements IView {
|
||||||
public element: HTMLElement;
|
public element: HTMLElement
|
||||||
private header: HTMLElement;
|
private header: HTMLElement
|
||||||
private body: HTMLElement;
|
private body: HTMLElement
|
||||||
|
|
||||||
private _onDidChangeExpansionState: Emitter<boolean> = new Emitter<boolean>();
|
private _onDidChangeExpansionState: Emitter<boolean> = new Emitter<
|
||||||
public onDidChangeExpansionState = this._onDidChangeExpansionState.event;
|
boolean
|
||||||
|
>()
|
||||||
|
public onDidChangeExpansionState = this._onDidChangeExpansionState.event
|
||||||
|
|
||||||
private _onDidChange: Emitter<number | undefined> = new Emitter<
|
private _onDidChange: Emitter<number | undefined> = new Emitter<
|
||||||
number | undefined
|
number | undefined
|
||||||
>();
|
>()
|
||||||
public onDidChange = this._onDidChange.event;
|
public onDidChange = this._onDidChange.event
|
||||||
|
|
||||||
private _minimumBodySize: number;
|
private _minimumBodySize: number
|
||||||
private _maximumBodySize: number;
|
private _maximumBodySize: number
|
||||||
|
|
||||||
private _minimumSize: number;
|
private _minimumSize: number
|
||||||
private _maximumSize: number;
|
private _maximumSize: number
|
||||||
private _isExpanded: boolean;
|
private _isExpanded: boolean
|
||||||
private _orientation: Orientation;
|
private _orientation: Orientation
|
||||||
private _orthogonalSize: number;
|
private _orthogonalSize: number
|
||||||
private animationTimer: NodeJS.Timeout;
|
private animationTimer: NodeJS.Timeout
|
||||||
private expandedSize: number;
|
private expandedSize: number
|
||||||
private headerSize = 22;
|
private headerSize = 22
|
||||||
|
|
||||||
constructor(options: IPaneOptions) {
|
constructor(options: IPaneOptions) {
|
||||||
this.element = document.createElement("div");
|
this.element = document.createElement('div')
|
||||||
this.element.className = "pane";
|
this.element.className = 'pane'
|
||||||
|
|
||||||
this._minimumBodySize =
|
this._minimumBodySize =
|
||||||
typeof options.minimumBodySize === "number"
|
typeof options.minimumBodySize === 'number'
|
||||||
? options.minimumBodySize
|
? options.minimumBodySize
|
||||||
: 120;
|
: 120
|
||||||
this._maximumBodySize =
|
this._maximumBodySize =
|
||||||
typeof options.maximumBodySize === "number"
|
typeof options.maximumBodySize === 'number'
|
||||||
? options.maximumBodySize
|
? options.maximumBodySize
|
||||||
: Number.POSITIVE_INFINITY;
|
: Number.POSITIVE_INFINITY
|
||||||
|
|
||||||
this._isExpanded = options.isExpanded;
|
this._isExpanded = options.isExpanded
|
||||||
this.orientation = options.orientation;
|
this.orientation = options.orientation
|
||||||
}
|
|
||||||
|
|
||||||
public get minimumSize(): number {
|
|
||||||
const headerSize = this.headerSize;
|
|
||||||
const expanded = this.isExpanded();
|
|
||||||
const minimumBodySize = expanded
|
|
||||||
? this._minimumBodySize
|
|
||||||
: this._orientation === Orientation.HORIZONTAL
|
|
||||||
? 50
|
|
||||||
: 0;
|
|
||||||
|
|
||||||
return headerSize + minimumBodySize;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get maximumSize(): number {
|
|
||||||
const headerSize = this.headerSize;
|
|
||||||
const expanded = this.isExpanded();
|
|
||||||
const maximumBodySize = expanded
|
|
||||||
? this._maximumBodySize
|
|
||||||
: this._orientation === Orientation.HORIZONTAL
|
|
||||||
? 50
|
|
||||||
: 0;
|
|
||||||
|
|
||||||
return headerSize + maximumBodySize;
|
|
||||||
}
|
|
||||||
|
|
||||||
public isExpanded() {
|
|
||||||
return this._isExpanded;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get orientation() {
|
|
||||||
return this._orientation;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get orthogonalSize() {
|
|
||||||
return this._orthogonalSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
public set minimumSize(size: number) {
|
|
||||||
this._minimumSize = size;
|
|
||||||
this._onDidChange.fire(undefined);
|
|
||||||
}
|
|
||||||
|
|
||||||
public set maximumSize(size: number) {
|
|
||||||
this._maximumSize = size;
|
|
||||||
this._onDidChange.fire(undefined);
|
|
||||||
}
|
|
||||||
|
|
||||||
public setExpanded(expanded: boolean) {
|
|
||||||
this._isExpanded = expanded;
|
|
||||||
|
|
||||||
if (expanded) {
|
|
||||||
if (this.animationTimer) {
|
|
||||||
clearTimeout(this.animationTimer);
|
|
||||||
}
|
|
||||||
this.element.appendChild(this.body);
|
|
||||||
} else {
|
|
||||||
this.animationTimer = setTimeout(() => {
|
|
||||||
this.body.remove();
|
|
||||||
}, 200);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this._onDidChangeExpansionState.fire(expanded);
|
public get minimumSize(): number {
|
||||||
this._onDidChange.fire(expanded ? this.expandedSize : undefined);
|
const headerSize = this.headerSize
|
||||||
}
|
const expanded = this.isExpanded()
|
||||||
|
const minimumBodySize = expanded
|
||||||
|
? this._minimumBodySize
|
||||||
|
: this._orientation === Orientation.HORIZONTAL
|
||||||
|
? 50
|
||||||
|
: 0
|
||||||
|
|
||||||
public set orientation(orientation: Orientation) {
|
return headerSize + minimumBodySize
|
||||||
this._orientation = orientation;
|
|
||||||
}
|
|
||||||
|
|
||||||
public set orthogonalSize(size: number) {
|
|
||||||
this._orthogonalSize = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
public layout(size: number, orthogonalSize: number) {
|
|
||||||
if (this.isExpanded()) {
|
|
||||||
this.expandedSize = size;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public render() {
|
public get maximumSize(): number {
|
||||||
this.header = document.createElement("div");
|
const headerSize = this.headerSize
|
||||||
this.header.className = "pane-header";
|
const expanded = this.isExpanded()
|
||||||
this.header.style.height = `${this.headerSize}px`;
|
const maximumBodySize = expanded
|
||||||
this.header.style.lineHeight = `${this.headerSize}px`;
|
? this._maximumBodySize
|
||||||
this.element.appendChild(this.header);
|
: this._orientation === Orientation.HORIZONTAL
|
||||||
this.renderHeader(this.header);
|
? 50
|
||||||
|
: 0
|
||||||
|
|
||||||
// this.updateHeader();
|
return headerSize + maximumBodySize
|
||||||
|
}
|
||||||
|
|
||||||
this.body = document.createElement("div");
|
public isExpanded() {
|
||||||
this.body.className = "pane-body";
|
return this._isExpanded
|
||||||
this.element.appendChild(this.body);
|
}
|
||||||
this.renderBody(this.body);
|
|
||||||
|
|
||||||
// if (!this.isExpanded()) {
|
public get orientation() {
|
||||||
// this.body.remove();
|
return this._orientation
|
||||||
|
}
|
||||||
|
|
||||||
|
public get orthogonalSize() {
|
||||||
|
return this._orthogonalSize
|
||||||
|
}
|
||||||
|
|
||||||
|
public set minimumSize(size: number) {
|
||||||
|
this._minimumSize = size
|
||||||
|
this._onDidChange.fire(undefined)
|
||||||
|
}
|
||||||
|
|
||||||
|
public set maximumSize(size: number) {
|
||||||
|
this._maximumSize = size
|
||||||
|
this._onDidChange.fire(undefined)
|
||||||
|
}
|
||||||
|
|
||||||
|
public setExpanded(expanded: boolean) {
|
||||||
|
this._isExpanded = expanded
|
||||||
|
|
||||||
|
if (expanded) {
|
||||||
|
if (this.animationTimer) {
|
||||||
|
clearTimeout(this.animationTimer)
|
||||||
|
}
|
||||||
|
this.element.appendChild(this.body)
|
||||||
|
} else {
|
||||||
|
this.animationTimer = setTimeout(() => {
|
||||||
|
this.body.remove()
|
||||||
|
}, 200)
|
||||||
|
}
|
||||||
|
|
||||||
|
this._onDidChangeExpansionState.fire(expanded)
|
||||||
|
this._onDidChange.fire(expanded ? this.expandedSize : undefined)
|
||||||
|
}
|
||||||
|
|
||||||
|
public set orientation(orientation: Orientation) {
|
||||||
|
this._orientation = orientation
|
||||||
|
}
|
||||||
|
|
||||||
|
public set orthogonalSize(size: number) {
|
||||||
|
this._orthogonalSize = size
|
||||||
|
}
|
||||||
|
|
||||||
|
public layout(size: number, orthogonalSize: number) {
|
||||||
|
if (this.isExpanded()) {
|
||||||
|
this.expandedSize = size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public render() {
|
||||||
|
this.header = document.createElement('div')
|
||||||
|
this.header.className = 'pane-header'
|
||||||
|
this.header.style.height = `${this.headerSize}px`
|
||||||
|
this.header.style.lineHeight = `${this.headerSize}px`
|
||||||
|
this.element.appendChild(this.header)
|
||||||
|
this.renderHeader(this.header)
|
||||||
|
|
||||||
|
// this.updateHeader();
|
||||||
|
|
||||||
|
this.body = document.createElement('div')
|
||||||
|
this.body.className = 'pane-body'
|
||||||
|
this.element.appendChild(this.body)
|
||||||
|
this.renderBody(this.body)
|
||||||
|
|
||||||
|
// if (!this.isExpanded()) {
|
||||||
|
// this.body.remove();
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
// protected updateHeader(): void {
|
||||||
|
// const expanded = this.isExpanded();
|
||||||
|
|
||||||
|
// this.header.style.height = `${this.headerSize}px`;
|
||||||
|
// this.header.style.lineHeight = `${this.headerSize}px`;
|
||||||
|
// toggleClass(this.header, "hidden", !this.headerVisible);
|
||||||
|
// toggleClass(this.header, "expanded", expanded);
|
||||||
|
// this.header.setAttribute("aria-expanded", String(expanded));
|
||||||
|
|
||||||
|
// this.header.style.color = this.styles.headerForeground
|
||||||
|
// ? this.styles.headerForeground.toString()
|
||||||
|
// : "";
|
||||||
|
// this.header.style.backgroundColor = this.styles.headerBackground
|
||||||
|
// ? this.styles.headerBackground.toString()
|
||||||
|
// : "";
|
||||||
|
// this.header.style.borderTop =
|
||||||
|
// this.styles.headerBorder && this.orientation === Orientation.VERTICAL
|
||||||
|
// ? `1px solid ${this.styles.headerBorder}`
|
||||||
|
// : "";
|
||||||
|
// this._dropBackground = this.styles.dropBackground;
|
||||||
// }
|
// }
|
||||||
}
|
|
||||||
|
|
||||||
// protected updateHeader(): void {
|
protected abstract renderHeader(container: HTMLElement): void
|
||||||
// const expanded = this.isExpanded();
|
protected abstract renderBody(container: HTMLElement): void
|
||||||
|
|
||||||
// this.header.style.height = `${this.headerSize}px`;
|
|
||||||
// this.header.style.lineHeight = `${this.headerSize}px`;
|
|
||||||
// toggleClass(this.header, "hidden", !this.headerVisible);
|
|
||||||
// toggleClass(this.header, "expanded", expanded);
|
|
||||||
// this.header.setAttribute("aria-expanded", String(expanded));
|
|
||||||
|
|
||||||
// this.header.style.color = this.styles.headerForeground
|
|
||||||
// ? this.styles.headerForeground.toString()
|
|
||||||
// : "";
|
|
||||||
// this.header.style.backgroundColor = this.styles.headerBackground
|
|
||||||
// ? this.styles.headerBackground.toString()
|
|
||||||
// : "";
|
|
||||||
// this.header.style.borderTop =
|
|
||||||
// this.styles.headerBorder && this.orientation === Orientation.VERTICAL
|
|
||||||
// ? `1px solid ${this.styles.headerBorder}`
|
|
||||||
// : "";
|
|
||||||
// this._dropBackground = this.styles.dropBackground;
|
|
||||||
// }
|
|
||||||
|
|
||||||
protected abstract renderHeader(container: HTMLElement): void;
|
|
||||||
protected abstract renderBody(container: HTMLElement): void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface PaneItem {
|
interface PaneItem {
|
||||||
pane: Pane;
|
pane: Pane
|
||||||
disposable: IDisposable;
|
disposable: IDisposable
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PaneView implements IDisposable {
|
export class PaneView implements IDisposable {
|
||||||
private element: HTMLElement;
|
private element: HTMLElement
|
||||||
private splitview: SplitView;
|
private splitview: SplitView
|
||||||
private paneItems: PaneItem[] = [];
|
private paneItems: PaneItem[] = []
|
||||||
private _orientation: Orientation;
|
private _orientation: Orientation
|
||||||
private animationTimer: NodeJS.Timeout;
|
private animationTimer: NodeJS.Timeout
|
||||||
private orthogonalSize: number;
|
private orthogonalSize: number
|
||||||
private size: number;
|
private size: number
|
||||||
|
|
||||||
constructor(container: HTMLElement, options: { orientation: Orientation }) {
|
constructor(container: HTMLElement, options: { orientation: Orientation }) {
|
||||||
this._orientation = options.orientation ?? Orientation.VERTICAL;
|
this._orientation = options.orientation ?? Orientation.VERTICAL
|
||||||
|
|
||||||
this.element = document.createElement("div");
|
this.element = document.createElement('div')
|
||||||
this.element.className = "pane-container";
|
this.element.className = 'pane-container'
|
||||||
|
|
||||||
this.setupAnimation = this.setupAnimation.bind(this);
|
this.setupAnimation = this.setupAnimation.bind(this)
|
||||||
|
|
||||||
container.appendChild(this.element);
|
container.appendChild(this.element)
|
||||||
this.splitview = new SplitView(this.element, {
|
this.splitview = new SplitView(this.element, {
|
||||||
orientation: this._orientation,
|
orientation: this._orientation,
|
||||||
});
|
})
|
||||||
}
|
|
||||||
|
|
||||||
public setOrientation(orientation: Orientation) {
|
|
||||||
this._orientation = orientation;
|
|
||||||
}
|
|
||||||
|
|
||||||
public addPane(pane: Pane, size?: number, index = this.splitview.length) {
|
|
||||||
const disposable = pane.onDidChangeExpansionState(this.setupAnimation);
|
|
||||||
|
|
||||||
const paneItem: PaneItem = {
|
|
||||||
pane,
|
|
||||||
disposable: {
|
|
||||||
dispose: () => {
|
|
||||||
disposable.dispose();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
this.paneItems.splice(index, 0, paneItem);
|
|
||||||
pane.orientation = this._orientation;
|
|
||||||
pane.orthogonalSize = this.orthogonalSize;
|
|
||||||
this.splitview.addView(pane, size, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
public getPanes() {
|
|
||||||
return this.splitview.getViews() as Pane[];
|
|
||||||
}
|
|
||||||
|
|
||||||
public removePane(index: number) {
|
|
||||||
this.splitview.removeView(index);
|
|
||||||
const paneItem = this.paneItems.splice(index, 1)[0];
|
|
||||||
paneItem.disposable.dispose();
|
|
||||||
return paneItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
public moveView(from: number, to: number) {
|
|
||||||
const view = this.removePane(from);
|
|
||||||
this.addPane(view.pane, to);
|
|
||||||
}
|
|
||||||
|
|
||||||
public layout(size: number, orthogonalSize: number): void {
|
|
||||||
this.orthogonalSize = orthogonalSize;
|
|
||||||
this.size = size;
|
|
||||||
|
|
||||||
for (const paneItem of this.paneItems) {
|
|
||||||
paneItem.pane.orthogonalSize = this.orthogonalSize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.splitview.layout(this.size, this.orthogonalSize);
|
public setOrientation(orientation: Orientation) {
|
||||||
}
|
this._orientation = orientation
|
||||||
|
|
||||||
private setupAnimation() {
|
|
||||||
if (this.animationTimer) {
|
|
||||||
clearTimeout(this.animationTimer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addClasses(this.element, "animated");
|
public addPane(pane: Pane, size?: number, index = this.splitview.length) {
|
||||||
|
const disposable = pane.onDidChangeExpansionState(this.setupAnimation)
|
||||||
|
|
||||||
this.animationTimer = setTimeout(() => {
|
const paneItem: PaneItem = {
|
||||||
this.animationTimer = undefined;
|
pane,
|
||||||
removeClasses(this.element, "animated");
|
disposable: {
|
||||||
}, 200);
|
dispose: () => {
|
||||||
}
|
disposable.dispose()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
public dispose() {
|
this.paneItems.splice(index, 0, paneItem)
|
||||||
this.paneItems.forEach((paneItem) => {
|
pane.orientation = this._orientation
|
||||||
paneItem.disposable.dispose();
|
pane.orthogonalSize = this.orthogonalSize
|
||||||
});
|
this.splitview.addView(pane, size, index)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getPanes() {
|
||||||
|
return this.splitview.getViews() as Pane[]
|
||||||
|
}
|
||||||
|
|
||||||
|
public removePane(index: number) {
|
||||||
|
this.splitview.removeView(index)
|
||||||
|
const paneItem = this.paneItems.splice(index, 1)[0]
|
||||||
|
paneItem.disposable.dispose()
|
||||||
|
return paneItem
|
||||||
|
}
|
||||||
|
|
||||||
|
public moveView(from: number, to: number) {
|
||||||
|
const view = this.removePane(from)
|
||||||
|
this.addPane(view.pane, to)
|
||||||
|
}
|
||||||
|
|
||||||
|
public layout(size: number, orthogonalSize: number): void {
|
||||||
|
this.orthogonalSize = orthogonalSize
|
||||||
|
this.size = size
|
||||||
|
|
||||||
|
for (const paneItem of this.paneItems) {
|
||||||
|
paneItem.pane.orthogonalSize = this.orthogonalSize
|
||||||
|
}
|
||||||
|
|
||||||
|
this.splitview.layout(this.size, this.orthogonalSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
private setupAnimation() {
|
||||||
|
if (this.animationTimer) {
|
||||||
|
clearTimeout(this.animationTimer)
|
||||||
|
}
|
||||||
|
|
||||||
|
addClasses(this.element, 'animated')
|
||||||
|
|
||||||
|
this.animationTimer = setTimeout(() => {
|
||||||
|
this.animationTimer = undefined
|
||||||
|
removeClasses(this.element, 'animated')
|
||||||
|
}, 200)
|
||||||
|
}
|
||||||
|
|
||||||
|
public dispose() {
|
||||||
|
this.paneItems.forEach((paneItem) => {
|
||||||
|
paneItem.disposable.dispose()
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,48 +1,48 @@
|
|||||||
import { IGroupPanel } from "../groupview/panel/types";
|
import { IGroupPanel } from '../groupview/panel/types'
|
||||||
import { Layout } from "../layout/layout";
|
import { Layout } from '../layout/layout'
|
||||||
import { DefaultPanel } from "../groupview/panel/panel";
|
import { DefaultPanel } from '../groupview/panel/panel'
|
||||||
import { PanelContentPart, PanelHeaderPart } from "../groupview/panel/parts";
|
import { PanelContentPart, PanelHeaderPart } from '../groupview/panel/parts'
|
||||||
import { IPanelDeserializer } from "../layout/deserializer";
|
import { IPanelDeserializer } from '../layout/deserializer'
|
||||||
import {
|
import {
|
||||||
createContentComponent,
|
createContentComponent,
|
||||||
createTabComponent,
|
createTabComponent,
|
||||||
} from "../layout/componentFactory";
|
} from '../layout/componentFactory'
|
||||||
|
|
||||||
export class ReactPanelDeserialzier implements IPanelDeserializer {
|
export class ReactPanelDeserialzier implements IPanelDeserializer {
|
||||||
constructor(private readonly layout: Layout) {}
|
constructor(private readonly layout: Layout) {}
|
||||||
|
|
||||||
public fromJSON(panelData: { [index: string]: any }): IGroupPanel {
|
public fromJSON(panelData: { [index: string]: any }): IGroupPanel {
|
||||||
const panelId = panelData.id;
|
const panelId = panelData.id
|
||||||
const content = panelData.content;
|
const content = panelData.content
|
||||||
const tab = panelData.tab;
|
const tab = panelData.tab
|
||||||
const props = panelData.props;
|
const props = panelData.props
|
||||||
const title = panelData.title;
|
const title = panelData.title
|
||||||
const state = panelData.state;
|
const state = panelData.state
|
||||||
const suppressClosable = panelData.suppressClosable;
|
const suppressClosable = panelData.suppressClosable
|
||||||
|
|
||||||
const contentPart = createContentComponent(
|
const contentPart = createContentComponent(
|
||||||
content.id,
|
content.id,
|
||||||
this.layout.options.components,
|
this.layout.options.components,
|
||||||
this.layout.options.frameworkComponents,
|
this.layout.options.frameworkComponents,
|
||||||
this.layout.options.frameworkComponentFactory.content
|
this.layout.options.frameworkComponentFactory.content
|
||||||
) as PanelContentPart;
|
) as PanelContentPart
|
||||||
|
|
||||||
const headerPart = createTabComponent(
|
const headerPart = createTabComponent(
|
||||||
tab.id,
|
tab.id,
|
||||||
this.layout.options.tabComponents,
|
this.layout.options.tabComponents,
|
||||||
this.layout.options.frameworkComponentFactory,
|
this.layout.options.frameworkComponentFactory,
|
||||||
this.layout.options.frameworkComponentFactory.tab
|
this.layout.options.frameworkComponentFactory.tab
|
||||||
) as PanelHeaderPart;
|
) as PanelHeaderPart
|
||||||
|
|
||||||
const panel = new DefaultPanel(panelId, headerPart, contentPart);
|
const panel = new DefaultPanel(panelId, headerPart, contentPart)
|
||||||
|
|
||||||
panel.init({
|
panel.init({
|
||||||
title,
|
title,
|
||||||
suppressClosable,
|
suppressClosable,
|
||||||
params: props || {},
|
params: props || {},
|
||||||
state: state || {},
|
state: state || {},
|
||||||
});
|
})
|
||||||
|
|
||||||
return panel;
|
return panel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,67 +1,71 @@
|
|||||||
import * as React from "react";
|
import * as React from 'react'
|
||||||
import {
|
import {
|
||||||
ComponentGridview,
|
ComponentGridview,
|
||||||
IComponentGridviewLayout,
|
IComponentGridviewLayout,
|
||||||
} from "../layout/componentGridview";
|
} from '../layout/componentGridview'
|
||||||
import { IGridApi } from "../panel/api";
|
import { IGridApi } from '../panel/api'
|
||||||
import { Orientation } from "../splitview/splitview";
|
import { Orientation } from '../splitview/splitview'
|
||||||
import { ReactComponentGridView } from "./reactComponentGridView";
|
import { ReactComponentGridView } from './reactComponentGridView'
|
||||||
|
|
||||||
export interface GridviewReadyEvent {
|
export interface GridviewReadyEvent {
|
||||||
api: IComponentGridviewLayout;
|
api: IComponentGridviewLayout
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IGridviewPanelProps {
|
export interface IGridviewPanelProps {
|
||||||
api: IGridApi;
|
api: IGridApi
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IGridviewComponentProps {
|
export interface IGridviewComponentProps {
|
||||||
orientation: Orientation;
|
orientation: Orientation
|
||||||
onReady?: (event: GridviewReadyEvent) => void;
|
onReady?: (event: GridviewReadyEvent) => void
|
||||||
components: {
|
components: {
|
||||||
[index: string]: React.FunctionComponent<IGridviewPanelProps>;
|
[index: string]: React.FunctionComponent<IGridviewPanelProps>
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const GridviewComponent = (props: IGridviewComponentProps) => {
|
export const GridviewComponent = (props: IGridviewComponentProps) => {
|
||||||
const domReference = React.useRef<HTMLDivElement>();
|
const domReference = React.useRef<HTMLDivElement>()
|
||||||
const gridview = React.useRef<IComponentGridviewLayout>();
|
const gridview = React.useRef<IComponentGridviewLayout>()
|
||||||
const [portals, setPortals] = React.useState<React.ReactPortal[]>([]);
|
const [portals, setPortals] = React.useState<React.ReactPortal[]>([])
|
||||||
|
|
||||||
const addPortal = React.useCallback((p: React.ReactPortal) => {
|
const addPortal = React.useCallback((p: React.ReactPortal) => {
|
||||||
setPortals((portals) => [...portals, p]);
|
setPortals((portals) => [...portals, p])
|
||||||
return {
|
return {
|
||||||
dispose: () => {
|
dispose: () => {
|
||||||
setPortals((portals) => portals.filter((portal) => portal !== p));
|
setPortals((portals) =>
|
||||||
},
|
portals.filter((portal) => portal !== p)
|
||||||
};
|
)
|
||||||
}, []);
|
},
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
gridview.current = new ComponentGridview(domReference.current, {
|
gridview.current = new ComponentGridview(domReference.current, {
|
||||||
orientation: props.orientation,
|
orientation: props.orientation,
|
||||||
frameworkComponents: props.components,
|
frameworkComponents: props.components,
|
||||||
frameworkComponentFactory: {
|
frameworkComponentFactory: {
|
||||||
createComponent: (id: string, component: any) => {
|
createComponent: (id: string, component: any) => {
|
||||||
return new ReactComponentGridView(id, id, component, { addPortal });
|
return new ReactComponentGridView(id, id, component, {
|
||||||
},
|
addPortal,
|
||||||
},
|
})
|
||||||
});
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
if (props.onReady) {
|
if (props.onReady) {
|
||||||
props.onReady({ api: gridview.current });
|
props.onReady({ api: gridview.current })
|
||||||
}
|
}
|
||||||
}, []);
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
height: "100%",
|
height: '100%',
|
||||||
width: "100%",
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
ref={domReference}
|
ref={domReference}
|
||||||
>
|
>
|
||||||
{portals}
|
{portals}
|
||||||
</div>
|
</div>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
@ -1,134 +1,142 @@
|
|||||||
import * as React from "react";
|
import * as React from 'react'
|
||||||
import { IDisposable } from "../lifecycle";
|
import { IDisposable } from '../lifecycle'
|
||||||
import { Layout, Api } from "../layout/layout";
|
import { Layout, Api } from '../layout/layout'
|
||||||
import { ReactPanelContentPart } from "./reactContentPart";
|
import { ReactPanelContentPart } from './reactContentPart'
|
||||||
import { ReactPanelHeaderPart } from "./reactHeaderPart";
|
import { ReactPanelHeaderPart } from './reactHeaderPart'
|
||||||
import { IPanelProps } from "./react";
|
import { IPanelProps } from './react'
|
||||||
import { ReactPanelDeserialzier } from "./deserializer";
|
import { ReactPanelDeserialzier } from './deserializer'
|
||||||
import { GroupPanelFrameworkComponentFactory, TabContextMenuEvent } from "../layout/options";
|
import {
|
||||||
|
GroupPanelFrameworkComponentFactory,
|
||||||
|
TabContextMenuEvent,
|
||||||
|
} from '../layout/options'
|
||||||
|
|
||||||
export interface OnReadyEvent {
|
export interface OnReadyEvent {
|
||||||
api: Api;
|
api: Api
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ReactLayout {
|
export interface ReactLayout {
|
||||||
addPortal: (portal: React.ReactPortal) => IDisposable;
|
addPortal: (portal: React.ReactPortal) => IDisposable
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IReactGridProps {
|
export interface IReactGridProps {
|
||||||
components?: {
|
components?: {
|
||||||
[componentName: string]: React.FunctionComponent<IPanelProps>;
|
[componentName: string]: React.FunctionComponent<IPanelProps>
|
||||||
};
|
}
|
||||||
tabComponents?: {
|
tabComponents?: {
|
||||||
[componentName: string]: React.FunctionComponent<IPanelProps>;
|
[componentName: string]: React.FunctionComponent<IPanelProps>
|
||||||
};
|
}
|
||||||
watermarkComponent?: React.FunctionComponent;
|
watermarkComponent?: React.FunctionComponent
|
||||||
onReady?: (event: OnReadyEvent) => void;
|
onReady?: (event: OnReadyEvent) => void
|
||||||
autoSizeToFitContainer?: boolean;
|
autoSizeToFitContainer?: boolean
|
||||||
serializedLayout?: {};
|
serializedLayout?: {}
|
||||||
deserializer?: {
|
deserializer?: {
|
||||||
fromJSON: (
|
fromJSON: (
|
||||||
data: any
|
data: any
|
||||||
) => {
|
) => {
|
||||||
component: React.FunctionComponent<IPanelProps>;
|
component: React.FunctionComponent<IPanelProps>
|
||||||
tabComponent?: React.FunctionComponent<IPanelProps>;
|
tabComponent?: React.FunctionComponent<IPanelProps>
|
||||||
props?: { [key: string]: any };
|
props?: { [key: string]: any }
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
debug?: boolean;
|
debug?: boolean
|
||||||
tabHeight?: number;
|
tabHeight?: number
|
||||||
enableExternalDragEvents?: boolean;
|
enableExternalDragEvents?: boolean
|
||||||
onTabContextMenu?: (event: TabContextMenuEvent) => void;
|
onTabContextMenu?: (event: TabContextMenuEvent) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ReactGrid = (props: IReactGridProps) => {
|
export const ReactGrid = (props: IReactGridProps) => {
|
||||||
const domReference = React.useRef<HTMLDivElement>();
|
const domReference = React.useRef<HTMLDivElement>()
|
||||||
const layoutReference = React.useRef<Layout>();
|
const layoutReference = React.useRef<Layout>()
|
||||||
|
|
||||||
const [portals, setPortals] = React.useState<React.ReactPortal[]>([]);
|
const [portals, setPortals] = React.useState<React.ReactPortal[]>([])
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
const addPortal = (p: React.ReactPortal) => {
|
const addPortal = (p: React.ReactPortal) => {
|
||||||
setPortals((portals) => [...portals, p]);
|
setPortals((portals) => [...portals, p])
|
||||||
return {
|
return {
|
||||||
dispose: () => {
|
dispose: () => {
|
||||||
setPortals((portals) => portals.filter((portal) => portal !== p));
|
setPortals((portals) =>
|
||||||
},
|
portals.filter((portal) => portal !== p)
|
||||||
};
|
)
|
||||||
};
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const factory: GroupPanelFrameworkComponentFactory = {
|
const factory: GroupPanelFrameworkComponentFactory = {
|
||||||
content: {
|
content: {
|
||||||
createComponent: (
|
createComponent: (
|
||||||
id: string,
|
id: string,
|
||||||
component: React.FunctionComponent<IPanelProps>
|
component: React.FunctionComponent<IPanelProps>
|
||||||
) => {
|
) => {
|
||||||
return new ReactPanelContentPart(id, component, { addPortal });
|
return new ReactPanelContentPart(id, component, {
|
||||||
},
|
addPortal,
|
||||||
},
|
})
|
||||||
tab: {
|
},
|
||||||
createComponent: (
|
},
|
||||||
id: string,
|
tab: {
|
||||||
component: React.FunctionComponent<IPanelProps>
|
createComponent: (
|
||||||
) => {
|
id: string,
|
||||||
return new ReactPanelHeaderPart(id, component, { addPortal });
|
component: React.FunctionComponent<IPanelProps>
|
||||||
},
|
) => {
|
||||||
},
|
return new ReactPanelHeaderPart(id, component, {
|
||||||
};
|
addPortal,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
const layout = new Layout({
|
const layout = new Layout({
|
||||||
frameworkComponentFactory: factory,
|
frameworkComponentFactory: factory,
|
||||||
frameworkComponents: props.components,
|
frameworkComponents: props.components,
|
||||||
frameworkTabComponents: props.tabComponents,
|
frameworkTabComponents: props.tabComponents,
|
||||||
tabHeight: props.tabHeight,
|
tabHeight: props.tabHeight,
|
||||||
debug: props.debug,
|
debug: props.debug,
|
||||||
enableExternalDragEvents: props.enableExternalDragEvents,
|
enableExternalDragEvents: props.enableExternalDragEvents,
|
||||||
});
|
})
|
||||||
|
|
||||||
layoutReference.current = layout;
|
layoutReference.current = layout
|
||||||
domReference.current.appendChild(layoutReference.current.element);
|
domReference.current.appendChild(layoutReference.current.element)
|
||||||
|
|
||||||
layout.deserializer = new ReactPanelDeserialzier(layout);
|
layout.deserializer = new ReactPanelDeserialzier(layout)
|
||||||
|
|
||||||
|
layout.resizeToFit()
|
||||||
|
|
||||||
layout.resizeToFit();
|
if (props.serializedLayout) {
|
||||||
|
layout.deserialize(props.serializedLayout)
|
||||||
|
}
|
||||||
|
|
||||||
if (props.serializedLayout) {
|
if (props.onReady) {
|
||||||
layout.deserialize(props.serializedLayout);
|
props.onReady({ api: layout })
|
||||||
}
|
}
|
||||||
|
|
||||||
if (props.onReady) {
|
return () => {
|
||||||
props.onReady({ api: layout });
|
layout.dispose()
|
||||||
}
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
return () => {
|
React.useEffect(() => {
|
||||||
layout.dispose();
|
const disposable = layoutReference.current.onTabContextMenu((event) => {
|
||||||
};
|
props.onTabContextMenu(event)
|
||||||
}, []);
|
})
|
||||||
|
|
||||||
React.useEffect(() => {
|
return () => {
|
||||||
const disposable = layoutReference.current.onTabContextMenu((event) => {
|
disposable.dispose()
|
||||||
props.onTabContextMenu(event);
|
}
|
||||||
});
|
}, [props.onTabContextMenu])
|
||||||
|
|
||||||
return () => {
|
React.useEffect(() => {
|
||||||
disposable.dispose()
|
layoutReference.current.setAutoResizeToFit(props.autoSizeToFitContainer)
|
||||||
}
|
}, [props.autoSizeToFitContainer])
|
||||||
}, [props.onTabContextMenu])
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
return (
|
||||||
layoutReference.current.setAutoResizeToFit(props.autoSizeToFitContainer);
|
<div
|
||||||
}, [props.autoSizeToFitContainer]);
|
style={{
|
||||||
|
// height: "100%",
|
||||||
return (
|
width: '100%',
|
||||||
<div
|
}}
|
||||||
style={{
|
ref={domReference}
|
||||||
// height: "100%",
|
>
|
||||||
width: "100%",
|
{portals}
|
||||||
}}
|
</div>
|
||||||
ref={domReference}
|
)
|
||||||
>
|
}
|
||||||
{portals}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
@ -1,103 +1,112 @@
|
|||||||
import * as React from "react";
|
import * as React from 'react'
|
||||||
import * as ReactDOM from "react-dom";
|
import * as ReactDOM from 'react-dom'
|
||||||
import { IDisposable } from "../lifecycle";
|
import { IDisposable } from '../lifecycle'
|
||||||
import { IGroupPanelApi } from "../groupview/panel/api";
|
import { IGroupPanelApi } from '../groupview/panel/api'
|
||||||
import { sequentialNumberGenerator } from "../math";
|
import { sequentialNumberGenerator } from '../math'
|
||||||
import { IBaseViewApi } from "../panel/api";
|
import { IBaseViewApi } from '../panel/api'
|
||||||
|
|
||||||
export interface IPanelProps {
|
export interface IPanelProps {
|
||||||
api: IGroupPanelApi;
|
api: IGroupPanelApi
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IPanelWrapperProps {
|
interface IPanelWrapperProps {
|
||||||
component: React.FunctionComponent<IPanelProps>;
|
component: React.FunctionComponent<IPanelProps>
|
||||||
componentProps: any;
|
componentProps: any
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IPanelWrapperRef {
|
interface IPanelWrapperRef {
|
||||||
update: (props: { [key: string]: any }) => void;
|
update: (props: { [key: string]: any }) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const PanelWrapper = React.forwardRef(
|
const PanelWrapper = React.forwardRef(
|
||||||
(props: IPanelWrapperProps, ref: React.RefObject<IPanelWrapperRef>) => {
|
(props: IPanelWrapperProps, ref: React.RefObject<IPanelWrapperRef>) => {
|
||||||
const [_, triggerRender] = React.useState<number>();
|
const [_, triggerRender] = React.useState<number>()
|
||||||
const _props = React.useRef<{ [key: string]: any }>(props.componentProps);
|
const _props = React.useRef<{ [key: string]: any }>(
|
||||||
|
props.componentProps
|
||||||
|
)
|
||||||
|
|
||||||
React.useImperativeHandle(
|
React.useImperativeHandle(
|
||||||
ref,
|
ref,
|
||||||
() => ({
|
() => ({
|
||||||
update: (props: { [key: string]: any }) => {
|
update: (props: { [key: string]: any }) => {
|
||||||
_props.current = { ..._props.current, ...props };
|
_props.current = { ..._props.current, ...props }
|
||||||
triggerRender(Date.now());
|
triggerRender(Date.now())
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
[]
|
[]
|
||||||
);
|
)
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
console.debug("[reactwrapper] component mounted ");
|
console.debug('[reactwrapper] component mounted ')
|
||||||
return () => {
|
return () => {
|
||||||
console.debug("[reactwrapper] component unmounted ");
|
console.debug('[reactwrapper] component unmounted ')
|
||||||
};
|
}
|
||||||
}, []);
|
}, [])
|
||||||
|
|
||||||
return React.createElement(props.component, _props.current as IPanelProps);
|
return React.createElement(
|
||||||
}
|
props.component,
|
||||||
);
|
_props.current as IPanelProps
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
const counter = sequentialNumberGenerator();
|
const counter = sequentialNumberGenerator()
|
||||||
|
|
||||||
export class ReactPart implements IDisposable {
|
export class ReactPart implements IDisposable {
|
||||||
private componentInstance: IPanelWrapperRef;
|
private componentInstance: IPanelWrapperRef
|
||||||
private ref: { portal: React.ReactPortal; disposable: IDisposable };
|
private ref: { portal: React.ReactPortal; disposable: IDisposable }
|
||||||
private disposed: boolean;
|
private disposed: boolean
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly parent: HTMLElement,
|
private readonly parent: HTMLElement,
|
||||||
private readonly api: IBaseViewApi,
|
private readonly api: IBaseViewApi,
|
||||||
private readonly addPortal: (portal: React.ReactPortal) => IDisposable,
|
private readonly addPortal: (portal: React.ReactPortal) => IDisposable,
|
||||||
private readonly component: React.FunctionComponent<{}>,
|
private readonly component: React.FunctionComponent<{}>,
|
||||||
private readonly parameters: { [key: string]: any }
|
private readonly parameters: { [key: string]: any }
|
||||||
) {
|
) {
|
||||||
this.createPortal();
|
this.createPortal()
|
||||||
}
|
|
||||||
|
|
||||||
public update(props: {}) {
|
|
||||||
if (this.disposed) {
|
|
||||||
throw new Error("invalid operation");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.componentInstance?.update(props);
|
public update(props: {}) {
|
||||||
}
|
if (this.disposed) {
|
||||||
|
throw new Error('invalid operation')
|
||||||
|
}
|
||||||
|
|
||||||
private createPortal() {
|
this.componentInstance?.update(props)
|
||||||
if (this.disposed) {
|
|
||||||
throw new Error("invalid operation");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let props = {
|
private createPortal() {
|
||||||
api: this.api,
|
if (this.disposed) {
|
||||||
...this.parameters,
|
throw new Error('invalid operation')
|
||||||
} as any;
|
}
|
||||||
|
|
||||||
const wrapper = React.createElement(PanelWrapper, {
|
let props = {
|
||||||
component: this.component,
|
api: this.api,
|
||||||
componentProps: props,
|
...this.parameters,
|
||||||
ref: (element: any) => {
|
} as any
|
||||||
this.componentInstance = element;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const portal = ReactDOM.createPortal(wrapper, this.parent, counter.next());
|
|
||||||
|
|
||||||
this.ref = {
|
const wrapper = React.createElement(PanelWrapper, {
|
||||||
portal,
|
component: this.component,
|
||||||
disposable: this.addPortal(portal),
|
componentProps: props,
|
||||||
};
|
ref: (element: any) => {
|
||||||
}
|
this.componentInstance = element
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const portal = ReactDOM.createPortal(
|
||||||
|
wrapper,
|
||||||
|
this.parent,
|
||||||
|
counter.next()
|
||||||
|
)
|
||||||
|
|
||||||
public dispose() {
|
this.ref = {
|
||||||
this.ref?.disposable?.dispose();
|
portal,
|
||||||
this.ref = undefined;
|
disposable: this.addPortal(portal),
|
||||||
this.disposed = true;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public dispose() {
|
||||||
|
this.ref?.disposable?.dispose()
|
||||||
|
this.ref = undefined
|
||||||
|
this.disposed = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,142 +1,144 @@
|
|||||||
import { trackFocus } from "../dom";
|
import { trackFocus } from '../dom'
|
||||||
import { Emitter } from "../events";
|
import { Emitter } from '../events'
|
||||||
import { GridApi } from "../panel/api";
|
import { GridApi } from '../panel/api'
|
||||||
import { CompositeDisposable } from "../lifecycle";
|
import { CompositeDisposable } from '../lifecycle'
|
||||||
import { ReactLayout } from "./layout";
|
import { ReactLayout } from './layout'
|
||||||
import { ReactPart } from "./react";
|
import { ReactPart } from './react'
|
||||||
import { ISplitviewPanelProps } from "./splitview";
|
import { ISplitviewPanelProps } from './splitview'
|
||||||
import { PanelUpdateEvent, InitParameters, IPanel } from "../panel/types";
|
import { PanelUpdateEvent, InitParameters, IPanel } from '../panel/types'
|
||||||
import { IComponentGridview } from "../layout/componentGridview";
|
import { IComponentGridview } from '../layout/componentGridview'
|
||||||
import { FunctionOrValue } from "../types";
|
import { FunctionOrValue } from '../types'
|
||||||
|
|
||||||
export class ReactComponentGridView
|
export class ReactComponentGridView
|
||||||
extends CompositeDisposable
|
extends CompositeDisposable
|
||||||
implements IComponentGridview, IPanel {
|
implements IComponentGridview, IPanel {
|
||||||
private _element: HTMLElement;
|
private _element: HTMLElement
|
||||||
private part: ReactPart;
|
private part: ReactPart
|
||||||
private params: { params: any };
|
private params: { params: any }
|
||||||
private api: GridApi;
|
private api: GridApi
|
||||||
|
|
||||||
private _onDidChange: Emitter<number | undefined> = new Emitter<
|
private _onDidChange: Emitter<number | undefined> = new Emitter<
|
||||||
number | undefined
|
number | undefined
|
||||||
>();
|
>()
|
||||||
public onDidChange = this._onDidChange.event;
|
public onDidChange = this._onDidChange.event
|
||||||
|
|
||||||
get element() {
|
get element() {
|
||||||
return this._element;
|
return this._element
|
||||||
}
|
|
||||||
|
|
||||||
private _minimumWidth: FunctionOrValue<number> = 200;
|
|
||||||
private _minimumHeight: FunctionOrValue<number> = 200;
|
|
||||||
private _maximumWidth: FunctionOrValue<number> = Number.MAX_SAFE_INTEGER;
|
|
||||||
private _maximumHeight: FunctionOrValue<number> = Number.MAX_SAFE_INTEGER;
|
|
||||||
|
|
||||||
get minimumWidth() {
|
|
||||||
return typeof this._minimumWidth === "function"
|
|
||||||
? this._minimumWidth()
|
|
||||||
: this._minimumWidth;
|
|
||||||
}
|
|
||||||
get minimumHeight() {
|
|
||||||
return typeof this._minimumHeight === "function"
|
|
||||||
? this._minimumHeight()
|
|
||||||
: this._minimumHeight;
|
|
||||||
}
|
|
||||||
get maximumHeight() {
|
|
||||||
return typeof this._maximumHeight === "function"
|
|
||||||
? this._maximumHeight()
|
|
||||||
: this._maximumHeight;
|
|
||||||
}
|
|
||||||
get maximumWidth() {
|
|
||||||
return typeof this._maximumWidth === "function"
|
|
||||||
? this._maximumWidth()
|
|
||||||
: this._maximumWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
public readonly id: string,
|
|
||||||
private readonly componentName: string,
|
|
||||||
private readonly component: React.FunctionComponent<ISplitviewPanelProps>,
|
|
||||||
private readonly parent: ReactLayout
|
|
||||||
) {
|
|
||||||
super();
|
|
||||||
this.api = new GridApi();
|
|
||||||
if (!this.component) {
|
|
||||||
throw new Error("React.FunctionalComponent cannot be undefined");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this._element = document.createElement("div");
|
private _minimumWidth: FunctionOrValue<number> = 200
|
||||||
this._element.tabIndex = -1;
|
private _minimumHeight: FunctionOrValue<number> = 200
|
||||||
this._element.style.outline = "none";
|
private _maximumWidth: FunctionOrValue<number> = Number.MAX_SAFE_INTEGER
|
||||||
|
private _maximumHeight: FunctionOrValue<number> = Number.MAX_SAFE_INTEGER
|
||||||
|
|
||||||
const { onDidFocus, onDidBlur } = trackFocus(this._element);
|
get minimumWidth() {
|
||||||
|
return typeof this._minimumWidth === 'function'
|
||||||
|
? this._minimumWidth()
|
||||||
|
: this._minimumWidth
|
||||||
|
}
|
||||||
|
get minimumHeight() {
|
||||||
|
return typeof this._minimumHeight === 'function'
|
||||||
|
? this._minimumHeight()
|
||||||
|
: this._minimumHeight
|
||||||
|
}
|
||||||
|
get maximumHeight() {
|
||||||
|
return typeof this._maximumHeight === 'function'
|
||||||
|
? this._maximumHeight()
|
||||||
|
: this._maximumHeight
|
||||||
|
}
|
||||||
|
get maximumWidth() {
|
||||||
|
return typeof this._maximumWidth === 'function'
|
||||||
|
? this._maximumWidth()
|
||||||
|
: this._maximumWidth
|
||||||
|
}
|
||||||
|
|
||||||
this.addDisposables(
|
constructor(
|
||||||
this.api.onDidConstraintsChange((event) => {
|
public readonly id: string,
|
||||||
if (
|
private readonly componentName: string,
|
||||||
typeof event.minimumWidth === "number" ||
|
private readonly component: React.FunctionComponent<
|
||||||
typeof event.minimumWidth === "function"
|
ISplitviewPanelProps
|
||||||
) {
|
>,
|
||||||
this._minimumWidth = event.minimumWidth;
|
private readonly parent: ReactLayout
|
||||||
|
) {
|
||||||
|
super()
|
||||||
|
this.api = new GridApi()
|
||||||
|
if (!this.component) {
|
||||||
|
throw new Error('React.FunctionalComponent cannot be undefined')
|
||||||
}
|
}
|
||||||
if (
|
|
||||||
typeof event.minimumHeight === "number" ||
|
this._element = document.createElement('div')
|
||||||
typeof event.minimumHeight === "function"
|
this._element.tabIndex = -1
|
||||||
) {
|
this._element.style.outline = 'none'
|
||||||
this._minimumHeight = event.minimumHeight;
|
|
||||||
|
const { onDidFocus, onDidBlur } = trackFocus(this._element)
|
||||||
|
|
||||||
|
this.addDisposables(
|
||||||
|
this.api.onDidConstraintsChange((event) => {
|
||||||
|
if (
|
||||||
|
typeof event.minimumWidth === 'number' ||
|
||||||
|
typeof event.minimumWidth === 'function'
|
||||||
|
) {
|
||||||
|
this._minimumWidth = event.minimumWidth
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
typeof event.minimumHeight === 'number' ||
|
||||||
|
typeof event.minimumHeight === 'function'
|
||||||
|
) {
|
||||||
|
this._minimumHeight = event.minimumHeight
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
typeof event.maximumWidth === 'number' ||
|
||||||
|
typeof event.maximumWidth === 'function'
|
||||||
|
) {
|
||||||
|
this._maximumWidth = event.maximumWidth
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
typeof event.maximumHeight === 'number' ||
|
||||||
|
typeof event.maximumHeight === 'function'
|
||||||
|
) {
|
||||||
|
this._maximumHeight = event.maximumHeight
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
onDidFocus(() => {
|
||||||
|
this.api._onDidChangeFocus.fire({ isFocused: true })
|
||||||
|
}),
|
||||||
|
onDidBlur(() => {
|
||||||
|
this.api._onDidChangeFocus.fire({ isFocused: false })
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
layout(width: number, height: number) {
|
||||||
|
this.api._onDidPanelDimensionChange.fire({ width, height })
|
||||||
|
}
|
||||||
|
|
||||||
|
init(parameters: InitParameters): void {
|
||||||
|
this.params = parameters
|
||||||
|
this.part = new ReactPart(
|
||||||
|
this.element,
|
||||||
|
this.api,
|
||||||
|
this.parent.addPortal,
|
||||||
|
this.component,
|
||||||
|
parameters.params
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
update(params: PanelUpdateEvent) {
|
||||||
|
this.params = { ...this.params.params, ...params }
|
||||||
|
this.part.update(params)
|
||||||
|
}
|
||||||
|
|
||||||
|
toJSON(): object {
|
||||||
|
return {
|
||||||
|
id: this.id,
|
||||||
|
component: this.componentName,
|
||||||
|
props: this.params.params,
|
||||||
|
state: this.api.getState(),
|
||||||
}
|
}
|
||||||
if (
|
}
|
||||||
typeof event.maximumWidth === "number" ||
|
|
||||||
typeof event.maximumWidth === "function"
|
|
||||||
) {
|
|
||||||
this._maximumWidth = event.maximumWidth;
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
typeof event.maximumHeight === "number" ||
|
|
||||||
typeof event.maximumHeight === "function"
|
|
||||||
) {
|
|
||||||
this._maximumHeight = event.maximumHeight;
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
onDidFocus(() => {
|
|
||||||
this.api._onDidChangeFocus.fire({ isFocused: true });
|
|
||||||
}),
|
|
||||||
onDidBlur(() => {
|
|
||||||
this.api._onDidChangeFocus.fire({ isFocused: false });
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
layout(width: number, height: number) {
|
dispose() {
|
||||||
this.api._onDidPanelDimensionChange.fire({ width, height });
|
super.dispose()
|
||||||
}
|
this.api.dispose()
|
||||||
|
}
|
||||||
init(parameters: InitParameters): void {
|
|
||||||
this.params = parameters;
|
|
||||||
this.part = new ReactPart(
|
|
||||||
this.element,
|
|
||||||
this.api,
|
|
||||||
this.parent.addPortal,
|
|
||||||
this.component,
|
|
||||||
parameters.params
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
update(params: PanelUpdateEvent) {
|
|
||||||
this.params = { ...this.params.params, ...params };
|
|
||||||
this.part.update(params);
|
|
||||||
}
|
|
||||||
|
|
||||||
toJSON(): object {
|
|
||||||
return {
|
|
||||||
id: this.id,
|
|
||||||
component: this.componentName,
|
|
||||||
props: this.params.params,
|
|
||||||
state: this.api.getState(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
dispose() {
|
|
||||||
super.dispose();
|
|
||||||
this.api.dispose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,118 +1,120 @@
|
|||||||
import { trackFocus } from "../dom";
|
import { trackFocus } from '../dom'
|
||||||
import { Emitter } from "../events";
|
import { Emitter } from '../events'
|
||||||
import { PanelApi } from "../panel/api";
|
import { PanelApi } from '../panel/api'
|
||||||
import { PanelDimensionChangeEvent } from "../panel/types";
|
import { PanelDimensionChangeEvent } from '../panel/types'
|
||||||
import { CompositeDisposable } from "../lifecycle";
|
import { CompositeDisposable } from '../lifecycle'
|
||||||
import { IView } from "../splitview/splitview";
|
import { IView } from '../splitview/splitview'
|
||||||
import { ReactLayout } from "./layout";
|
import { ReactLayout } from './layout'
|
||||||
import { ReactPart } from "./react";
|
import { ReactPart } from './react'
|
||||||
import { ISplitviewPanelProps } from "./splitview";
|
import { ISplitviewPanelProps } from './splitview'
|
||||||
import { PanelUpdateEvent, InitParameters, IPanel } from "../panel/types";
|
import { PanelUpdateEvent, InitParameters, IPanel } from '../panel/types'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A no-thrills implementation of IView that renders a React component
|
* A no-thrills implementation of IView that renders a React component
|
||||||
*/
|
*/
|
||||||
export class ReactComponentView
|
export class ReactComponentView
|
||||||
extends CompositeDisposable
|
extends CompositeDisposable
|
||||||
implements IView, IPanel {
|
implements IView, IPanel {
|
||||||
private _element: HTMLElement;
|
private _element: HTMLElement
|
||||||
private part: ReactPart;
|
private part: ReactPart
|
||||||
private params: { params: any };
|
private params: { params: any }
|
||||||
private api: PanelApi;
|
private api: PanelApi
|
||||||
|
|
||||||
private _onDidChange: Emitter<number | undefined> = new Emitter<
|
private _onDidChange: Emitter<number | undefined> = new Emitter<
|
||||||
number | undefined
|
number | undefined
|
||||||
>();
|
>()
|
||||||
public onDidChange = this._onDidChange.event;
|
public onDidChange = this._onDidChange.event
|
||||||
|
|
||||||
get element() {
|
get element() {
|
||||||
return this._element;
|
return this._element
|
||||||
}
|
|
||||||
|
|
||||||
private _minimumSize: number = 200;
|
|
||||||
private _maximumSize: number = Number.MAX_SAFE_INTEGER;
|
|
||||||
private _snapSize: number;
|
|
||||||
|
|
||||||
get minimumSize() {
|
|
||||||
return this._minimumSize;
|
|
||||||
}
|
|
||||||
set minimumSize(value: number) {
|
|
||||||
this._minimumSize = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
get snapSize() {
|
|
||||||
return this._snapSize;
|
|
||||||
}
|
|
||||||
set snapSize(value: number) {
|
|
||||||
this._snapSize = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
get maximumSize() {
|
|
||||||
return this._maximumSize;
|
|
||||||
}
|
|
||||||
set maximumSize(value: number) {
|
|
||||||
this._maximumSize = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
public readonly id: string,
|
|
||||||
private readonly componentName: string,
|
|
||||||
private readonly component: React.FunctionComponent<ISplitviewPanelProps>,
|
|
||||||
private readonly parent: ReactLayout
|
|
||||||
) {
|
|
||||||
super();
|
|
||||||
this.api = new PanelApi();
|
|
||||||
if (!this.component) {
|
|
||||||
throw new Error("React.FunctionalComponent cannot be undefined");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this._element = document.createElement("div");
|
private _minimumSize: number = 200
|
||||||
this._element.tabIndex = -1;
|
private _maximumSize: number = Number.MAX_SAFE_INTEGER
|
||||||
this._element.style.outline = "none";
|
private _snapSize: number
|
||||||
|
|
||||||
const { onDidFocus, onDidBlur } = trackFocus(this._element);
|
get minimumSize() {
|
||||||
|
return this._minimumSize
|
||||||
|
}
|
||||||
|
set minimumSize(value: number) {
|
||||||
|
this._minimumSize = value
|
||||||
|
}
|
||||||
|
|
||||||
this.addDisposables(
|
get snapSize() {
|
||||||
onDidFocus(() => {
|
return this._snapSize
|
||||||
this.api._onDidChangeFocus.fire({ isFocused: true });
|
}
|
||||||
}),
|
set snapSize(value: number) {
|
||||||
onDidBlur(() => {
|
this._snapSize = value
|
||||||
this.api._onDidChangeFocus.fire({ isFocused: false });
|
}
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
layout(width: number, height: number) {
|
get maximumSize() {
|
||||||
this.api._onDidPanelDimensionChange.fire({ width, height });
|
return this._maximumSize
|
||||||
}
|
}
|
||||||
|
set maximumSize(value: number) {
|
||||||
|
this._maximumSize = value
|
||||||
|
}
|
||||||
|
|
||||||
init(parameters: InitParameters): void {
|
constructor(
|
||||||
this.params = parameters;
|
public readonly id: string,
|
||||||
this.part = new ReactPart(
|
private readonly componentName: string,
|
||||||
this.element,
|
private readonly component: React.FunctionComponent<
|
||||||
this.api,
|
ISplitviewPanelProps
|
||||||
this.parent.addPortal,
|
>,
|
||||||
this.component,
|
private readonly parent: ReactLayout
|
||||||
parameters.params
|
) {
|
||||||
);
|
super()
|
||||||
}
|
this.api = new PanelApi()
|
||||||
|
if (!this.component) {
|
||||||
|
throw new Error('React.FunctionalComponent cannot be undefined')
|
||||||
|
}
|
||||||
|
|
||||||
update(params: PanelUpdateEvent) {
|
this._element = document.createElement('div')
|
||||||
this.params = { ...this.params.params, ...params };
|
this._element.tabIndex = -1
|
||||||
this.part.update(params);
|
this._element.style.outline = 'none'
|
||||||
}
|
|
||||||
|
|
||||||
toJSON(): object {
|
const { onDidFocus, onDidBlur } = trackFocus(this._element)
|
||||||
return {
|
|
||||||
id: this.id,
|
|
||||||
component: this.componentName,
|
|
||||||
props: this.params.params,
|
|
||||||
state: this.api.getState(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
dispose() {
|
this.addDisposables(
|
||||||
super.dispose();
|
onDidFocus(() => {
|
||||||
this.api.dispose();
|
this.api._onDidChangeFocus.fire({ isFocused: true })
|
||||||
}
|
}),
|
||||||
|
onDidBlur(() => {
|
||||||
|
this.api._onDidChangeFocus.fire({ isFocused: false })
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
layout(width: number, height: number) {
|
||||||
|
this.api._onDidPanelDimensionChange.fire({ width, height })
|
||||||
|
}
|
||||||
|
|
||||||
|
init(parameters: InitParameters): void {
|
||||||
|
this.params = parameters
|
||||||
|
this.part = new ReactPart(
|
||||||
|
this.element,
|
||||||
|
this.api,
|
||||||
|
this.parent.addPortal,
|
||||||
|
this.component,
|
||||||
|
parameters.params
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
update(params: PanelUpdateEvent) {
|
||||||
|
this.params = { ...this.params.params, ...params }
|
||||||
|
this.part.update(params)
|
||||||
|
}
|
||||||
|
|
||||||
|
toJSON(): object {
|
||||||
|
return {
|
||||||
|
id: this.id,
|
||||||
|
component: this.componentName,
|
||||||
|
props: this.params.params,
|
||||||
|
state: this.api.getState(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dispose() {
|
||||||
|
super.dispose()
|
||||||
|
this.api.dispose()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,62 +1,62 @@
|
|||||||
import * as React from "react";
|
import * as React from 'react'
|
||||||
import {
|
import {
|
||||||
PanelContentPart,
|
PanelContentPart,
|
||||||
PartInitParameters,
|
PartInitParameters,
|
||||||
ClosePanelResult,
|
ClosePanelResult,
|
||||||
} from "../groupview/panel/parts";
|
} from '../groupview/panel/parts'
|
||||||
import { ReactPart, IPanelProps } from "./react";
|
import { ReactPart, IPanelProps } from './react'
|
||||||
import { ReactLayout } from "./layout";
|
import { ReactLayout } from './layout'
|
||||||
|
|
||||||
export class ReactPanelContentPart implements PanelContentPart {
|
export class ReactPanelContentPart implements PanelContentPart {
|
||||||
private _element: HTMLElement;
|
private _element: HTMLElement
|
||||||
private part: ReactPart;
|
private part: ReactPart
|
||||||
|
|
||||||
get element() {
|
get element() {
|
||||||
return this._element;
|
return this._element
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public readonly id: string,
|
public readonly id: string,
|
||||||
private readonly component: React.FunctionComponent<IPanelProps>,
|
private readonly component: React.FunctionComponent<IPanelProps>,
|
||||||
private readonly parent: ReactLayout
|
private readonly parent: ReactLayout
|
||||||
) {
|
) {
|
||||||
this._element = document.createElement("div");
|
this._element = document.createElement('div')
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(parameters: PartInitParameters): void {
|
public init(parameters: PartInitParameters): void {
|
||||||
this.part = new ReactPart(
|
this.part = new ReactPart(
|
||||||
this.element,
|
this.element,
|
||||||
parameters.api,
|
parameters.api,
|
||||||
this.parent.addPortal,
|
this.parent.addPortal,
|
||||||
this.component,
|
this.component,
|
||||||
parameters.params
|
parameters.params
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
public toJSON() {
|
public toJSON() {
|
||||||
return {
|
return {
|
||||||
id: this.id,
|
id: this.id,
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public update(params: {}) {
|
public update(params: {}) {
|
||||||
this.part.update(params);
|
this.part.update(params)
|
||||||
}
|
}
|
||||||
|
|
||||||
public setVisible(isPanelVisible: boolean, isGroupVisible: boolean): void {
|
public setVisible(isPanelVisible: boolean, isGroupVisible: boolean): void {
|
||||||
// noop - retrieval from api
|
// noop - retrieval from api
|
||||||
}
|
}
|
||||||
|
|
||||||
public layout(width: number, height: number): void {}
|
public layout(width: number, height: number): void {}
|
||||||
|
|
||||||
public close(): Promise<ClosePanelResult> {
|
public close(): Promise<ClosePanelResult> {
|
||||||
return Promise.resolve(ClosePanelResult.CLOSE);
|
return Promise.resolve(ClosePanelResult.CLOSE)
|
||||||
}
|
}
|
||||||
|
|
||||||
public focus(): void {}
|
public focus(): void {}
|
||||||
public onHide(): void {}
|
public onHide(): void {}
|
||||||
|
|
||||||
public dispose() {
|
public dispose() {
|
||||||
this.part?.dispose();
|
this.part?.dispose()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,49 +1,49 @@
|
|||||||
import * as React from "react";
|
import * as React from 'react'
|
||||||
import { PanelHeaderPart, PartInitParameters } from "../groupview/panel/parts";
|
import { PanelHeaderPart, PartInitParameters } from '../groupview/panel/parts'
|
||||||
import { ReactPart, IPanelProps } from "./react";
|
import { ReactPart, IPanelProps } from './react'
|
||||||
import { ReactLayout } from "./layout";
|
import { ReactLayout } from './layout'
|
||||||
|
|
||||||
export class ReactPanelHeaderPart implements PanelHeaderPart {
|
export class ReactPanelHeaderPart implements PanelHeaderPart {
|
||||||
private _element: HTMLElement;
|
private _element: HTMLElement
|
||||||
private part: ReactPart;
|
private part: ReactPart
|
||||||
|
|
||||||
get element() {
|
get element() {
|
||||||
return this._element;
|
return this._element
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public readonly id: string,
|
public readonly id: string,
|
||||||
private readonly component: React.FunctionComponent<IPanelProps>,
|
private readonly component: React.FunctionComponent<IPanelProps>,
|
||||||
private readonly parent: ReactLayout
|
private readonly parent: ReactLayout
|
||||||
) {
|
) {
|
||||||
this._element = document.createElement("div");
|
this._element = document.createElement('div')
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(parameters: PartInitParameters): void {
|
public init(parameters: PartInitParameters): void {
|
||||||
this.part = new ReactPart(
|
this.part = new ReactPart(
|
||||||
this.element,
|
this.element,
|
||||||
parameters.api,
|
parameters.api,
|
||||||
this.parent.addPortal,
|
this.parent.addPortal,
|
||||||
this.component,
|
this.component,
|
||||||
parameters.params
|
parameters.params
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
public toJSON() {
|
public toJSON() {
|
||||||
return {
|
return {
|
||||||
id: this.id,
|
id: this.id,
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public layout(height: string) {
|
public layout(height: string) {
|
||||||
// noop - retrieval from api
|
// noop - retrieval from api
|
||||||
}
|
}
|
||||||
|
|
||||||
public setVisible(isPanelVisible: boolean, isGroupVisible: boolean): void {
|
public setVisible(isPanelVisible: boolean, isGroupVisible: boolean): void {
|
||||||
// noop - retrieval from api
|
// noop - retrieval from api
|
||||||
}
|
}
|
||||||
|
|
||||||
public dispose() {
|
public dispose() {
|
||||||
this.part?.dispose();
|
this.part?.dispose()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,93 +1,97 @@
|
|||||||
import * as React from "react";
|
import * as React from 'react'
|
||||||
import { IPanelApi } from "../panel/api";
|
import { IPanelApi } from '../panel/api'
|
||||||
import { IDisposable } from "../lifecycle";
|
import { IDisposable } from '../lifecycle'
|
||||||
import {
|
import {
|
||||||
IComponentSplitview,
|
IComponentSplitview,
|
||||||
ComponentSplitview,
|
ComponentSplitview,
|
||||||
} from "../splitview/componentSplitview";
|
} from '../splitview/componentSplitview'
|
||||||
import { Orientation } from "../splitview/splitview";
|
import { Orientation } from '../splitview/splitview'
|
||||||
import { ReactComponentView } from "./reactComponentView";
|
import { ReactComponentView } from './reactComponentView'
|
||||||
|
|
||||||
export interface SplitviewFacade {
|
export interface SplitviewFacade {
|
||||||
addFromComponent(options: {
|
addFromComponent(options: {
|
||||||
id: string;
|
id: string
|
||||||
component: string;
|
component: string
|
||||||
params?: { [index: string]: any };
|
params?: { [index: string]: any }
|
||||||
}): void;
|
}): void
|
||||||
layout(size: number, orthogonalSize: number): void;
|
layout(size: number, orthogonalSize: number): void
|
||||||
onChange: (cb: (event: { proportions: number[] }) => void) => IDisposable;
|
onChange: (cb: (event: { proportions: number[] }) => void) => IDisposable
|
||||||
toJSON: () => any;
|
toJSON: () => any
|
||||||
deserialize: (data: any) => void;
|
deserialize: (data: any) => void
|
||||||
minimumSize: number;
|
minimumSize: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SplitviewReadyEvent {
|
export interface SplitviewReadyEvent {
|
||||||
api: IComponentSplitview;
|
api: IComponentSplitview
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISplitviewPanelProps {
|
export interface ISplitviewPanelProps {
|
||||||
api: IPanelApi;
|
api: IPanelApi
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISplitviewComponentProps {
|
export interface ISplitviewComponentProps {
|
||||||
orientation: Orientation;
|
orientation: Orientation
|
||||||
onReady?: (event: SplitviewReadyEvent) => void;
|
onReady?: (event: SplitviewReadyEvent) => void
|
||||||
components: {
|
components: {
|
||||||
[index: string]: React.FunctionComponent<ISplitviewPanelProps>;
|
[index: string]: React.FunctionComponent<ISplitviewPanelProps>
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SplitViewComponent = (props: ISplitviewComponentProps) => {
|
export const SplitViewComponent = (props: ISplitviewComponentProps) => {
|
||||||
const domReference = React.useRef<HTMLDivElement>();
|
const domReference = React.useRef<HTMLDivElement>()
|
||||||
const splitpanel = React.useRef<IComponentSplitview>();
|
const splitpanel = React.useRef<IComponentSplitview>()
|
||||||
const [portals, setPortals] = React.useState<React.ReactPortal[]>([]);
|
const [portals, setPortals] = React.useState<React.ReactPortal[]>([])
|
||||||
|
|
||||||
const addPortal = React.useCallback((p: React.ReactPortal) => {
|
const addPortal = React.useCallback((p: React.ReactPortal) => {
|
||||||
setPortals((portals) => [...portals, p]);
|
setPortals((portals) => [...portals, p])
|
||||||
return {
|
return {
|
||||||
dispose: () => {
|
dispose: () => {
|
||||||
setPortals((portals) => portals.filter((portal) => portal !== p));
|
setPortals((portals) =>
|
||||||
},
|
portals.filter((portal) => portal !== p)
|
||||||
};
|
)
|
||||||
}, []);
|
},
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
splitpanel.current = new ComponentSplitview(domReference.current, {
|
splitpanel.current = new ComponentSplitview(domReference.current, {
|
||||||
orientation: props.orientation,
|
orientation: props.orientation,
|
||||||
frameworkComponents: props.components,
|
frameworkComponents: props.components,
|
||||||
frameworkWrapper: {
|
frameworkWrapper: {
|
||||||
createComponent: (id: string, component: any) => {
|
createComponent: (id: string, component: any) => {
|
||||||
return new ReactComponentView(id, id, component, { addPortal });
|
return new ReactComponentView(id, id, component, {
|
||||||
},
|
addPortal,
|
||||||
},
|
})
|
||||||
proportionalLayout: false,
|
},
|
||||||
});
|
},
|
||||||
|
proportionalLayout: false,
|
||||||
|
})
|
||||||
|
|
||||||
const { width, height } = domReference.current.getBoundingClientRect();
|
const { width, height } = domReference.current.getBoundingClientRect()
|
||||||
const [size, orthogonalSize] =
|
const [size, orthogonalSize] =
|
||||||
props.orientation === Orientation.HORIZONTAL
|
props.orientation === Orientation.HORIZONTAL
|
||||||
? [width, height]
|
? [width, height]
|
||||||
: [height, width];
|
: [height, width]
|
||||||
splitpanel.current.layout(size, orthogonalSize);
|
splitpanel.current.layout(size, orthogonalSize)
|
||||||
|
|
||||||
if (props.onReady) {
|
if (props.onReady) {
|
||||||
props.onReady({ api: splitpanel.current });
|
props.onReady({ api: splitpanel.current })
|
||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
splitpanel.current.dispose();
|
splitpanel.current.dispose()
|
||||||
};
|
}
|
||||||
}, []);
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
height: "100%",
|
height: '100%',
|
||||||
width: "100%",
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
ref={domReference}
|
ref={domReference}
|
||||||
>
|
>
|
||||||
{portals}
|
{portals}
|
||||||
</div>
|
</div>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
@ -1,156 +1,158 @@
|
|||||||
import { IDisposable } from "../lifecycle";
|
import { IDisposable } from '../lifecycle'
|
||||||
import { LayoutPriority, Orientation, SplitView } from "./splitview";
|
import { LayoutPriority, Orientation, SplitView } from './splitview'
|
||||||
import {
|
import {
|
||||||
createComponent,
|
createComponent,
|
||||||
ISerializableView,
|
ISerializableView,
|
||||||
SplitPanelOptions,
|
SplitPanelOptions,
|
||||||
} from "./options";
|
} from './options'
|
||||||
|
|
||||||
export interface IComponentSplitview extends IDisposable {
|
export interface IComponentSplitview extends IDisposable {
|
||||||
addFromComponent(options: {
|
addFromComponent(options: {
|
||||||
id: string;
|
id: string
|
||||||
component: string;
|
component: string
|
||||||
params?: {
|
params?: {
|
||||||
[index: string]: any;
|
[index: string]: any
|
||||||
};
|
}
|
||||||
priority?: LayoutPriority;
|
priority?: LayoutPriority
|
||||||
}): IDisposable;
|
}): IDisposable
|
||||||
layout(width: number, height: number): void;
|
layout(width: number, height: number): void
|
||||||
onChange(cb: (event: { proportions: number[] }) => void): IDisposable;
|
onChange(cb: (event: { proportions: number[] }) => void): IDisposable
|
||||||
toJSON(): object;
|
toJSON(): object
|
||||||
deserialize(data: any): void;
|
deserialize(data: any): void
|
||||||
minimumSize: number;
|
minimumSize: number
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A high-level implementation of splitview that works using 'panels'
|
* A high-level implementation of splitview that works using 'panels'
|
||||||
*/
|
*/
|
||||||
export class ComponentSplitview implements IComponentSplitview {
|
export class ComponentSplitview implements IComponentSplitview {
|
||||||
private splitview: SplitView;
|
private splitview: SplitView
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly element: HTMLElement,
|
private readonly element: HTMLElement,
|
||||||
private readonly options: SplitPanelOptions
|
private readonly options: SplitPanelOptions
|
||||||
) {
|
) {
|
||||||
if (!options.components) {
|
if (!options.components) {
|
||||||
options.components = {};
|
options.components = {}
|
||||||
}
|
}
|
||||||
if (!options.frameworkComponents) {
|
if (!options.frameworkComponents) {
|
||||||
options.frameworkComponents = {};
|
options.frameworkComponents = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.splitview = new SplitView(this.element, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.splitview = new SplitView(this.element, options);
|
get minimumSize() {
|
||||||
}
|
return this.splitview.minimumSize
|
||||||
|
}
|
||||||
|
|
||||||
get minimumSize() {
|
addFromComponent(options: {
|
||||||
return this.splitview.minimumSize;
|
id: string
|
||||||
}
|
component: string
|
||||||
|
params?: {
|
||||||
addFromComponent(options: {
|
[index: string]: any
|
||||||
id: string;
|
}
|
||||||
component: string;
|
priority?: LayoutPriority
|
||||||
params?: {
|
}): IDisposable {
|
||||||
[index: string]: any;
|
const view = createComponent(
|
||||||
};
|
options.component,
|
||||||
priority?: LayoutPriority;
|
|
||||||
}): IDisposable {
|
|
||||||
const view = createComponent(
|
|
||||||
options.component,
|
|
||||||
this.options.components,
|
|
||||||
this.options.frameworkComponents,
|
|
||||||
this.options.frameworkWrapper.createComponent
|
|
||||||
);
|
|
||||||
|
|
||||||
this.registerView(view);
|
|
||||||
|
|
||||||
this.splitview.addView(view, { type: "distribute" });
|
|
||||||
view.init({ params: options.params });
|
|
||||||
view.priority = options.priority;
|
|
||||||
|
|
||||||
return {
|
|
||||||
dispose: () => {
|
|
||||||
//
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private registerView(view: ISerializableView) {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
layout(width: number, height: number): void {
|
|
||||||
const [size, orthogonalSize] =
|
|
||||||
this.splitview.orientation === Orientation.HORIZONTAL
|
|
||||||
? [width, height]
|
|
||||||
: [height, width];
|
|
||||||
this.splitview.layout(size, orthogonalSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
onChange(cb: (event: { proportions: number[] }) => void): IDisposable {
|
|
||||||
return this.splitview.onDidSashEnd(() => {
|
|
||||||
cb({ proportions: this.splitview.proportions });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
toJSON(): object {
|
|
||||||
const views = this.splitview.getViews().map((v: ISerializableView, i) => {
|
|
||||||
const size = this.splitview.getViewSize(i);
|
|
||||||
return {
|
|
||||||
size,
|
|
||||||
data: v.toJSON ? v.toJSON() : {},
|
|
||||||
minimumSize: v.minimumSize,
|
|
||||||
maximumSize: v.maximumSize,
|
|
||||||
snapSize: v.snapSize,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
views,
|
|
||||||
size: this.splitview.size,
|
|
||||||
orientation: this.splitview.orientation,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
deserialize(data: any): void {
|
|
||||||
const { views, orientation, size } = data;
|
|
||||||
|
|
||||||
this.splitview.dispose();
|
|
||||||
this.splitview = new SplitView(this.element, {
|
|
||||||
orientation,
|
|
||||||
proportionalLayout: false,
|
|
||||||
descriptor: {
|
|
||||||
size,
|
|
||||||
views: views.map((v) => {
|
|
||||||
const data = v.data;
|
|
||||||
|
|
||||||
const view = createComponent(
|
|
||||||
data.component,
|
|
||||||
this.options.components,
|
this.options.components,
|
||||||
this.options.frameworkComponents,
|
this.options.frameworkComponents,
|
||||||
this.options.frameworkWrapper.createComponent
|
this.options.frameworkWrapper.createComponent
|
||||||
);
|
)
|
||||||
|
|
||||||
if (typeof v.minimumSize === "number") {
|
this.registerView(view)
|
||||||
view.minimumSize = v.minimumSize;
|
|
||||||
}
|
|
||||||
if (typeof v.maximumSize === "number") {
|
|
||||||
view.maximumSize = v.maximumSize;
|
|
||||||
}
|
|
||||||
if (typeof v.snapSize === "number") {
|
|
||||||
view.snapSize = v.snapSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
view.init({ params: v.props });
|
this.splitview.addView(view, { type: 'distribute' })
|
||||||
|
view.init({ params: options.params })
|
||||||
|
view.priority = options.priority
|
||||||
|
|
||||||
view.priority = v.priority;
|
return {
|
||||||
|
dispose: () => {
|
||||||
|
//
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return { size: v.size, view };
|
private registerView(view: ISerializableView) {
|
||||||
}),
|
//
|
||||||
},
|
}
|
||||||
});
|
|
||||||
|
|
||||||
this.splitview.orientation = orientation;
|
layout(width: number, height: number): void {
|
||||||
}
|
const [size, orthogonalSize] =
|
||||||
|
this.splitview.orientation === Orientation.HORIZONTAL
|
||||||
|
? [width, height]
|
||||||
|
: [height, width]
|
||||||
|
this.splitview.layout(size, orthogonalSize)
|
||||||
|
}
|
||||||
|
|
||||||
public dispose() {
|
onChange(cb: (event: { proportions: number[] }) => void): IDisposable {
|
||||||
this.splitview.dispose();
|
return this.splitview.onDidSashEnd(() => {
|
||||||
}
|
cb({ proportions: this.splitview.proportions })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
toJSON(): object {
|
||||||
|
const views = this.splitview
|
||||||
|
.getViews()
|
||||||
|
.map((v: ISerializableView, i) => {
|
||||||
|
const size = this.splitview.getViewSize(i)
|
||||||
|
return {
|
||||||
|
size,
|
||||||
|
data: v.toJSON ? v.toJSON() : {},
|
||||||
|
minimumSize: v.minimumSize,
|
||||||
|
maximumSize: v.maximumSize,
|
||||||
|
snapSize: v.snapSize,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
views,
|
||||||
|
size: this.splitview.size,
|
||||||
|
orientation: this.splitview.orientation,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
deserialize(data: any): void {
|
||||||
|
const { views, orientation, size } = data
|
||||||
|
|
||||||
|
this.splitview.dispose()
|
||||||
|
this.splitview = new SplitView(this.element, {
|
||||||
|
orientation,
|
||||||
|
proportionalLayout: false,
|
||||||
|
descriptor: {
|
||||||
|
size,
|
||||||
|
views: views.map((v) => {
|
||||||
|
const data = v.data
|
||||||
|
|
||||||
|
const view = createComponent(
|
||||||
|
data.component,
|
||||||
|
this.options.components,
|
||||||
|
this.options.frameworkComponents,
|
||||||
|
this.options.frameworkWrapper.createComponent
|
||||||
|
)
|
||||||
|
|
||||||
|
if (typeof v.minimumSize === 'number') {
|
||||||
|
view.minimumSize = v.minimumSize
|
||||||
|
}
|
||||||
|
if (typeof v.maximumSize === 'number') {
|
||||||
|
view.maximumSize = v.maximumSize
|
||||||
|
}
|
||||||
|
if (typeof v.snapSize === 'number') {
|
||||||
|
view.snapSize = v.snapSize
|
||||||
|
}
|
||||||
|
|
||||||
|
view.init({ params: v.props })
|
||||||
|
|
||||||
|
view.priority = v.priority
|
||||||
|
|
||||||
|
return { size: v.size, view }
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
this.splitview.orientation = orientation
|
||||||
|
}
|
||||||
|
|
||||||
|
public dispose() {
|
||||||
|
this.splitview.dispose()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,58 +1,58 @@
|
|||||||
import { IView, ISplitViewOptions } from "../splitview/splitview";
|
import { IView, ISplitViewOptions } from '../splitview/splitview'
|
||||||
import { Constructor, FrameworkFactory } from "../types";
|
import { Constructor, FrameworkFactory } from '../types'
|
||||||
|
|
||||||
export interface ISerializableView extends IView {
|
export interface ISerializableView extends IView {
|
||||||
toJSON: () => object;
|
toJSON: () => object
|
||||||
init: (params: { params: any }) => void;
|
init: (params: { params: any }) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SplitPanelOptions extends ISplitViewOptions {
|
export interface SplitPanelOptions extends ISplitViewOptions {
|
||||||
components?: {
|
components?: {
|
||||||
[componentName: string]: ISerializableView;
|
[componentName: string]: ISerializableView
|
||||||
};
|
}
|
||||||
frameworkComponents?: {
|
frameworkComponents?: {
|
||||||
[componentName: string]: any;
|
[componentName: string]: any
|
||||||
};
|
}
|
||||||
frameworkWrapper?: FrameworkFactory<ISerializableView>;
|
frameworkWrapper?: FrameworkFactory<ISerializableView>
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISerializableViewConstructor
|
export interface ISerializableViewConstructor
|
||||||
extends Constructor<ISerializableView> {}
|
extends Constructor<ISerializableView> {}
|
||||||
|
|
||||||
export function createComponent<T>(
|
export function createComponent<T>(
|
||||||
componentName: string | Constructor<T> | any,
|
componentName: string | Constructor<T> | any,
|
||||||
components: {
|
components: {
|
||||||
[componentName: string]: T;
|
[componentName: string]: T
|
||||||
},
|
},
|
||||||
frameworkComponents: {
|
frameworkComponents: {
|
||||||
[componentName: string]: any;
|
[componentName: string]: any
|
||||||
},
|
},
|
||||||
createFrameworkComponent: (id: string, component: any) => T
|
createFrameworkComponent: (id: string, component: any) => T
|
||||||
): T {
|
): T {
|
||||||
const Component =
|
const Component =
|
||||||
typeof componentName === "string"
|
typeof componentName === 'string'
|
||||||
? components[componentName]
|
? components[componentName]
|
||||||
: componentName;
|
: componentName
|
||||||
const FrameworkComponent =
|
const FrameworkComponent =
|
||||||
typeof componentName === "string"
|
typeof componentName === 'string'
|
||||||
? frameworkComponents[componentName]
|
? frameworkComponents[componentName]
|
||||||
: componentName;
|
: componentName
|
||||||
if (Component && FrameworkComponent) {
|
if (Component && FrameworkComponent) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`cannot register component ${componentName} as both a component and frameworkComponent`
|
`cannot register component ${componentName} as both a component and frameworkComponent`
|
||||||
);
|
)
|
||||||
}
|
|
||||||
if (FrameworkComponent) {
|
|
||||||
if (!createFrameworkComponent) {
|
|
||||||
throw new Error(
|
|
||||||
"you must register a frameworkPanelWrapper to use framework components"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
const wrappedComponent = createFrameworkComponent(
|
if (FrameworkComponent) {
|
||||||
componentName,
|
if (!createFrameworkComponent) {
|
||||||
FrameworkComponent
|
throw new Error(
|
||||||
);
|
'you must register a frameworkPanelWrapper to use framework components'
|
||||||
return wrappedComponent;
|
)
|
||||||
}
|
}
|
||||||
return new Component() as T;
|
const wrappedComponent = createFrameworkComponent(
|
||||||
|
componentName,
|
||||||
|
FrameworkComponent
|
||||||
|
)
|
||||||
|
return wrappedComponent
|
||||||
|
}
|
||||||
|
return new Component() as T
|
||||||
}
|
}
|
||||||
|
@ -1,130 +1,130 @@
|
|||||||
.split-view-container {
|
.split-view-container {
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
&.animation {
|
|
||||||
.view,
|
|
||||||
.sash {
|
|
||||||
transition-duration: 0.15s;
|
|
||||||
transition-timing-function: ease-out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// debug
|
|
||||||
// .sash {
|
|
||||||
// &.enabled {
|
|
||||||
// background-color: black;
|
|
||||||
// }
|
|
||||||
// &.disabled {
|
|
||||||
// background-color: orange;
|
|
||||||
// }
|
|
||||||
// &.maximum {
|
|
||||||
// background-color: green;
|
|
||||||
// }
|
|
||||||
// &.minimum {
|
|
||||||
// background-color: red;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
&.horizontal {
|
|
||||||
height: 100%;
|
|
||||||
|
|
||||||
& > .sash-container > .sash {
|
|
||||||
height: 100%;
|
|
||||||
width: 4px;
|
|
||||||
&.enabled {
|
|
||||||
cursor: ew-resize;
|
|
||||||
}
|
|
||||||
&.disabled {
|
|
||||||
cursor: none;
|
|
||||||
}
|
|
||||||
&.maximum {
|
|
||||||
cursor: w-resize;
|
|
||||||
}
|
|
||||||
&.minimum {
|
|
||||||
cursor: e-resize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& > .view-container > .view {
|
|
||||||
&:not(:first-child) {
|
|
||||||
padding-left: 1px;
|
|
||||||
&::before {
|
|
||||||
height: 100%;
|
|
||||||
width: 1px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.vertical {
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
& > .sash-container > .sash {
|
|
||||||
width: 100%;
|
|
||||||
height: 4px;
|
|
||||||
|
|
||||||
&.enabled {
|
|
||||||
cursor: ns-resize;
|
|
||||||
}
|
|
||||||
&.disabled {
|
|
||||||
cursor: none;
|
|
||||||
}
|
|
||||||
&.maximum {
|
|
||||||
cursor: n-resize;
|
|
||||||
}
|
|
||||||
&.minimum {
|
|
||||||
cursor: s-resize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& > .view-container > .view {
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
&:not(:first-child) {
|
|
||||||
padding-top: 1px;
|
|
||||||
&::before {
|
|
||||||
height: 1px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.sash-container {
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
position: absolute;
|
|
||||||
|
|
||||||
.sash {
|
|
||||||
position: absolute;
|
|
||||||
z-index: 99;
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.view-container {
|
|
||||||
position: relative;
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
.view:not(:first-child)::before {
|
&.animation {
|
||||||
content: " ";
|
.view,
|
||||||
position: absolute;
|
.sash {
|
||||||
top: 0;
|
transition-duration: 0.15s;
|
||||||
left: 0;
|
transition-timing-function: ease-out;
|
||||||
z-index: 5;
|
}
|
||||||
pointer-events: none;
|
|
||||||
background-color: var(--splitview-divider-color);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.view {
|
// debug
|
||||||
height: 100%;
|
// .sash {
|
||||||
box-sizing: border-box;
|
// &.enabled {
|
||||||
overflow: auto;
|
// background-color: black;
|
||||||
position: absolute;
|
// }
|
||||||
|
// &.disabled {
|
||||||
|
// background-color: orange;
|
||||||
|
// }
|
||||||
|
// &.maximum {
|
||||||
|
// background-color: green;
|
||||||
|
// }
|
||||||
|
// &.minimum {
|
||||||
|
// background-color: red;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
&.horizontal {
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
& > .sash-container > .sash {
|
||||||
|
height: 100%;
|
||||||
|
width: 4px;
|
||||||
|
&.enabled {
|
||||||
|
cursor: ew-resize;
|
||||||
|
}
|
||||||
|
&.disabled {
|
||||||
|
cursor: none;
|
||||||
|
}
|
||||||
|
&.maximum {
|
||||||
|
cursor: w-resize;
|
||||||
|
}
|
||||||
|
&.minimum {
|
||||||
|
cursor: e-resize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& > .view-container > .view {
|
||||||
|
&:not(:first-child) {
|
||||||
|
padding-left: 1px;
|
||||||
|
&::before {
|
||||||
|
height: 100%;
|
||||||
|
width: 1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.vertical {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
& > .sash-container > .sash {
|
||||||
|
width: 100%;
|
||||||
|
height: 4px;
|
||||||
|
|
||||||
|
&.enabled {
|
||||||
|
cursor: ns-resize;
|
||||||
|
}
|
||||||
|
&.disabled {
|
||||||
|
cursor: none;
|
||||||
|
}
|
||||||
|
&.maximum {
|
||||||
|
cursor: n-resize;
|
||||||
|
}
|
||||||
|
&.minimum {
|
||||||
|
cursor: s-resize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& > .view-container > .view {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
&:not(:first-child) {
|
||||||
|
padding-top: 1px;
|
||||||
|
&::before {
|
||||||
|
height: 1px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sash-container {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
position: absolute;
|
||||||
|
|
||||||
|
.sash {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 99;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-container {
|
||||||
|
position: relative;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.view:not(:first-child)::before {
|
||||||
|
content: ' ';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 5;
|
||||||
|
pointer-events: none;
|
||||||
|
background-color: var(--splitview-divider-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.view {
|
||||||
|
height: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: auto;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,41 +1,41 @@
|
|||||||
:root {
|
:root {
|
||||||
--group-view-background-color: #252526;
|
--group-view-background-color: #252526;
|
||||||
//
|
//
|
||||||
--title-bar-background-color: #252526;
|
--title-bar-background-color: #252526;
|
||||||
--title-bar-scroll-bar-color: #888;
|
--title-bar-scroll-bar-color: #888;
|
||||||
//
|
//
|
||||||
--active-tab-background-visible: #1e1e1e;
|
--active-tab-background-visible: #1e1e1e;
|
||||||
--active-tab-background-hidden: #2d2d2d;
|
--active-tab-background-hidden: #2d2d2d;
|
||||||
--inactive-tab-background-visible: #1e1e1e;
|
--inactive-tab-background-visible: #1e1e1e;
|
||||||
--inactive-tab-background-hidden: #2d2d2d;
|
--inactive-tab-background-hidden: #2d2d2d;
|
||||||
--tab-divider-color: #1e1e1e;
|
--tab-divider-color: #1e1e1e;
|
||||||
//
|
//
|
||||||
--drag-over-background-color: rgba(83, 89, 93, 0.5);
|
--drag-over-background-color: rgba(83, 89, 93, 0.5);
|
||||||
//
|
//
|
||||||
--active-group-visible-panel-color: white;
|
--active-group-visible-panel-color: white;
|
||||||
--active-group-hidden-panel-color: #969696;
|
--active-group-hidden-panel-color: #969696;
|
||||||
--inactive-group-visible-panel-color: #8f8f8f;
|
--inactive-group-visible-panel-color: #8f8f8f;
|
||||||
--inactive-group-hidden-panel-color: #626262;
|
--inactive-group-hidden-panel-color: #626262;
|
||||||
//
|
//
|
||||||
--tab-close-icon: url("https://fonts.gstatic.com/s/i/materialicons/close/v8/24px.svg");
|
--tab-close-icon: url('https://fonts.gstatic.com/s/i/materialicons/close/v8/24px.svg');
|
||||||
--tab-dirty-icon: url("https://fonts.gstatic.com/s/i/materialicons/lens/v6/24px.svg");
|
--tab-dirty-icon: url('https://fonts.gstatic.com/s/i/materialicons/lens/v6/24px.svg');
|
||||||
//
|
//
|
||||||
--splitview-divider-color: rgb(68, 68, 68);
|
--splitview-divider-color: rgb(68, 68, 68);
|
||||||
}
|
}
|
||||||
|
|
||||||
.visual-studio-theme {
|
.visual-studio-theme {
|
||||||
--active-tab-background-visible: dodgerblue;
|
--active-tab-background-visible: dodgerblue;
|
||||||
|
|
||||||
.groupview {
|
.groupview {
|
||||||
&.active-group {
|
&.active-group {
|
||||||
> .title-container {
|
> .title-container {
|
||||||
border-bottom: 2px solid var(--active-tab-background-visible);
|
border-bottom: 2px solid var(--active-tab-background-visible);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
&.inactive-group {
|
||||||
|
> .title-container {
|
||||||
|
border-bottom: 2px solid var(--inactive-tab-background-visible);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
&.inactive-group {
|
|
||||||
> .title-container {
|
|
||||||
border-bottom: 2px solid var(--inactive-tab-background-visible);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
export interface Constructor<T> {
|
export interface Constructor<T> {
|
||||||
new (): T;
|
new (): T
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FrameworkFactory<T> {
|
export interface FrameworkFactory<T> {
|
||||||
createComponent: (id: string, component: any) => T;
|
createComponent: (id: string, component: any) => T
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FunctionOrValue<T> = (() => T) | T;
|
export type FunctionOrValue<T> = (() => T) | T
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"extends": "../../tsconfig.build.json",
|
"extends": "../../tsconfig.build.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"composite": true,
|
"composite": true,
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"outDir": "./dist",
|
"outDir": "./dist",
|
||||||
"rootDir": "./src"
|
"rootDir": "./src"
|
||||||
},
|
},
|
||||||
"include": ["src/**/*"]
|
"include": ["src/**/*"]
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
{
|
{
|
||||||
"extends": "../../tsconfig.json"
|
"extends": "../../tsconfig.json"
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"out": "typedocs",
|
"out": "typedocs",
|
||||||
"mode": "file",
|
"mode": "file",
|
||||||
"inputFiles": ["./src"],
|
"inputFiles": ["./src"],
|
||||||
"exclude": ["**/_test/**/*.*", "**/index.ts"],
|
"exclude": ["**/_test/**/*.*", "**/index.ts"],
|
||||||
"ignoreCompilerErrors": true,
|
"ignoreCompilerErrors": true,
|
||||||
"disableOutputCheck": true,
|
"disableOutputCheck": true,
|
||||||
"excludeExternals": true,
|
"excludeExternals": true,
|
||||||
"excludePrivate": true,
|
"excludePrivate": true,
|
||||||
"excludeNotExported": true
|
"excludeNotExported": true
|
||||||
}
|
}
|
||||||
|
108
scripts/build.js
108
scripts/build.js
@ -1,63 +1,63 @@
|
|||||||
const gulp = require("gulp");
|
const gulp = require('gulp')
|
||||||
const gulpClean = require("gulp-clean");
|
const gulpClean = require('gulp-clean')
|
||||||
const gulpTypescript = require("gulp-typescript");
|
const gulpTypescript = require('gulp-typescript')
|
||||||
const merge = require("merge2");
|
const merge = require('merge2')
|
||||||
const header = require("gulp-header");
|
const header = require('gulp-header')
|
||||||
const gulpSass = require("gulp-sass");
|
const gulpSass = require('gulp-sass')
|
||||||
const concat = require("gulp-concat");
|
const concat = require('gulp-concat')
|
||||||
const sourcemaps = require("gulp-sourcemaps");
|
const sourcemaps = require('gulp-sourcemaps')
|
||||||
|
|
||||||
const headerTemplate = [
|
const headerTemplate = [
|
||||||
"/**",
|
'/**',
|
||||||
" * <%= pkg.name %> - <%= pkg.description %>",
|
' * <%= pkg.name %> - <%= pkg.description %>',
|
||||||
" * @version v<%= pkg.version %>",
|
' * @version v<%= pkg.version %>',
|
||||||
" * @link <%= pkg.homepage %>",
|
' * @link <%= pkg.homepage %>',
|
||||||
" * @licence <%= pkg.licence %>",
|
' * @licence <%= pkg.licence %>',
|
||||||
" */\n",
|
' */\n',
|
||||||
].join("\n");
|
].join('\n')
|
||||||
|
|
||||||
const dtsHeaderTemplate = [
|
const dtsHeaderTemplate = [
|
||||||
"// Type definitions for <%= pkg.name %> v <%= pkg.version %>",
|
'// Type definitions for <%= pkg.name %> v <%= pkg.version %>',
|
||||||
"// Project <%= pkg.homepage %>\n",
|
'// Project <%= pkg.homepage %>\n',
|
||||||
].join("\n");
|
].join('\n')
|
||||||
|
|
||||||
const build = (options) => {
|
const build = (options) => {
|
||||||
const { tsconfig, package } = options;
|
const { tsconfig, package } = options
|
||||||
gulp.task("clean", () =>
|
gulp.task('clean', () =>
|
||||||
gulp.src("dist", { read: false, allowEmpty: true }).pipe(gulpClean())
|
gulp.src('dist', { read: false, allowEmpty: true }).pipe(gulpClean())
|
||||||
);
|
)
|
||||||
|
|
||||||
gulp.task("esm", () => {
|
gulp.task('esm', () => {
|
||||||
const ts = gulpTypescript.createProject(tsconfig);
|
const ts = gulpTypescript.createProject(tsconfig)
|
||||||
const tsResult = gulp
|
const tsResult = gulp
|
||||||
.src(["src/**/*.ts", "src/**/*.tsx"])
|
.src(['src/**/*.ts', 'src/**/*.tsx'])
|
||||||
.pipe(sourcemaps.init())
|
.pipe(sourcemaps.init())
|
||||||
.pipe(ts());
|
.pipe(ts())
|
||||||
return merge([
|
return merge([
|
||||||
tsResult.dts
|
tsResult.dts
|
||||||
.pipe(header(dtsHeaderTemplate, { pkg: package }))
|
.pipe(header(dtsHeaderTemplate, { pkg: package }))
|
||||||
.pipe(gulp.dest("./dist/esm")),
|
.pipe(gulp.dest('./dist/esm')),
|
||||||
tsResult.js
|
tsResult.js
|
||||||
.pipe(header(headerTemplate, { pkg: package }))
|
.pipe(header(headerTemplate, { pkg: package }))
|
||||||
.pipe(gulp.dest("./dist/esm")),
|
.pipe(gulp.dest('./dist/esm')),
|
||||||
tsResult
|
tsResult
|
||||||
.pipe(sourcemaps.write(".", { includeContent: false }))
|
.pipe(sourcemaps.write('.', { includeContent: false }))
|
||||||
.pipe(gulp.dest("./dist/esm")),
|
.pipe(gulp.dest('./dist/esm')),
|
||||||
]);
|
])
|
||||||
});
|
})
|
||||||
|
|
||||||
gulp.task("sass", () => {
|
gulp.task('sass', () => {
|
||||||
return (
|
return (
|
||||||
gulp
|
gulp
|
||||||
.src("./src/**/*.scss")
|
.src('./src/**/*.scss')
|
||||||
// .pipe(
|
// .pipe(
|
||||||
// concat("styles.scss")
|
// concat("styles.scss")
|
||||||
.pipe(gulpSass().on("error", gulpSass.logError))
|
.pipe(gulpSass().on('error', gulpSass.logError))
|
||||||
// )
|
// )
|
||||||
.pipe(concat("styles.css"))
|
.pipe(concat('styles.css'))
|
||||||
.pipe(gulp.dest("./dist"))
|
.pipe(gulp.dest('./dist'))
|
||||||
);
|
)
|
||||||
});
|
})
|
||||||
};
|
}
|
||||||
|
|
||||||
module.exports = { build };
|
module.exports = { build }
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user