mirror of
https://github.com/mathuo/dockview
synced 2025-02-01 22:15:44 +00:00
feat: Vue 3 Support
This commit is contained in:
parent
45919ff397
commit
c5770d4381
3
.vscode/extensions.json
vendored
3
.vscode/extensions.json
vendored
@ -7,7 +7,8 @@
|
||||
"esbenp.prettier-vscode",
|
||||
"redhat.vscode-yaml",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"editorconfig.editorconfig"
|
||||
"editorconfig.editorconfig",
|
||||
"vue.volar"
|
||||
],
|
||||
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
|
||||
"unwantedRecommendations": []
|
||||
|
12
package.json
12
package.json
@ -45,6 +45,8 @@
|
||||
"@types/react-dom": "^18.2.18",
|
||||
"@typescript-eslint/eslint-plugin": "^6.17.0",
|
||||
"@typescript-eslint/parser": "^6.17.0",
|
||||
"@vitejs/plugin-vue": "^5.0.4",
|
||||
"@vue/tsconfig": "^0.5.1",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^8.56.0",
|
||||
"fs-extra": "^11.2.0",
|
||||
@ -66,9 +68,15 @@
|
||||
"ts-node": "^10.9.2",
|
||||
"tslib": "^2.6.2",
|
||||
"typedoc": "^0.25.6",
|
||||
"typescript": "^5.3.3"
|
||||
"typescript": "^5.3.3",
|
||||
"vite": "^5.1.5",
|
||||
"vue": "^3.4.21",
|
||||
"vue-tsc": "^2.0.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ag-grid-vue3": "^31.1.1"
|
||||
}
|
||||
}
|
||||
}
|
56
packages/dockview-angular/README.md
Normal file
56
packages/dockview-angular/README.md
Normal file
@ -0,0 +1,56 @@
|
||||
<div align="center">
|
||||
<h1>dockview</h1>
|
||||
|
||||
<p>Zero dependency layout manager supporting tabs, groups, grids and splitviews with ReactJS support written in TypeScript</p>
|
||||
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
[![npm version](https://badge.fury.io/js/dockview.svg)](https://www.npmjs.com/package/dockview)
|
||||
[![npm](https://img.shields.io/npm/dm/dockview)](https://www.npmjs.com/package/dockview)
|
||||
[![CI Build](https://github.com/mathuo/dockview/workflows/CI/badge.svg)](https://github.com/mathuo/dockview/actions?query=workflow%3ACI)
|
||||
[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=mathuo_dockview&metric=coverage)](https://sonarcloud.io/summary/overall?id=mathuo_dockview)
|
||||
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=mathuo_dockview&metric=alert_status)](https://sonarcloud.io/summary/overall?id=mathuo_dockview)
|
||||
[![Bundle Phobia](https://badgen.net/bundlephobia/minzip/dockview)](https://bundlephobia.com/result?p=dockview)
|
||||
|
||||
##
|
||||
|
||||
Please see the website: https://dockview.dev
|
||||
|
||||
## Features
|
||||
|
||||
- Serialization / deserialization with full layout management
|
||||
- Support for split-views, grid-views and 'dockable' views
|
||||
- Themeable and customizable
|
||||
- Tab and Group docking / Drag n' Drop
|
||||
- Popout Windows
|
||||
- Floating Groups
|
||||
- Extensive API
|
||||
- Supports Shadow DOMs
|
||||
- High test coverage
|
||||
- Documentation website with live examples
|
||||
- Transparent builds and Code Analysis
|
||||
- Security at mind - verifed publishing and builds through GitHub Actions
|
||||
|
||||
Want to verify our builds? Go [here](https://www.npmjs.com/package/dockview#Provenance).
|
||||
|
||||
## Quick start
|
||||
|
||||
Dockview has a peer dependency on `react >= 16.8.0` and `react-dom >= 16.8.0`. You can install dockview from [npm](https://www.npmjs.com/package/dockview).
|
||||
|
||||
```
|
||||
npm install --save dockview
|
||||
```
|
||||
|
||||
Within your project you must import or reference the stylesheet at `dockview/dist/styles/dockview.css` and attach a theme.
|
||||
|
||||
```css
|
||||
@import '~dockview/dist/styles/dockview.css';
|
||||
```
|
||||
|
||||
You should also attach a dockview theme to an element containing your components. For example:
|
||||
|
||||
```html
|
||||
<body classname="dockview-theme-dark"></body>
|
||||
```
|
6
packages/dockview-angular/gulpfile.js
Normal file
6
packages/dockview-angular/gulpfile.js
Normal file
@ -0,0 +1,6 @@
|
||||
const gulp = require('gulp');
|
||||
const buildfile = require('../../scripts/build');
|
||||
|
||||
buildfile.init();
|
||||
|
||||
gulp.task('run', gulp.series(['sass']));
|
34
packages/dockview-angular/jest.config.ts
Normal file
34
packages/dockview-angular/jest.config.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import { JestConfigWithTsJest } from 'ts-jest';
|
||||
|
||||
const config: JestConfigWithTsJest = {
|
||||
preset: 'ts-jest',
|
||||
roots: ['<rootDir>/packages/dockview-angular'],
|
||||
modulePaths: ['<rootDir>/packages/dockview-angular/src'],
|
||||
displayName: { name: 'dockview', color: 'blue' },
|
||||
rootDir: '../../',
|
||||
collectCoverageFrom: [
|
||||
'<rootDir>/packages/dockview-angular/src/**/*.{js,jsx,ts,tsx}',
|
||||
],
|
||||
setupFiles: [
|
||||
// '<rootDir>/packages/dockview-angular/src/__tests__/__mocks__/resizeObserver.js',
|
||||
],
|
||||
setupFilesAfterEnv: ['<rootDir>/jest-setup.ts'],
|
||||
coveragePathIgnorePatterns: ['/node_modules/'],
|
||||
modulePathIgnorePatterns: [
|
||||
// '<rootDir>/packages/dockview-angular/src/__tests__/__mocks__',
|
||||
// '<rootDir>/packages/dockview-angular/src/__tests__/__test_utils__',
|
||||
],
|
||||
coverageDirectory: '<rootDir>/packages/dockview-angular/coverage/',
|
||||
testResultsProcessor: 'jest-sonar-reporter',
|
||||
testEnvironment: 'jsdom',
|
||||
transform: {
|
||||
'^.+\\.tsx?$': [
|
||||
'ts-jest',
|
||||
{
|
||||
tsconfig: '<rootDir>/tsconfig.test.json',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
59
packages/dockview-angular/package.json
Normal file
59
packages/dockview-angular/package.json
Normal file
@ -0,0 +1,59 @@
|
||||
{
|
||||
"name": "dockview-angular",
|
||||
"version": "0.0.0-beta-0",
|
||||
"description": "Zero dependency layout manager supporting tabs, grids and splitviews with ReactJS support",
|
||||
"keywords": [
|
||||
"splitview",
|
||||
"split-view",
|
||||
"gridview",
|
||||
"grid-view",
|
||||
"dockview",
|
||||
"dock-view",
|
||||
"grid",
|
||||
"tabs",
|
||||
"layout",
|
||||
"layout manager",
|
||||
"dock layout",
|
||||
"dock",
|
||||
"docking",
|
||||
"splitter",
|
||||
"drag-and-drop",
|
||||
"drag",
|
||||
"drop",
|
||||
"react",
|
||||
"react-component"
|
||||
],
|
||||
"homepage": "https://github.com/mathuo/dockview",
|
||||
"bugs": {
|
||||
"url": "https://github.com/mathuo/dockview/issues"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mathuo/dockview.git"
|
||||
},
|
||||
"license": "MIT",
|
||||
"author": "https://github.com/mathuo",
|
||||
"main": "./dist/cjs/index.js",
|
||||
"module": "./dist/esm/index.js",
|
||||
"types": "./dist/cjs/index.d.ts",
|
||||
"files": [
|
||||
"dist",
|
||||
"README.md"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "npm run build:package && npm run build:bundles",
|
||||
"build:bundles": "rollup -c",
|
||||
"build:cjs": "cross-env ../../node_modules/.bin/tsc --build ./tsconfig.json --verbose --extendedDiagnostics",
|
||||
"build:css": "gulp sass",
|
||||
"build:esm": "cross-env ../../node_modules/.bin/tsc --build ./tsconfig.esm.json --verbose --extendedDiagnostics",
|
||||
"build:package": "npm run build:cjs && npm run build:esm && npm run build:css",
|
||||
"clean": "rimraf dist/ .build/ .rollup.cache/",
|
||||
"prepublishOnly": "npm run rebuild && npm run test",
|
||||
"rebuild": "npm run clean && npm run build",
|
||||
"test": "cross-env ../../node_modules/.bin/jest --selectProjects dockview",
|
||||
"test:cov": "cross-env ../../node_modules/.bin/jest --selectProjects dockview --coverage"
|
||||
},
|
||||
"dependencies": {
|
||||
"dockview-core": "^1.10.1"
|
||||
}
|
||||
}
|
113
packages/dockview-angular/rollup.config.js
Normal file
113
packages/dockview-angular/rollup.config.js
Normal file
@ -0,0 +1,113 @@
|
||||
/* eslint-disable */
|
||||
|
||||
const { join } = require('path');
|
||||
const typescript = require('@rollup/plugin-typescript');
|
||||
const terser = require('@rollup/plugin-terser');
|
||||
const postcss = require('rollup-plugin-postcss');
|
||||
const nodeResolve = require('@rollup/plugin-node-resolve');
|
||||
|
||||
const { name, version, homepage, license } = require('./package.json');
|
||||
const main = join(__dirname, './scripts/rollupEntryTarget.ts');
|
||||
const mainNoStyles = join(__dirname, './src/index.ts');
|
||||
const outputDir = join(__dirname, 'dist');
|
||||
|
||||
function outputFile(format, isMinified, withStyles) {
|
||||
let filename = join(outputDir, name);
|
||||
|
||||
if (format !== 'umd') {
|
||||
filename += `.${format}`;
|
||||
}
|
||||
if (isMinified) {
|
||||
filename += '.min';
|
||||
}
|
||||
if (!withStyles) {
|
||||
filename += '.noStyle';
|
||||
}
|
||||
|
||||
return `${filename}.js`;
|
||||
}
|
||||
|
||||
function getInput(options) {
|
||||
const { withStyles } = options;
|
||||
|
||||
if (withStyles) {
|
||||
return main;
|
||||
}
|
||||
|
||||
return mainNoStyles;
|
||||
}
|
||||
|
||||
function createBundle(format, options) {
|
||||
const { withStyles, isMinified } = options;
|
||||
const input = getInput(options);
|
||||
const file = outputFile(format, isMinified, withStyles);
|
||||
|
||||
const external = [];
|
||||
|
||||
const output = {
|
||||
file,
|
||||
format,
|
||||
sourcemap: true,
|
||||
globals: {},
|
||||
banner: [
|
||||
`/**`,
|
||||
` * ${name}`,
|
||||
` * @version ${version}`,
|
||||
` * @link ${homepage}`,
|
||||
` * @license ${license}`,
|
||||
` */`,
|
||||
].join('\n'),
|
||||
};
|
||||
|
||||
const plugins = [
|
||||
nodeResolve({
|
||||
include: ['node_modules/dockview-core/**'],
|
||||
}),
|
||||
typescript({
|
||||
tsconfig: 'tsconfig.esm.json',
|
||||
}),
|
||||
];
|
||||
|
||||
if (isMinified) {
|
||||
plugins.push(terser());
|
||||
}
|
||||
if (withStyles) {
|
||||
plugins.push(postcss());
|
||||
}
|
||||
|
||||
if (format === 'umd') {
|
||||
output['name'] = name;
|
||||
}
|
||||
|
||||
external.push('react', 'react-dom');
|
||||
|
||||
if (format === 'umd') {
|
||||
output.globals['react'] = 'React';
|
||||
output.globals['react-dom'] = 'ReactDOM';
|
||||
}
|
||||
|
||||
return {
|
||||
input,
|
||||
output,
|
||||
plugins,
|
||||
external,
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = [
|
||||
// amd
|
||||
createBundle('amd', { withStyles: false, isMinified: false }),
|
||||
createBundle('amd', { withStyles: true, isMinified: false }),
|
||||
createBundle('amd', { withStyles: false, isMinified: true }),
|
||||
createBundle('amd', { withStyles: true, isMinified: true }),
|
||||
// umd
|
||||
createBundle('umd', { withStyles: false, isMinified: false }),
|
||||
createBundle('umd', { withStyles: true, isMinified: false }),
|
||||
createBundle('umd', { withStyles: false, isMinified: true }),
|
||||
createBundle('umd', { withStyles: true, isMinified: true }),
|
||||
// cjs
|
||||
createBundle('cjs', { withStyles: true, isMinified: false }),
|
||||
// esm
|
||||
createBundle('esm', { withStyles: true, isMinified: false }),
|
||||
createBundle('esm', { withStyles: true, isMinified: true }),
|
||||
];
|
2
packages/dockview-angular/scripts/rollupEntryTarget.ts
Normal file
2
packages/dockview-angular/scripts/rollupEntryTarget.ts
Normal file
@ -0,0 +1,2 @@
|
||||
import '../dist/styles/dockview.css';
|
||||
export * from '../src/index';
|
5
packages/dockview-angular/src/__tests__/empty.spec.ts
Normal file
5
packages/dockview-angular/src/__tests__/empty.spec.ts
Normal file
@ -0,0 +1,5 @@
|
||||
describe('empty', () => {
|
||||
test('that passes', () => {
|
||||
expect(true).toBeTruthy();
|
||||
});
|
||||
});
|
121
packages/dockview-angular/src/dockview.vue
Normal file
121
packages/dockview-angular/src/dockview.vue
Normal file
@ -0,0 +1,121 @@
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
DockviewApi,
|
||||
DockviewComponent,
|
||||
type DockviewDndOverlayEvent,
|
||||
type DockviewPanelRenderer,
|
||||
type DroptargetOverlayModel,
|
||||
type IContentRenderer,
|
||||
type ITabRenderer,
|
||||
type IWatermarkRenderer
|
||||
} from 'dockview-core'
|
||||
import { ref, onMounted, watch, onBeforeUnmount } from 'vue'
|
||||
import {
|
||||
VueContentRenderer,
|
||||
VueTabRenderer,
|
||||
VueWatermarkRenderer,
|
||||
type ComponentInterface
|
||||
} from './utils'
|
||||
|
||||
interface Props {
|
||||
// onReady: (event: DockviewReadyEvent) => void;
|
||||
components: Record<string, any>
|
||||
tabComponents?: Record<string, any>
|
||||
// watermarkComponent?: React.FunctionComponent<IWatermarkPanelProps>;
|
||||
// onDidDrop?: (event: DockviewDidDropEvent) => void;
|
||||
// onWillDrop?: (event: DockviewWillDropEvent) => void;
|
||||
// showDndOverlay?: (event: DockviewDndOverlayEvent) => boolean;
|
||||
hideBorders?: boolean;
|
||||
className?: string;
|
||||
disableAutoResizing?: boolean;
|
||||
// defaultTabComponent?: React.FunctionComponent<IDockviewPanelHeaderProps>;
|
||||
// rightHeaderActionsComponent?: React.FunctionComponent<IDockviewHeaderActionsProps>;
|
||||
// leftHeaderActionsComponent?: React.FunctionComponent<IDockviewHeaderActionsProps>;
|
||||
// prefixHeaderActionsComponent?: React.FunctionComponent<IDockviewHeaderActionsProps>;
|
||||
singleTabMode?: 'fullwidth' | 'default';
|
||||
disableFloatingGroups?: boolean;
|
||||
floatingGroupBounds?:
|
||||
| 'boundedWithinViewport'
|
||||
| {
|
||||
minimumHeightWithinViewport?: number;
|
||||
minimumWidthWithinViewport?: number;
|
||||
};
|
||||
debug?: boolean;
|
||||
defaultRenderer?: DockviewPanelRenderer;
|
||||
rootOverlayModel?: DroptargetOverlayModel
|
||||
locked?: boolean;
|
||||
disableDnd?: boolean;
|
||||
}
|
||||
|
||||
interface Emits {
|
||||
(event: 'ready', value: { api: DockviewApi }): void
|
||||
(event: 'showDndOverlay', value: DockviewDndOverlayEvent):void
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
|
||||
const emit = defineEmits<Emits>()
|
||||
|
||||
const el = ref<HTMLElement | null>(null)
|
||||
const instance = ref<DockviewComponent | null>(null)
|
||||
|
||||
watch(() => props.components, (newValue, oldValue) => {
|
||||
if (instance.value) {
|
||||
instance.value.updateOptions({ components: newValue })
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
if (!el.value) {
|
||||
throw new Error('element is not mounted')
|
||||
}
|
||||
|
||||
const dockview = new DockviewComponent({
|
||||
parentElement: el.value,
|
||||
frameworkComponentFactory: {
|
||||
content: {
|
||||
createComponent: (id: string, componentId: string, component: any): IContentRenderer => {
|
||||
console.log('dockview-vue: createComponent')
|
||||
|
||||
return new VueContentRenderer(component as ComponentInterface)
|
||||
}
|
||||
},
|
||||
tab: {
|
||||
createComponent: (id: string, componentId: string, component: any): ITabRenderer => {
|
||||
return new VueTabRenderer(component as ComponentInterface)
|
||||
}
|
||||
},
|
||||
watermark: {
|
||||
createComponent: (id: string, componentId: string, component: any): IWatermarkRenderer => {
|
||||
return new VueWatermarkRenderer(component as ComponentInterface)
|
||||
}
|
||||
}
|
||||
},
|
||||
frameworkComponents: props.components,
|
||||
disableAutoResizing: props.disableAutoResizing,
|
||||
frameworkTabComponents: props.tabComponents,
|
||||
singleTabMode: props.singleTabMode,
|
||||
disableFloatingGroups: props.disableFloatingGroups,
|
||||
floatingGroupBounds: props.floatingGroupBounds,
|
||||
defaultRenderer: props.defaultRenderer,
|
||||
debug: props.debug,
|
||||
rootOverlayModel: props.rootOverlayModel,
|
||||
locked: props.locked,
|
||||
disableDnd: props.disableDnd,
|
||||
})
|
||||
|
||||
instance.value = dockview
|
||||
emit("ready", { api: new DockviewApi(dockview) })
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (instance.value) {
|
||||
instance.value.dispose()
|
||||
}
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="el" />
|
||||
</template>
|
0
packages/dockview-angular/src/index.scss
Normal file
0
packages/dockview-angular/src/index.scss
Normal file
1
packages/dockview-angular/src/index.ts
Normal file
1
packages/dockview-angular/src/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from 'dockview-core';
|
151
packages/dockview-angular/src/utils.ts
Normal file
151
packages/dockview-angular/src/utils.ts
Normal file
@ -0,0 +1,151 @@
|
||||
import type {
|
||||
DockviewGroupPanel,
|
||||
GroupPanelPartInitParameters,
|
||||
IContentRenderer,
|
||||
ITabRenderer,
|
||||
IWatermarkRenderer,
|
||||
PanelUpdateEvent,
|
||||
Parameters,
|
||||
WatermarkRendererInitParameters
|
||||
} from 'dockview-core'
|
||||
import { createVNode, type ComponentOptionsBase, render, cloneVNode, mergeProps } from 'vue'
|
||||
|
||||
export type ComponentInterface = ComponentOptionsBase<any, any, any, any, any, any, any, any>
|
||||
|
||||
/**
|
||||
* TODO List
|
||||
*
|
||||
* 1. handle vue context-ish stuff (appContext? provides?)
|
||||
*
|
||||
*
|
||||
*
|
||||
* @see https://vuejs.org/api/render-function.html#clonevnode
|
||||
* @see https://vuejs.org/api/render-function.html#mergeprops
|
||||
*/
|
||||
export function mountVueComponent(component: ComponentInterface, props: any, element: HTMLElement) {
|
||||
let vNode = createVNode(component, props)
|
||||
|
||||
render(vNode, element)
|
||||
|
||||
return {
|
||||
update: (newProps: any) => {
|
||||
vNode = cloneVNode(vNode, mergeProps(props, newProps))
|
||||
render(vNode, element)
|
||||
},
|
||||
dispose: () => {
|
||||
render(null, element)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class VueContentRenderer implements IContentRenderer {
|
||||
private _element: HTMLElement
|
||||
private _renderDisposable: { update: (props: any) => void; dispose: () => void } | undefined
|
||||
|
||||
get element(): HTMLElement {
|
||||
return this._element
|
||||
}
|
||||
|
||||
constructor(private readonly component: ComponentInterface) {
|
||||
this._element = document.createElement('div')
|
||||
this.element.className = 'dv-vue-part'
|
||||
}
|
||||
|
||||
init(parameters: GroupPanelPartInitParameters): void {
|
||||
const props = {
|
||||
params: parameters.params,
|
||||
api: parameters.api,
|
||||
containerApi: parameters.containerApi
|
||||
}
|
||||
|
||||
this._renderDisposable?.dispose()
|
||||
this._renderDisposable = mountVueComponent(this.component, props, this.element)
|
||||
}
|
||||
|
||||
update(event: PanelUpdateEvent<Parameters>): void {
|
||||
const params = event.params
|
||||
// TODO: handle prop updates somehow?
|
||||
this._renderDisposable?.update(params)
|
||||
}
|
||||
|
||||
focus(): void {
|
||||
// TODO: make optional on interface
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._renderDisposable?.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
export class VueTabRenderer implements ITabRenderer {
|
||||
private _element: HTMLElement
|
||||
private _renderDisposable: { update: (props: any) => void; dispose: () => void } | undefined
|
||||
|
||||
get element(): HTMLElement {
|
||||
return this._element
|
||||
}
|
||||
|
||||
constructor(private readonly component: ComponentInterface) {
|
||||
this._element = document.createElement('div')
|
||||
this.element.className = 'dv-vue-part'
|
||||
}
|
||||
|
||||
init(parameters: GroupPanelPartInitParameters): void {
|
||||
const props = {
|
||||
params: parameters.params,
|
||||
api: parameters.api,
|
||||
containerApi: parameters.containerApi
|
||||
}
|
||||
|
||||
this._renderDisposable?.dispose()
|
||||
this._renderDisposable = mountVueComponent(this.component, props, this.element)
|
||||
}
|
||||
|
||||
update(event: PanelUpdateEvent<Parameters>): void {
|
||||
const params = event.params
|
||||
// TODO: handle prop updates somehow?
|
||||
this._renderDisposable?.update(params)
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._renderDisposable?.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
export class VueWatermarkRenderer implements IWatermarkRenderer {
|
||||
private _element: HTMLElement
|
||||
private _renderDisposable: { update: (props: any) => void; dispose: () => void } | undefined
|
||||
|
||||
get element(): HTMLElement {
|
||||
return this._element
|
||||
}
|
||||
|
||||
constructor(private readonly component: ComponentInterface) {
|
||||
this._element = document.createElement('div')
|
||||
this.element.className = 'dv-vue-part'
|
||||
}
|
||||
|
||||
init(parameters: WatermarkRendererInitParameters): void {
|
||||
const props = {
|
||||
group: parameters.group,
|
||||
containerApi: parameters.containerApi
|
||||
}
|
||||
|
||||
this._renderDisposable?.dispose()
|
||||
this._renderDisposable = mountVueComponent(this.component, props, this.element)
|
||||
}
|
||||
|
||||
updateParentGroup(group: DockviewGroupPanel, visible: boolean): void {
|
||||
// TODO: make optional on interface
|
||||
}
|
||||
|
||||
update(event: PanelUpdateEvent<Parameters>): void {
|
||||
const params = event.params
|
||||
// TODO: handle prop updates somehow?
|
||||
this._renderDisposable?.update(params)
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._renderDisposable?.dispose()
|
||||
}
|
||||
}
|
14
packages/dockview-angular/tsconfig.esm.json
Normal file
14
packages/dockview-angular/tsconfig.esm.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"module": "ES2020",
|
||||
"moduleResolution": "node",
|
||||
"target": "es6",
|
||||
"outDir": "dist/esm",
|
||||
"tsBuildInfoFile": ".build/tsconfig.tsbuildinfo.esm",
|
||||
"jsx": "react",
|
||||
"rootDir": "src"
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["**/node_modules", "src/__tests__"]
|
||||
}
|
11
packages/dockview-angular/tsconfig.json
Normal file
11
packages/dockview-angular/tsconfig.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "dist/cjs",
|
||||
"tsBuildInfoFile": ".build/tsconfig.tsbuildinfo.cjs",
|
||||
"jsx": "react",
|
||||
"rootDir": "src"
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["**/node_modules", "src/__tests__"]
|
||||
}
|
5
packages/dockview-angular/typedoc.json
Normal file
5
packages/dockview-angular/typedoc.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": ["../../typedoc.base.json"],
|
||||
"entryPoints": ["src/index.ts"],
|
||||
"exclude": ["**/dist/**"]
|
||||
}
|
@ -2,7 +2,7 @@ import { fireEvent } from '@testing-library/dom';
|
||||
import { Emitter, Event } from '../../../../events';
|
||||
import { ContentContainer } from '../../../../dockview/components/panel/content';
|
||||
import {
|
||||
GroupPanelContentPartInitParameters,
|
||||
GroupPanelPartInitParameters,
|
||||
IContentRenderer,
|
||||
} from '../../../../dockview/types';
|
||||
import { CompositeDisposable } from '../../../../lifecycle';
|
||||
@ -20,18 +20,13 @@ class TestContentRenderer
|
||||
{
|
||||
readonly element: HTMLElement;
|
||||
|
||||
readonly _onDidFocus = new Emitter<void>();
|
||||
readonly _onDidBlur = new Emitter<void>();
|
||||
readonly onDidFocus: Event<void> = this._onDidFocus.event;
|
||||
readonly onDidBlur: Event<void> = this._onDidBlur.event;
|
||||
|
||||
constructor(public id: string) {
|
||||
super();
|
||||
this.element = document.createElement('div');
|
||||
this.element.id = id;
|
||||
}
|
||||
|
||||
init(parameters: GroupPanelContentPartInitParameters): void {
|
||||
init(parameters: GroupPanelPartInitParameters): void {
|
||||
//
|
||||
}
|
||||
|
||||
@ -110,16 +105,6 @@ describe('contentContainer', () => {
|
||||
expect(focus).toBe(1);
|
||||
expect(blur).toBe(1);
|
||||
|
||||
// renderer explicitly asks for focus
|
||||
contentRenderer._onDidFocus.fire();
|
||||
expect(focus).toBe(2);
|
||||
expect(blur).toBe(1);
|
||||
|
||||
// renderer explicitly looses focus
|
||||
contentRenderer._onDidBlur.fire();
|
||||
expect(focus).toBe(2);
|
||||
expect(blur).toBe(2);
|
||||
|
||||
const contentRenderer2 = new TestContentRenderer('id-2');
|
||||
|
||||
const panel2 = {
|
||||
@ -130,25 +115,19 @@ describe('contentContainer', () => {
|
||||
} as Partial<IDockviewPanel>;
|
||||
|
||||
cut.openPanel(panel2 as IDockviewPanel);
|
||||
expect(focus).toBe(2);
|
||||
expect(blur).toBe(2);
|
||||
|
||||
// previous renderer events should no longer be attached to container
|
||||
contentRenderer._onDidFocus.fire();
|
||||
contentRenderer._onDidBlur.fire();
|
||||
expect(focus).toBe(2);
|
||||
expect(blur).toBe(2);
|
||||
// expect(focus).toBe(2);
|
||||
// expect(blur).toBe(1);
|
||||
|
||||
// new panel recieves focus
|
||||
fireEvent.focus(contentRenderer2.element);
|
||||
expect(focus).toBe(3);
|
||||
expect(blur).toBe(2);
|
||||
expect(focus).toBe(2);
|
||||
expect(blur).toBe(1);
|
||||
|
||||
// new panel looses focus
|
||||
fireEvent.blur(contentRenderer2.element);
|
||||
jest.runAllTimers();
|
||||
expect(focus).toBe(3);
|
||||
expect(blur).toBe(3);
|
||||
expect(focus).toBe(2);
|
||||
expect(blur).toBe(2);
|
||||
|
||||
disposable.dispose();
|
||||
});
|
||||
|
@ -18,6 +18,7 @@ import {
|
||||
} from '../../dockview/components/titlebar/tabsContainer';
|
||||
import { fromPartial } from '@total-typescript/shoehorn';
|
||||
import { DockviewApi } from '../../api/component.api';
|
||||
import { DockviewDndOverlayEvent } from '../../dockview/options';
|
||||
|
||||
class PanelContentPartTest implements IContentRenderer {
|
||||
element: HTMLElement = document.createElement('div');
|
||||
@ -2040,7 +2041,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 1000);
|
||||
@ -2147,7 +2147,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 1000);
|
||||
@ -2289,7 +2288,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 1000);
|
||||
@ -2418,7 +2416,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 1000);
|
||||
@ -2467,66 +2464,6 @@ describe('dockviewComponent', () => {
|
||||
});
|
||||
});
|
||||
|
||||
test('orthogonal realigment #5', () => {
|
||||
const container = document.createElement('div');
|
||||
|
||||
const dockview = new DockviewComponent({
|
||||
parentElement: container,
|
||||
components: {
|
||||
default: PanelContentPartTest,
|
||||
},
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.VERTICAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 1000);
|
||||
|
||||
expect(dockview.orientation).toBe(Orientation.VERTICAL);
|
||||
|
||||
dockview.addPanel({
|
||||
id: 'panel1',
|
||||
component: 'default',
|
||||
position: {
|
||||
direction: 'left',
|
||||
},
|
||||
});
|
||||
|
||||
expect(dockview.orientation).toBe(Orientation.HORIZONTAL);
|
||||
|
||||
expect(JSON.parse(JSON.stringify(dockview.toJSON()))).toEqual({
|
||||
activeGroup: '1',
|
||||
grid: {
|
||||
root: {
|
||||
type: 'branch',
|
||||
data: [
|
||||
{
|
||||
type: 'leaf',
|
||||
data: {
|
||||
views: ['panel1'],
|
||||
id: '1',
|
||||
activeView: 'panel1',
|
||||
},
|
||||
size: 1000,
|
||||
},
|
||||
],
|
||||
size: 1000,
|
||||
},
|
||||
height: 1000,
|
||||
width: 1000,
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
},
|
||||
panels: {
|
||||
panel1: {
|
||||
id: 'panel1',
|
||||
contentComponent: 'default',
|
||||
title: 'panel1',
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('that a empty component has no groups', () => {
|
||||
const container = document.createElement('div');
|
||||
|
||||
@ -2538,7 +2475,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
expect(dockview.groups.length).toBe(0);
|
||||
@ -2555,7 +2491,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
expect(dockview.groups.length).toBe(0);
|
||||
@ -2595,7 +2530,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
expect(JSON.parse(JSON.stringify(dockview.toJSON()))).toEqual({
|
||||
@ -2624,7 +2558,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(100, 100);
|
||||
@ -2711,7 +2644,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(100, 100);
|
||||
@ -2774,7 +2706,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
expect(dockview.orientation).toBe(Orientation.HORIZONTAL);
|
||||
@ -2865,7 +2796,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -2897,7 +2827,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -2922,8 +2851,6 @@ describe('dockviewComponent', () => {
|
||||
test('that external dnd events do not trigger the top-level center dnd target unless empty', () => {
|
||||
const container = document.createElement('div');
|
||||
|
||||
const showDndOverlay = jest.fn().mockReturnValue(true);
|
||||
|
||||
const dockview = new DockviewComponent({
|
||||
parentElement: container,
|
||||
components: {
|
||||
@ -2932,8 +2859,13 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
showDndOverlay: showDndOverlay,
|
||||
});
|
||||
|
||||
let events: DockviewDndOverlayEvent[] = [];
|
||||
|
||||
dockview.onUnhandledDragOverEvent((e) => {
|
||||
events.push(e);
|
||||
e.accept();
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -2973,13 +2905,11 @@ describe('dockviewComponent', () => {
|
||||
});
|
||||
fireEvent(dockview.element, eventLeft);
|
||||
|
||||
expect(showDndOverlay).toHaveBeenCalledWith({
|
||||
nativeEvent: eventLeft,
|
||||
position: 'left',
|
||||
target: 'edge',
|
||||
getData: getPanelData,
|
||||
});
|
||||
expect(showDndOverlay).toBeCalledTimes(1);
|
||||
expect(events[0].nativeEvent).toBe(eventLeft);
|
||||
expect(events[0].position).toBe('left');
|
||||
expect(events[0].target).toBe('edge');
|
||||
expect(events[0].getData).toBe(getPanelData);
|
||||
expect(events.length).toBe(1);
|
||||
|
||||
// right
|
||||
|
||||
@ -2992,13 +2922,11 @@ describe('dockviewComponent', () => {
|
||||
});
|
||||
fireEvent(dockview.element, eventRight);
|
||||
|
||||
expect(showDndOverlay).toHaveBeenCalledWith({
|
||||
nativeEvent: eventRight,
|
||||
position: 'right',
|
||||
target: 'edge',
|
||||
getData: getPanelData,
|
||||
});
|
||||
expect(showDndOverlay).toBeCalledTimes(2);
|
||||
expect(events[1].nativeEvent).toBe(eventRight);
|
||||
expect(events[1].position).toBe('right');
|
||||
expect(events[1].target).toBe('edge');
|
||||
expect(events[1].getData).toBe(getPanelData);
|
||||
expect(events.length).toBe(2);
|
||||
|
||||
// top
|
||||
|
||||
@ -3011,13 +2939,11 @@ describe('dockviewComponent', () => {
|
||||
});
|
||||
fireEvent(dockview.element, eventTop);
|
||||
|
||||
expect(showDndOverlay).toHaveBeenCalledWith({
|
||||
nativeEvent: eventTop,
|
||||
position: 'top',
|
||||
target: 'edge',
|
||||
getData: getPanelData,
|
||||
});
|
||||
expect(showDndOverlay).toBeCalledTimes(3);
|
||||
expect(events[2].nativeEvent).toBe(eventTop);
|
||||
expect(events[2].position).toBe('top');
|
||||
expect(events[2].target).toBe('edge');
|
||||
expect(events[2].getData).toBe(getPanelData);
|
||||
expect(events.length).toBe(3);
|
||||
|
||||
// top
|
||||
|
||||
@ -3030,13 +2956,11 @@ describe('dockviewComponent', () => {
|
||||
});
|
||||
fireEvent(dockview.element, eventBottom);
|
||||
|
||||
expect(showDndOverlay).toHaveBeenCalledWith({
|
||||
nativeEvent: eventBottom,
|
||||
position: 'bottom',
|
||||
target: 'edge',
|
||||
getData: getPanelData,
|
||||
});
|
||||
expect(showDndOverlay).toBeCalledTimes(4);
|
||||
expect(events[3].nativeEvent).toBe(eventBottom);
|
||||
expect(events[3].position).toBe('bottom');
|
||||
expect(events[3].target).toBe('edge');
|
||||
expect(events[3].getData).toBe(getPanelData);
|
||||
expect(events.length).toBe(4);
|
||||
|
||||
// center
|
||||
|
||||
@ -3050,7 +2974,7 @@ describe('dockviewComponent', () => {
|
||||
fireEvent(dockview.element, eventCenter);
|
||||
|
||||
// expect not to be called for center
|
||||
expect(showDndOverlay).toBeCalledTimes(4);
|
||||
expect(events.length).toBe(4);
|
||||
|
||||
dockview.removePanel(panel1);
|
||||
dockview.removePanel(panel2);
|
||||
@ -3066,13 +2990,11 @@ describe('dockviewComponent', () => {
|
||||
});
|
||||
fireEvent(dockview.element, eventCenter2);
|
||||
|
||||
expect(showDndOverlay).toHaveBeenCalledWith({
|
||||
nativeEvent: eventTop,
|
||||
position: 'center',
|
||||
target: 'edge',
|
||||
getData: getPanelData,
|
||||
});
|
||||
expect(showDndOverlay).toBeCalledTimes(5);
|
||||
expect(events[4].nativeEvent).toBe(eventCenter2);
|
||||
expect(events[4].position).toBe('center');
|
||||
expect(events[4].target).toBe('edge');
|
||||
expect(events[4].getData).toBe(getPanelData);
|
||||
expect(events.length).toBe(5);
|
||||
});
|
||||
|
||||
test('that dragging a tab triggers onWillDragPanel', () => {
|
||||
@ -3086,7 +3008,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -3126,7 +3047,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -3167,7 +3087,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -3257,7 +3176,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -3380,7 +3298,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
expect(dockview.disableResizing).toBeFalsy();
|
||||
@ -3398,7 +3315,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
disableAutoResizing: true,
|
||||
});
|
||||
|
||||
@ -3417,7 +3333,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -3445,7 +3360,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -3488,7 +3402,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -3531,7 +3444,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -3582,7 +3494,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -3633,7 +3544,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -3684,7 +3594,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -3743,7 +3652,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -3786,7 +3694,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -3829,7 +3736,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -3880,7 +3786,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -3931,7 +3836,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -3982,7 +3886,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -4041,7 +3944,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -4092,7 +3994,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -4142,7 +4043,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -4193,7 +4093,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -4243,7 +4142,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -4283,7 +4181,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -4322,7 +4219,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -4362,7 +4258,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -4423,7 +4318,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -4462,7 +4356,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -4495,7 +4388,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -4568,7 +4460,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
|
||||
dockview.layout(1000, 500);
|
||||
@ -4609,7 +4500,6 @@ describe('dockviewComponent', () => {
|
||||
tabComponents: {
|
||||
test_tab_id: PanelTabPartTest,
|
||||
},
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
});
|
||||
const api = new DockviewApi(dockview);
|
||||
|
||||
|
@ -642,7 +642,6 @@ describe('dockviewGroupPanelModel', () => {
|
||||
return {
|
||||
id: 'testcomponentid',
|
||||
options: {
|
||||
showDndOverlay: jest.fn(),
|
||||
parentElement: document.createElement('div'),
|
||||
},
|
||||
getPanel: jest.fn(),
|
||||
@ -650,6 +649,7 @@ describe('dockviewGroupPanelModel', () => {
|
||||
onDidRemovePanel: jest.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
const accessor = new accessorMock() as DockviewComponent;
|
||||
const groupviewMock = jest.fn<Partial<DockviewGroupPanelModel>, []>(
|
||||
() => {
|
||||
@ -679,6 +679,12 @@ describe('dockviewGroupPanelModel', () => {
|
||||
new groupPanelMock() as DockviewGroupPanel
|
||||
);
|
||||
|
||||
let counter = 0;
|
||||
|
||||
cut.onUnhandledDragOverEvent(() => {
|
||||
counter++;
|
||||
});
|
||||
|
||||
const element = container
|
||||
.getElementsByClassName('content-container')
|
||||
.item(0)!;
|
||||
@ -691,7 +697,7 @@ describe('dockviewGroupPanelModel', () => {
|
||||
fireEvent.dragEnter(element);
|
||||
fireEvent.dragOver(element);
|
||||
|
||||
expect(accessor.options.showDndOverlay).toBeCalledTimes(1);
|
||||
expect(counter).toBe(1);
|
||||
|
||||
expect(
|
||||
element.getElementsByClassName('drop-target-dropzone').length
|
||||
@ -703,7 +709,6 @@ describe('dockviewGroupPanelModel', () => {
|
||||
return {
|
||||
id: 'testcomponentid',
|
||||
options: {
|
||||
showDndOverlay: () => true,
|
||||
parentElement: document.createElement('div'),
|
||||
},
|
||||
getPanel: jest.fn(),
|
||||
@ -740,6 +745,10 @@ describe('dockviewGroupPanelModel', () => {
|
||||
new groupPanelMock() as DockviewGroupPanel
|
||||
);
|
||||
|
||||
cut.onUnhandledDragOverEvent((e) => {
|
||||
e.accept();
|
||||
});
|
||||
|
||||
const element = container
|
||||
.getElementsByClassName('content-container')
|
||||
.item(0)!;
|
||||
@ -795,7 +804,6 @@ describe('dockviewGroupPanelModel', () => {
|
||||
return {
|
||||
id: 'testcomponentid',
|
||||
options: {
|
||||
showDndOverlay: jest.fn(),
|
||||
parentElement: document.createElement('div'),
|
||||
},
|
||||
getPanel: jest.fn(),
|
||||
@ -834,6 +842,12 @@ describe('dockviewGroupPanelModel', () => {
|
||||
new groupPanelMock() as DockviewGroupPanel
|
||||
);
|
||||
|
||||
let counter = 0;
|
||||
|
||||
cut.onUnhandledDragOverEvent(() => {
|
||||
counter++;
|
||||
});
|
||||
|
||||
cut.openPanel(
|
||||
new TestPanel('panel1', {
|
||||
renderer: 'onlyWhenVisibile',
|
||||
@ -857,7 +871,7 @@ describe('dockviewGroupPanelModel', () => {
|
||||
fireEvent.dragEnter(element);
|
||||
fireEvent.dragOver(element);
|
||||
|
||||
expect(accessor.options.showDndOverlay).toBeCalledTimes(0);
|
||||
expect(counter).toBe(0);
|
||||
|
||||
expect(
|
||||
element.getElementsByClassName('drop-target-dropzone').length
|
||||
@ -869,7 +883,6 @@ describe('dockviewGroupPanelModel', () => {
|
||||
return {
|
||||
id: 'testcomponentid',
|
||||
options: {
|
||||
showDndOverlay: jest.fn(),
|
||||
parentElement: document.createElement('div'),
|
||||
},
|
||||
getPanel: jest.fn(),
|
||||
@ -908,6 +921,12 @@ describe('dockviewGroupPanelModel', () => {
|
||||
new groupPanelMock() as DockviewGroupPanel
|
||||
);
|
||||
|
||||
let counter = 0;
|
||||
|
||||
cut.onUnhandledDragOverEvent(() => {
|
||||
counter++;
|
||||
});
|
||||
|
||||
cut.openPanel(
|
||||
new TestPanel('panel1', {
|
||||
renderer: 'onlyWhenVisibile',
|
||||
@ -936,7 +955,7 @@ describe('dockviewGroupPanelModel', () => {
|
||||
fireEvent.dragEnter(element);
|
||||
fireEvent.dragOver(element);
|
||||
|
||||
expect(accessor.options.showDndOverlay).toBeCalledTimes(0);
|
||||
expect(counter).toBe(0);
|
||||
|
||||
expect(
|
||||
element.getElementsByClassName('drop-target-dropzone').length
|
||||
@ -948,7 +967,6 @@ describe('dockviewGroupPanelModel', () => {
|
||||
return {
|
||||
id: 'testcomponentid',
|
||||
options: {
|
||||
showDndOverlay: jest.fn(),
|
||||
parentElement: document.createElement('div'),
|
||||
},
|
||||
getPanel: jest.fn(),
|
||||
@ -987,6 +1005,12 @@ describe('dockviewGroupPanelModel', () => {
|
||||
new groupPanelMock() as DockviewGroupPanel
|
||||
);
|
||||
|
||||
let counter = 0;
|
||||
|
||||
cut.onUnhandledDragOverEvent(() => {
|
||||
counter++;
|
||||
});
|
||||
|
||||
cut.openPanel(
|
||||
new TestPanel('panel1', {
|
||||
renderer: 'onlyWhenVisibile',
|
||||
@ -1015,7 +1039,7 @@ describe('dockviewGroupPanelModel', () => {
|
||||
fireEvent.dragEnter(element);
|
||||
fireEvent.dragOver(element);
|
||||
|
||||
expect(accessor.options.showDndOverlay).toBeCalledTimes(1);
|
||||
expect(counter).toBe(1);
|
||||
|
||||
expect(
|
||||
element.getElementsByClassName('drop-target-dropzone').length
|
||||
|
@ -5,6 +5,7 @@ import {
|
||||
import {
|
||||
AddGroupOptions,
|
||||
AddPanelOptions,
|
||||
DockviewDndOverlayEvent,
|
||||
MovementOptions,
|
||||
} from '../dockview/options';
|
||||
import { Parameters } from '../panel/types';
|
||||
@ -695,6 +696,10 @@ export class DockviewApi implements CommonApi<SerializedDockview> {
|
||||
return this.component.onWillDragPanel;
|
||||
}
|
||||
|
||||
get onUnhandledDragOverEvent(): Event<DockviewDndOverlayEvent> {
|
||||
return this.component.onUnhandledDragOverEvent;
|
||||
}
|
||||
|
||||
/**
|
||||
* All panel objects.
|
||||
*/
|
||||
|
@ -68,9 +68,10 @@ export function positionToDirection(position: Position): Direction {
|
||||
|
||||
export type Position = 'top' | 'bottom' | 'left' | 'right' | 'center';
|
||||
|
||||
export type CanDisplayOverlay =
|
||||
| boolean
|
||||
| ((dragEvent: DragEvent, state: Position) => boolean);
|
||||
export type CanDisplayOverlay = (
|
||||
dragEvent: DragEvent,
|
||||
state: Position
|
||||
) => boolean;
|
||||
|
||||
export type MeasuredValue = { value: number; type: 'pixels' | 'percentage' };
|
||||
|
||||
@ -170,6 +171,11 @@ export class Droptarget extends CompositeDisposable {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.options.canDisplayOverlay(e, quadrant)) {
|
||||
this.removeDropTarget();
|
||||
return;
|
||||
}
|
||||
|
||||
const willShowOverlayEvent = new WillShowOverlayEvent({
|
||||
nativeEvent: e,
|
||||
position: quadrant,
|
||||
@ -186,16 +192,6 @@ export class Droptarget extends CompositeDisposable {
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof this.options.canDisplayOverlay === 'boolean') {
|
||||
if (!this.options.canDisplayOverlay) {
|
||||
this.removeDropTarget();
|
||||
return;
|
||||
}
|
||||
} else if (!this.options.canDisplayOverlay(e, quadrant)) {
|
||||
this.removeDropTarget();
|
||||
return;
|
||||
}
|
||||
|
||||
this.markAsUsed(e);
|
||||
|
||||
if (!this.targetElement) {
|
||||
|
@ -157,9 +157,6 @@ export class ContentContainer
|
||||
}
|
||||
|
||||
if (doRender) {
|
||||
const _onDidFocus = panel.view.content.onDidFocus;
|
||||
const _onDidBlur = panel.view.content.onDidBlur;
|
||||
|
||||
const focusTracker = trackFocus(container);
|
||||
const disposable = new CompositeDisposable();
|
||||
|
||||
@ -169,17 +166,6 @@ export class ContentContainer
|
||||
focusTracker.onDidBlur(() => this._onDidBlur.fire())
|
||||
);
|
||||
|
||||
if (_onDidFocus) {
|
||||
disposable.addDisposables(
|
||||
_onDidFocus(() => this._onDidFocus.fire())
|
||||
);
|
||||
}
|
||||
if (_onDidBlur) {
|
||||
disposable.addDisposables(
|
||||
_onDidBlur(() => this._onDidBlur.fire())
|
||||
);
|
||||
}
|
||||
|
||||
this.disposable.value = disposable;
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import {
|
||||
} from '../dnd/droptarget';
|
||||
import { tail, sequenceEquals, remove } from '../array';
|
||||
import { DockviewPanel, IDockviewPanel } from './dockviewPanel';
|
||||
import { CompositeDisposable, Disposable, IDisposable } from '../lifecycle';
|
||||
import { CompositeDisposable, Disposable } from '../lifecycle';
|
||||
import { Event, Emitter, addDisposableWindowListener } from '../events';
|
||||
import { Watermark } from './components/watermark/watermark';
|
||||
import { IWatermarkRenderer, GroupviewPanelState } from './types';
|
||||
@ -23,6 +23,9 @@ import {
|
||||
AddGroupOptions,
|
||||
AddPanelOptions,
|
||||
DockviewComponentOptions,
|
||||
DockviewDndOverlayEvent,
|
||||
DockviewOptions,
|
||||
DockviewUnhandledDragOverEvent,
|
||||
isGroupOptionsWithGroup,
|
||||
isGroupOptionsWithPanel,
|
||||
isPanelOptionsWithGroup,
|
||||
@ -232,25 +235,6 @@ function typeValidate(data: SerializedDockview): void {
|
||||
typeValidate2(grid.root, '.grid.root');
|
||||
}
|
||||
|
||||
export type DockviewComponentUpdateOptions = Pick<
|
||||
DockviewComponentOptions,
|
||||
| 'orientation'
|
||||
| 'components'
|
||||
| 'frameworkComponents'
|
||||
| 'tabComponents'
|
||||
| 'frameworkTabComponents'
|
||||
| 'showDndOverlay'
|
||||
| 'watermarkFrameworkComponent'
|
||||
| 'defaultTabComponent'
|
||||
| 'createLeftHeaderActionsElement'
|
||||
| 'createRightHeaderActionsElement'
|
||||
| 'createPrefixHeaderActionsElement'
|
||||
| 'disableFloatingGroups'
|
||||
| 'floatingGroupBounds'
|
||||
| 'rootOverlayModel'
|
||||
| 'disableDnd'
|
||||
>;
|
||||
|
||||
type MoveGroupOptions = {
|
||||
from: { group: DockviewGroupPanel };
|
||||
to: { group: DockviewGroupPanel; position: Position };
|
||||
@ -285,8 +269,9 @@ export interface IDockviewComponent extends IBaseGrid<DockviewGroupPanel> {
|
||||
readonly onDidRemoveGroup: Event<DockviewGroupPanel>;
|
||||
readonly onDidAddGroup: Event<DockviewGroupPanel>;
|
||||
readonly onDidActiveGroupChange: Event<DockviewGroupPanel | undefined>;
|
||||
readonly onUnhandledDragOverEvent: Event<DockviewDndOverlayEvent>;
|
||||
readonly options: DockviewComponentOptions;
|
||||
updateOptions(options: DockviewComponentUpdateOptions): void;
|
||||
updateOptions(options: DockviewOptions): void;
|
||||
moveGroupOrPanel(options: MoveGroupOrPanelOptions): void;
|
||||
moveGroup(options: MoveGroupOptions): void;
|
||||
doSetGroupActive: (group: DockviewGroupPanel, skipFocus?: boolean) => void;
|
||||
@ -353,6 +338,11 @@ export class DockviewComponent
|
||||
readonly onWillShowOverlay: Event<WillShowOverlayLocationEvent> =
|
||||
this._onWillShowOverlay.event;
|
||||
|
||||
private readonly _onUnhandledDragOverEvent =
|
||||
new Emitter<DockviewDndOverlayEvent>();
|
||||
readonly onUnhandledDragOverEvent: Event<DockviewDndOverlayEvent> =
|
||||
this._onUnhandledDragOverEvent.event;
|
||||
|
||||
private readonly _onDidRemovePanel = new Emitter<IDockviewPanel>();
|
||||
readonly onDidRemovePanel: Event<IDockviewPanel> =
|
||||
this._onDidRemovePanel.event;
|
||||
@ -431,8 +421,10 @@ export class DockviewComponent
|
||||
constructor(options: DockviewComponentOptions) {
|
||||
super({
|
||||
proportionalLayout: true,
|
||||
orientation: options.orientation ?? Orientation.HORIZONTAL,
|
||||
styles: options.styles,
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
styles: options.hideBorders
|
||||
? { separatorBorder: 'transparent' }
|
||||
: undefined,
|
||||
parentElement: options.parentElement,
|
||||
disableAutoResizing: options.disableAutoResizing,
|
||||
locked: options.locked,
|
||||
@ -462,6 +454,7 @@ export class DockviewComponent
|
||||
this._onDidAddGroup,
|
||||
this._onDidRemoveGroup,
|
||||
this._onDidActiveGroupChange,
|
||||
this._onUnhandledDragOverEvent,
|
||||
this.onDidAdd((event) => {
|
||||
if (!this._moving) {
|
||||
this._onDidAddGroup.fire(event);
|
||||
@ -542,25 +535,25 @@ export class DockviewComponent
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.options.showDndOverlay) {
|
||||
if (position === 'center' && this.gridview.length !== 0) {
|
||||
/**
|
||||
* for external events only show the four-corner drag overlays, disable
|
||||
* the center position so that external drag events can fall through to the group
|
||||
* and panel drop target handlers
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.options.showDndOverlay({
|
||||
nativeEvent: event,
|
||||
position: position,
|
||||
target: 'edge',
|
||||
getData: getPanelData,
|
||||
});
|
||||
if (position === 'center' && this.gridview.length !== 0) {
|
||||
/**
|
||||
* for external events only show the four-corner drag overlays, disable
|
||||
* the center position so that external drag events can fall through to the group
|
||||
* and panel drop target handlers
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
const firedEvent = new DockviewUnhandledDragOverEvent(
|
||||
event,
|
||||
'edge',
|
||||
position,
|
||||
getPanelData
|
||||
);
|
||||
|
||||
this._onUnhandledDragOverEvent.fire(firedEvent);
|
||||
|
||||
return firedEvent.isAccepted;
|
||||
},
|
||||
acceptedTargetZones: ['top', 'bottom', 'left', 'right', 'center'],
|
||||
overlayModel:
|
||||
@ -1043,10 +1036,7 @@ export class DockviewComponent
|
||||
}
|
||||
}
|
||||
|
||||
updateOptions(options: DockviewComponentUpdateOptions): void {
|
||||
const changed_orientation =
|
||||
typeof options.orientation === 'string' &&
|
||||
this.gridview.orientation !== options.orientation;
|
||||
updateOptions(options: Partial<DockviewComponentOptions>): void {
|
||||
const changed_floatingGroupBounds =
|
||||
options.floatingGroupBounds !== undefined &&
|
||||
options.floatingGroupBounds !== this.options.floatingGroupBounds;
|
||||
@ -1057,10 +1047,6 @@ export class DockviewComponent
|
||||
|
||||
this._options = { ...this.options, ...options };
|
||||
|
||||
if (changed_orientation) {
|
||||
this.gridview.orientation = options.orientation!;
|
||||
}
|
||||
|
||||
if (changed_floatingGroupBounds) {
|
||||
for (const group of this._floatingGroups) {
|
||||
switch (this.options.floatingGroupBounds) {
|
||||
@ -2153,6 +2139,9 @@ export class DockviewComponent
|
||||
|
||||
this._onWillShowOverlay.fire(event);
|
||||
}),
|
||||
view.model.onUnhandledDragOverEvent((event) => {
|
||||
this._onUnhandledDragOverEvent.fire(event);
|
||||
}),
|
||||
view.model.onDidAddPanel((event) => {
|
||||
if (this._moving) {
|
||||
return;
|
||||
|
@ -26,7 +26,11 @@ import {
|
||||
import { IWatermarkRenderer } from './types';
|
||||
import { DockviewGroupPanel } from './dockviewGroupPanel';
|
||||
import { IDockviewPanel } from './dockviewPanel';
|
||||
import { IHeaderActionsRenderer } from './options';
|
||||
import {
|
||||
DockviewDndOverlayEvent,
|
||||
DockviewUnhandledDragOverEvent,
|
||||
IHeaderActionsRenderer,
|
||||
} from './options';
|
||||
import { OverlayRenderContainer } from '../overlayRenderContainer';
|
||||
|
||||
interface GroupMoveEvent {
|
||||
@ -281,6 +285,11 @@ export class DockviewGroupPanelModel
|
||||
readonly onDidActivePanelChange: Event<DockviewGroupChangeEvent> =
|
||||
this._onDidActivePanelChange.event;
|
||||
|
||||
private readonly _onUnhandledDragOverEvent =
|
||||
new Emitter<DockviewDndOverlayEvent>();
|
||||
readonly onUnhandledDragOverEvent: Event<DockviewDndOverlayEvent> =
|
||||
this._onUnhandledDragOverEvent.event;
|
||||
|
||||
private readonly _api: DockviewApi;
|
||||
|
||||
get element(): HTMLElement {
|
||||
@ -458,7 +467,8 @@ export class DockviewGroupPanelModel
|
||||
this._onWillDrop,
|
||||
this._onDidAddPanel,
|
||||
this._onDidRemovePanel,
|
||||
this._onDidActivePanelChange
|
||||
this._onDidActivePanelChange,
|
||||
this._onUnhandledDragOverEvent
|
||||
);
|
||||
}
|
||||
|
||||
@ -503,9 +513,9 @@ export class DockviewGroupPanelModel
|
||||
this.setActive(this.isActive, true);
|
||||
this.updateContainer();
|
||||
|
||||
if (this.accessor.options.createRightHeaderActionsElement) {
|
||||
if (this.accessor.options.headerRightActionComponent) {
|
||||
this._rightHeaderActions =
|
||||
this.accessor.options.createRightHeaderActionsElement(
|
||||
this.accessor.options.headerRightActionComponent(
|
||||
this.groupPanel
|
||||
);
|
||||
this.addDisposables(this._rightHeaderActions);
|
||||
@ -518,9 +528,9 @@ export class DockviewGroupPanelModel
|
||||
);
|
||||
}
|
||||
|
||||
if (this.accessor.options.createLeftHeaderActionsElement) {
|
||||
if (this.accessor.options.headerLeftActionComponent) {
|
||||
this._leftHeaderActions =
|
||||
this.accessor.options.createLeftHeaderActionsElement(
|
||||
this.accessor.options.headerLeftActionComponent(
|
||||
this.groupPanel
|
||||
);
|
||||
this.addDisposables(this._leftHeaderActions);
|
||||
@ -533,9 +543,9 @@ export class DockviewGroupPanelModel
|
||||
);
|
||||
}
|
||||
|
||||
if (this.accessor.options.createPrefixHeaderActionsElement) {
|
||||
if (this.accessor.options.headerPrefixActionComponent) {
|
||||
this._prefixHeaderActions =
|
||||
this.accessor.options.createPrefixHeaderActionsElement(
|
||||
this.accessor.options.headerPrefixActionComponent(
|
||||
this.groupPanel
|
||||
);
|
||||
this.addDisposables(this._prefixHeaderActions);
|
||||
@ -926,17 +936,17 @@ export class DockviewGroupPanelModel
|
||||
position: Position,
|
||||
target: DockviewGroupDropLocation
|
||||
): boolean {
|
||||
// custom overlay handler
|
||||
if (this.accessor.options.showDndOverlay) {
|
||||
return this.accessor.options.showDndOverlay({
|
||||
nativeEvent: event,
|
||||
target,
|
||||
group: this.accessor.getPanel(this.id)!,
|
||||
position,
|
||||
getData: getPanelData,
|
||||
});
|
||||
}
|
||||
return false;
|
||||
const firedEvent = new DockviewUnhandledDragOverEvent(
|
||||
event,
|
||||
target,
|
||||
position,
|
||||
getPanelData,
|
||||
this.accessor.getPanel(this.id)!
|
||||
);
|
||||
|
||||
this._onUnhandledDragOverEvent.fire(firedEvent);
|
||||
|
||||
return firedEvent.isAccepted;
|
||||
}
|
||||
|
||||
private handleDropEvent(
|
||||
|
@ -44,7 +44,7 @@ export class DockviewPanelModel implements IDockviewPanelModel {
|
||||
}
|
||||
|
||||
init(params: GroupPanelPartInitParameters): void {
|
||||
this.content.init({ ...params, tab: this.tab });
|
||||
this.content.init(params);
|
||||
this.tab.init(params);
|
||||
}
|
||||
|
||||
|
42
packages/dockview-core/src/dockview/framework.ts
Normal file
42
packages/dockview-core/src/dockview/framework.ts
Normal file
@ -0,0 +1,42 @@
|
||||
import { DockviewApi } from '../api/component.api';
|
||||
import { DockviewGroupPanelApi } from '../api/dockviewGroupPanelApi';
|
||||
import { DockviewPanelApi } from '../api/dockviewPanelApi';
|
||||
import { PanelParameters } from '../framwork';
|
||||
import { DockviewGroupPanel, IDockviewGroupPanel } from './dockviewGroupPanel';
|
||||
import { IDockviewPanel } from './dockviewPanel';
|
||||
|
||||
export interface IGroupPanelBaseProps<T extends { [index: string]: any } = any>
|
||||
extends PanelParameters<T> {
|
||||
api: DockviewPanelApi;
|
||||
containerApi: DockviewApi;
|
||||
}
|
||||
|
||||
export type IDockviewPanelHeaderProps<
|
||||
T extends { [index: string]: any } = any
|
||||
> = IGroupPanelBaseProps<T>;
|
||||
|
||||
export type IDockviewPanelProps<T extends { [index: string]: any } = any> =
|
||||
IGroupPanelBaseProps<T>;
|
||||
|
||||
export interface IDockviewHeaderActionsProps {
|
||||
api: DockviewGroupPanelApi;
|
||||
containerApi: DockviewApi;
|
||||
panels: IDockviewPanel[];
|
||||
activePanel: IDockviewPanel | undefined;
|
||||
isGroupActive: boolean;
|
||||
group: DockviewGroupPanel;
|
||||
}
|
||||
|
||||
export interface IGroupHeaderProps {
|
||||
api: DockviewGroupPanelApi;
|
||||
containerApi: DockviewApi;
|
||||
}
|
||||
|
||||
export interface IWatermarkPanelProps {
|
||||
containerApi: DockviewApi;
|
||||
group?: IDockviewGroupPanel;
|
||||
}
|
||||
|
||||
export interface DockviewReadyEvent {
|
||||
api: DockviewApi;
|
||||
}
|
@ -9,25 +9,24 @@ import {
|
||||
} from './types';
|
||||
import { Parameters } from '../panel/types';
|
||||
import { DockviewGroupPanel } from './dockviewGroupPanel';
|
||||
import { ISplitviewStyles, Orientation } from '../splitview/splitview';
|
||||
import { PanelTransfer } from '../dnd/dataTransfer';
|
||||
import { IDisposable } from '../lifecycle';
|
||||
import { DroptargetOverlayModel, Position } from '../dnd/droptarget';
|
||||
import { DockviewGroupDropLocation, GroupOptions } from './dockviewGroupPanelModel';
|
||||
import {
|
||||
DockviewGroupDropLocation,
|
||||
GroupOptions,
|
||||
} from './dockviewGroupPanelModel';
|
||||
import { IDockviewPanel } from './dockviewPanel';
|
||||
import {
|
||||
ComponentConstructor,
|
||||
FrameworkFactory,
|
||||
} from '../panel/componentFactory';
|
||||
import { DockviewGroupPanelApi } from '../api/dockviewGroupPanelApi';
|
||||
import { DockviewPanelRenderer } from '../overlayRenderContainer';
|
||||
import { IGroupHeaderProps } from './framework';
|
||||
|
||||
export interface IHeaderActionsRenderer extends IDisposable {
|
||||
readonly element: HTMLElement;
|
||||
init(params: {
|
||||
containerApi: DockviewApi;
|
||||
api: DockviewGroupPanelApi;
|
||||
}): void;
|
||||
init(params: IGroupHeaderProps): void;
|
||||
}
|
||||
|
||||
export interface GroupPanelFrameworkComponentFactory {
|
||||
@ -42,54 +41,15 @@ export interface TabContextMenuEvent {
|
||||
panel: IDockviewPanel;
|
||||
}
|
||||
|
||||
export interface DockviewRenderFunctions {
|
||||
tabComponents?: {
|
||||
[componentName: string]: ComponentConstructor<ITabRenderer>;
|
||||
};
|
||||
components?: {
|
||||
[componentName: string]: ComponentConstructor<IContentRenderer>;
|
||||
};
|
||||
frameworkTabComponents?: {
|
||||
[componentName: string]: any;
|
||||
};
|
||||
frameworkComponents?: {
|
||||
[componentName: string]: any;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ViewFactoryData {
|
||||
content: string;
|
||||
tab?: string;
|
||||
}
|
||||
|
||||
export interface DockviewDndOverlayEvent {
|
||||
nativeEvent: DragEvent;
|
||||
target: DockviewGroupDropLocation;
|
||||
position: Position;
|
||||
group?: DockviewGroupPanel;
|
||||
getData: () => PanelTransfer | undefined;
|
||||
}
|
||||
|
||||
export interface DockviewComponentOptions extends DockviewRenderFunctions {
|
||||
export interface DockviewOptions {
|
||||
disableAutoResizing?: boolean;
|
||||
watermarkComponent?: WatermarkConstructor;
|
||||
watermarkFrameworkComponent?: any;
|
||||
frameworkComponentFactory?: GroupPanelFrameworkComponentFactory;
|
||||
orientation?: Orientation;
|
||||
styles?: ISplitviewStyles;
|
||||
defaultTabComponent?: string;
|
||||
showDndOverlay?: (event: DockviewDndOverlayEvent) => boolean;
|
||||
createRightHeaderActionsElement?: (
|
||||
group: DockviewGroupPanel
|
||||
) => IHeaderActionsRenderer;
|
||||
createLeftHeaderActionsElement?: (
|
||||
group: DockviewGroupPanel
|
||||
) => IHeaderActionsRenderer;
|
||||
createPrefixHeaderActionsElement?: (
|
||||
group: DockviewGroupPanel
|
||||
) => IHeaderActionsRenderer;
|
||||
hideBorders?: boolean;
|
||||
singleTabMode?: 'fullwidth' | 'default';
|
||||
parentElement: HTMLElement;
|
||||
disableFloatingGroups?: boolean;
|
||||
floatingGroupBounds?:
|
||||
| 'boundedWithinViewport'
|
||||
@ -105,6 +65,108 @@ export interface DockviewComponentOptions extends DockviewRenderFunctions {
|
||||
disableDnd?: boolean;
|
||||
}
|
||||
|
||||
export interface DockviewDndOverlayEvent {
|
||||
nativeEvent: DragEvent;
|
||||
target: DockviewGroupDropLocation;
|
||||
position: Position;
|
||||
group?: DockviewGroupPanel;
|
||||
getData: () => PanelTransfer | undefined;
|
||||
//
|
||||
isAccepted: boolean;
|
||||
accept(): void;
|
||||
}
|
||||
|
||||
export class DockviewUnhandledDragOverEvent implements DockviewDndOverlayEvent {
|
||||
private _isAccepted = false;
|
||||
|
||||
get isAccepted(): boolean {
|
||||
return this._isAccepted;
|
||||
}
|
||||
|
||||
constructor(
|
||||
readonly nativeEvent: DragEvent,
|
||||
readonly target: DockviewGroupDropLocation,
|
||||
readonly position: Position,
|
||||
readonly getData: () => PanelTransfer | undefined,
|
||||
readonly group?: DockviewGroupPanel
|
||||
) {}
|
||||
|
||||
accept(): void {
|
||||
this._isAccepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
export interface DockviewEvents {
|
||||
// noop
|
||||
}
|
||||
|
||||
export const PROPERTY_KEYS: (keyof DockviewOptions)[] = (() => {
|
||||
/**
|
||||
* by readong the keys from an empty value object TypeScript will error
|
||||
* when we add or remove new properties to `DockviewOptions`
|
||||
*/
|
||||
const properties: Record<keyof DockviewOptions, undefined> = {
|
||||
disableAutoResizing: undefined,
|
||||
hideBorders: undefined,
|
||||
singleTabMode: undefined,
|
||||
disableFloatingGroups: undefined,
|
||||
floatingGroupBounds: undefined,
|
||||
popoutUrl: undefined,
|
||||
defaultRenderer: undefined,
|
||||
debug: undefined,
|
||||
rootOverlayModel: undefined,
|
||||
locked: undefined,
|
||||
disableDnd: undefined,
|
||||
};
|
||||
|
||||
return Object.keys(properties) as (keyof DockviewOptions)[];
|
||||
})();
|
||||
|
||||
export const EVENT_KEYS: (keyof DockviewEvents)[] = (() => {
|
||||
/**
|
||||
* by readong the keys from an empty value object TypeScript will error
|
||||
* when we add or remove new properties to `DockviewOptions`
|
||||
*/
|
||||
const properties: Record<keyof DockviewEvents, undefined> = {
|
||||
showDndOverlay: undefined,
|
||||
};
|
||||
|
||||
return Object.keys(properties) as (keyof DockviewEvents)[];
|
||||
})();
|
||||
|
||||
export interface DockviewFrameworkOptions {
|
||||
headerRightActionComponent?: (
|
||||
group: DockviewGroupPanel
|
||||
) => IHeaderActionsRenderer;
|
||||
headerLeftActionComponent?: (
|
||||
group: DockviewGroupPanel
|
||||
) => IHeaderActionsRenderer;
|
||||
headerPrefixActionComponent?: (
|
||||
group: DockviewGroupPanel
|
||||
) => IHeaderActionsRenderer;
|
||||
tabComponents?: {
|
||||
[componentName: string]: ComponentConstructor<ITabRenderer>;
|
||||
};
|
||||
components?: {
|
||||
[componentName: string]: ComponentConstructor<IContentRenderer>;
|
||||
};
|
||||
frameworkTabComponents?: {
|
||||
[componentName: string]: any;
|
||||
};
|
||||
frameworkComponents?: {
|
||||
[componentName: string]: any;
|
||||
};
|
||||
parentElement: HTMLElement;
|
||||
defaultTabComponent?: string;
|
||||
watermarkComponent?: WatermarkConstructor;
|
||||
watermarkFrameworkComponent?: any;
|
||||
frameworkComponentFactory?: GroupPanelFrameworkComponentFactory;
|
||||
}
|
||||
|
||||
export type DockviewComponentOptions = DockviewOptions &
|
||||
DockviewEvents &
|
||||
DockviewFrameworkOptions;
|
||||
|
||||
export interface PanelOptions<P extends object = Parameters> {
|
||||
component: string;
|
||||
tabComponent?: string;
|
||||
|
@ -18,11 +18,6 @@ export interface GroupPanelPartInitParameters
|
||||
containerApi: DockviewApi;
|
||||
}
|
||||
|
||||
export interface GroupPanelContentPartInitParameters
|
||||
extends GroupPanelPartInitParameters {
|
||||
tab: ITabRenderer;
|
||||
}
|
||||
|
||||
export interface WatermarkRendererInitParameters {
|
||||
containerApi: DockviewApi;
|
||||
group?: IDockviewGroupPanel;
|
||||
@ -31,7 +26,7 @@ export interface WatermarkRendererInitParameters {
|
||||
export interface IWatermarkRenderer
|
||||
extends Optional<
|
||||
Omit<IPanel, 'id' | 'init'>,
|
||||
'dispose' | 'update' | 'layout' | 'toJSON'
|
||||
'dispose' | 'update' | 'layout' | 'toJSON' | 'focus'
|
||||
> {
|
||||
readonly element: HTMLElement;
|
||||
init: (params: WatermarkRendererInitParameters) => void;
|
||||
@ -41,7 +36,7 @@ export interface IWatermarkRenderer
|
||||
export interface ITabRenderer
|
||||
extends Optional<
|
||||
Omit<IPanel, 'id'>,
|
||||
'dispose' | 'update' | 'layout' | 'toJSON'
|
||||
'dispose' | 'update' | 'layout' | 'toJSON' | 'focus'
|
||||
> {
|
||||
readonly element: HTMLElement;
|
||||
init(parameters: GroupPanelPartInitParameters): void;
|
||||
@ -50,12 +45,10 @@ export interface ITabRenderer
|
||||
export interface IContentRenderer
|
||||
extends Optional<
|
||||
Omit<IPanel, 'id'>,
|
||||
'dispose' | 'update' | 'layout' | 'toJSON'
|
||||
'dispose' | 'update' | 'layout' | 'toJSON' | 'focus'
|
||||
> {
|
||||
readonly element: HTMLElement;
|
||||
readonly onDidFocus?: Event<void>;
|
||||
readonly onDidBlur?: Event<void>;
|
||||
init(parameters: GroupPanelContentPartInitParameters): void;
|
||||
init(parameters: GroupPanelPartInitParameters): void;
|
||||
}
|
||||
|
||||
// watermark component
|
||||
|
6
packages/dockview-core/src/framwork.ts
Normal file
6
packages/dockview-core/src/framwork.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import { Parameters } from "./panel/types";
|
||||
|
||||
export interface PanelParameters<T extends {} = Parameters> {
|
||||
params: T;
|
||||
}
|
||||
|
@ -23,19 +23,28 @@ export {
|
||||
export * from './paneview/paneview';
|
||||
export * from './gridview/gridview';
|
||||
export { GridviewComponentOptions } from './gridview/options';
|
||||
export * from './dockview/dockviewGroupPanelModel';
|
||||
export * from './gridview/baseComponentGridview';
|
||||
|
||||
export * from './paneview/draggablePaneviewPanel';
|
||||
|
||||
export * from './dockview/components/panel/content';
|
||||
export * from './dockview/components/tab/tab';
|
||||
export * from './dockview/dockviewGroupPanelModel';
|
||||
export {
|
||||
TabDragEvent,
|
||||
GroupDragEvent,
|
||||
} from './dockview/components/titlebar/tabsContainer';
|
||||
export * from './dockview/types';
|
||||
export * from './dockview/dockviewGroupPanel';
|
||||
export {
|
||||
IGroupPanelBaseProps,
|
||||
IDockviewPanelHeaderProps,
|
||||
IDockviewPanelProps,
|
||||
IDockviewHeaderActionsProps,
|
||||
IGroupHeaderProps,
|
||||
IWatermarkPanelProps,
|
||||
DockviewReadyEvent,
|
||||
} from './dockview/framework';
|
||||
|
||||
export * from './dockview/options';
|
||||
export * from './dockview/dockviewPanel';
|
||||
|
15
packages/dockview-examples/vue-project/.eslintrc.cjs
Normal file
15
packages/dockview-examples/vue-project/.eslintrc.cjs
Normal file
@ -0,0 +1,15 @@
|
||||
/* eslint-env node */
|
||||
require('@rushstack/eslint-patch/modern-module-resolution')
|
||||
|
||||
module.exports = {
|
||||
root: true,
|
||||
'extends': [
|
||||
'plugin:vue/vue3-essential',
|
||||
'eslint:recommended',
|
||||
'@vue/eslint-config-typescript',
|
||||
'@vue/eslint-config-prettier/skip-formatting'
|
||||
],
|
||||
parserOptions: {
|
||||
ecmaVersion: 'latest'
|
||||
}
|
||||
}
|
30
packages/dockview-examples/vue-project/.gitignore
vendored
Normal file
30
packages/dockview-examples/vue-project/.gitignore
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
.DS_Store
|
||||
dist
|
||||
dist-ssr
|
||||
coverage
|
||||
*.local
|
||||
|
||||
/cypress/videos/
|
||||
/cypress/screenshots/
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
*.tsbuildinfo
|
8
packages/dockview-examples/vue-project/.prettierrc.json
Normal file
8
packages/dockview-examples/vue-project/.prettierrc.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/prettierrc",
|
||||
"semi": false,
|
||||
"tabWidth": 2,
|
||||
"singleQuote": true,
|
||||
"printWidth": 100,
|
||||
"trailingComma": "none"
|
||||
}
|
8
packages/dockview-examples/vue-project/.vscode/extensions.json
vendored
Normal file
8
packages/dockview-examples/vue-project/.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"Vue.volar",
|
||||
"Vue.vscode-typescript-vue-plugin",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"esbenp.prettier-vscode"
|
||||
]
|
||||
}
|
52
packages/dockview-examples/vue-project/README.md
Normal file
52
packages/dockview-examples/vue-project/README.md
Normal file
@ -0,0 +1,52 @@
|
||||
# vue-project
|
||||
|
||||
This template should help get you started developing with Vue 3 in Vite.
|
||||
|
||||
## Recommended IDE Setup
|
||||
|
||||
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin).
|
||||
|
||||
## Type Support for `.vue` Imports in TS
|
||||
|
||||
TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin) to make the TypeScript language service aware of `.vue` types.
|
||||
|
||||
If the standalone TypeScript plugin doesn't feel fast enough to you, Volar has also implemented a [Take Over Mode](https://github.com/johnsoncodehk/volar/discussions/471#discussioncomment-1361669) that is more performant. You can enable it by the following steps:
|
||||
|
||||
1. Disable the built-in TypeScript Extension
|
||||
1) Run `Extensions: Show Built-in Extensions` from VSCode's command palette
|
||||
2) Find `TypeScript and JavaScript Language Features`, right click and select `Disable (Workspace)`
|
||||
2. Reload the VSCode window by running `Developer: Reload Window` from the command palette.
|
||||
|
||||
## Customize configuration
|
||||
|
||||
See [Vite Configuration Reference](https://vitejs.dev/config/).
|
||||
|
||||
## Project Setup
|
||||
|
||||
```sh
|
||||
npm install
|
||||
```
|
||||
|
||||
### Compile and Hot-Reload for Development
|
||||
|
||||
```sh
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### Type-Check, Compile and Minify for Production
|
||||
|
||||
```sh
|
||||
npm run build
|
||||
```
|
||||
|
||||
### Run Unit Tests with [Vitest](https://vitest.dev/)
|
||||
|
||||
```sh
|
||||
npm run test:unit
|
||||
```
|
||||
|
||||
### Lint with [ESLint](https://eslint.org/)
|
||||
|
||||
```sh
|
||||
npm run lint
|
||||
```
|
1
packages/dockview-examples/vue-project/env.d.ts
vendored
Normal file
1
packages/dockview-examples/vue-project/env.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
/// <reference types="vite/client" />
|
13
packages/dockview-examples/vue-project/index.html
Normal file
13
packages/dockview-examples/vue-project/index.html
Normal file
@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Vite App</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
35
packages/dockview-examples/vue-project/package.json
Normal file
35
packages/dockview-examples/vue-project/package.json
Normal file
@ -0,0 +1,35 @@
|
||||
{
|
||||
"name": "vue-project",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "run-p type-check \"build-only {@}\" --",
|
||||
"preview": "vite preview",
|
||||
"test:unit": "vitest",
|
||||
"build-only": "vite build",
|
||||
"type-check": "vue-tsc --build --force",
|
||||
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
|
||||
"format": "prettier --write src/"
|
||||
},
|
||||
"dependencies": {
|
||||
"pinia": "^2.1.7",
|
||||
"vue-router": "^4.2.5",
|
||||
"dockview-vue": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rushstack/eslint-patch": "^1.3.3",
|
||||
"@tsconfig/node20": "^20.1.2",
|
||||
"@types/jsdom": "^21.1.6",
|
||||
"@types/node": "^20.11.10",
|
||||
"@vitejs/plugin-vue-jsx": "^3.1.0",
|
||||
"@vue/eslint-config-prettier": "^8.0.0",
|
||||
"@vue/eslint-config-typescript": "^12.0.0",
|
||||
"@vue/test-utils": "^2.4.4",
|
||||
"eslint-plugin-vue": "^9.17.0",
|
||||
"npm-run-all2": "^6.1.1",
|
||||
"prettier": "^3.0.3",
|
||||
"vitest": "^1.2.2"
|
||||
}
|
||||
}
|
BIN
packages/dockview-examples/vue-project/public/favicon.ico
Normal file
BIN
packages/dockview-examples/vue-project/public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
87
packages/dockview-examples/vue-project/src/App.vue
Normal file
87
packages/dockview-examples/vue-project/src/App.vue
Normal file
@ -0,0 +1,87 @@
|
||||
<script setup lang="ts">
|
||||
import { RouterLink, RouterView } from 'vue-router'
|
||||
import HelloWorld from './components/HelloWorld.vue'
|
||||
import TestView from './views/TestView.vue'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- <header>
|
||||
<img alt="Vue logo" class="logo" src="@/assets/logo.svg" width="125" height="125" />
|
||||
|
||||
<div class="wrapper">
|
||||
<HelloWorld msg="You did it!" />
|
||||
|
||||
<nav>
|
||||
<RouterLink to="/">Home</RouterLink>
|
||||
<RouterLink to="/about">About</RouterLink>
|
||||
</nav>
|
||||
</div>
|
||||
</header> -->
|
||||
|
||||
<TestView/>
|
||||
<!-- <RouterView /> -->
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
header {
|
||||
line-height: 1.5;
|
||||
max-height: 100vh;
|
||||
}
|
||||
|
||||
.logo {
|
||||
display: block;
|
||||
margin: 0 auto 2rem;
|
||||
}
|
||||
|
||||
nav {
|
||||
width: 100%;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
nav a.router-link-exact-active {
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
nav a.router-link-exact-active:hover {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
nav a {
|
||||
display: inline-block;
|
||||
padding: 0 1rem;
|
||||
border-left: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
nav a:first-of-type {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
header {
|
||||
display: flex;
|
||||
place-items: center;
|
||||
padding-right: calc(var(--section-gap) / 2);
|
||||
}
|
||||
|
||||
.logo {
|
||||
margin: 0 2rem 0 0;
|
||||
}
|
||||
|
||||
header .wrapper {
|
||||
display: flex;
|
||||
place-items: flex-start;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
nav {
|
||||
text-align: left;
|
||||
margin-left: -1rem;
|
||||
font-size: 1rem;
|
||||
|
||||
padding: 1rem 0;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
}
|
||||
</style>
|
86
packages/dockview-examples/vue-project/src/assets/base.css
Normal file
86
packages/dockview-examples/vue-project/src/assets/base.css
Normal file
@ -0,0 +1,86 @@
|
||||
/* color palette from <https://github.com/vuejs/theme> */
|
||||
:root {
|
||||
--vt-c-white: #ffffff;
|
||||
--vt-c-white-soft: #f8f8f8;
|
||||
--vt-c-white-mute: #f2f2f2;
|
||||
|
||||
--vt-c-black: #181818;
|
||||
--vt-c-black-soft: #222222;
|
||||
--vt-c-black-mute: #282828;
|
||||
|
||||
--vt-c-indigo: #2c3e50;
|
||||
|
||||
--vt-c-divider-light-1: rgba(60, 60, 60, 0.29);
|
||||
--vt-c-divider-light-2: rgba(60, 60, 60, 0.12);
|
||||
--vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);
|
||||
--vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);
|
||||
|
||||
--vt-c-text-light-1: var(--vt-c-indigo);
|
||||
--vt-c-text-light-2: rgba(60, 60, 60, 0.66);
|
||||
--vt-c-text-dark-1: var(--vt-c-white);
|
||||
--vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
|
||||
}
|
||||
|
||||
/* semantic color variables for this project */
|
||||
:root {
|
||||
--color-background: var(--vt-c-white);
|
||||
--color-background-soft: var(--vt-c-white-soft);
|
||||
--color-background-mute: var(--vt-c-white-mute);
|
||||
|
||||
--color-border: var(--vt-c-divider-light-2);
|
||||
--color-border-hover: var(--vt-c-divider-light-1);
|
||||
|
||||
--color-heading: var(--vt-c-text-light-1);
|
||||
--color-text: var(--vt-c-text-light-1);
|
||||
|
||||
--section-gap: 160px;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--color-background: var(--vt-c-black);
|
||||
--color-background-soft: var(--vt-c-black-soft);
|
||||
--color-background-mute: var(--vt-c-black-mute);
|
||||
|
||||
--color-border: var(--vt-c-divider-dark-2);
|
||||
--color-border-hover: var(--vt-c-divider-dark-1);
|
||||
|
||||
--color-heading: var(--vt-c-text-dark-1);
|
||||
--color-text: var(--vt-c-text-dark-2);
|
||||
}
|
||||
}
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
body {
|
||||
min-height: 100vh;
|
||||
color: var(--color-text);
|
||||
background: var(--color-background);
|
||||
transition:
|
||||
color 0.5s,
|
||||
background-color 0.5s;
|
||||
line-height: 1.6;
|
||||
font-family:
|
||||
Inter,
|
||||
-apple-system,
|
||||
BlinkMacSystemFont,
|
||||
'Segoe UI',
|
||||
Roboto,
|
||||
Oxygen,
|
||||
Ubuntu,
|
||||
Cantarell,
|
||||
'Fira Sans',
|
||||
'Droid Sans',
|
||||
'Helvetica Neue',
|
||||
sans-serif;
|
||||
font-size: 15px;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 261.76 226.69"><path d="M161.096.001l-30.225 52.351L100.647.001H-.005l130.877 226.688L261.749.001z" fill="#41b883"/><path d="M161.096.001l-30.225 52.351L100.647.001H52.346l78.526 136.01L209.398.001z" fill="#34495e"/></svg>
|
After Width: | Height: | Size: 276 B |
35
packages/dockview-examples/vue-project/src/assets/main.css
Normal file
35
packages/dockview-examples/vue-project/src/assets/main.css
Normal file
@ -0,0 +1,35 @@
|
||||
@import './base.css';
|
||||
|
||||
#app {
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
a,
|
||||
.green {
|
||||
text-decoration: none;
|
||||
color: hsla(160, 100%, 37%, 1);
|
||||
transition: 0.4s;
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
a:hover {
|
||||
background-color: hsla(160, 100%, 37%, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
body {
|
||||
display: flex;
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
#app {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
padding: 0 2rem;
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
<script setup lang="ts">
|
||||
defineProps<{
|
||||
msg: string
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="greetings">
|
||||
<h1 class="green">{{ msg }}</h1>
|
||||
<h3>
|
||||
You’ve successfully created a project with
|
||||
<a href="https://vitejs.dev/" target="_blank" rel="noopener">Vite</a> +
|
||||
<a href="https://vuejs.org/" target="_blank" rel="noopener">Vue 3</a>. What's next?
|
||||
</h3>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
h1 {
|
||||
font-weight: 500;
|
||||
font-size: 2.6rem;
|
||||
position: relative;
|
||||
top: -10px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.greetings h1,
|
||||
.greetings h3 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.greetings h1,
|
||||
.greetings h3 {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,88 @@
|
||||
<script setup lang="ts">
|
||||
import WelcomeItem from './WelcomeItem.vue'
|
||||
import DocumentationIcon from './icons/IconDocumentation.vue'
|
||||
import ToolingIcon from './icons/IconTooling.vue'
|
||||
import EcosystemIcon from './icons/IconEcosystem.vue'
|
||||
import CommunityIcon from './icons/IconCommunity.vue'
|
||||
import SupportIcon from './icons/IconSupport.vue'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<WelcomeItem>
|
||||
<template #icon>
|
||||
<DocumentationIcon />
|
||||
</template>
|
||||
<template #heading>Documentation</template>
|
||||
|
||||
Vue’s
|
||||
<a href="https://vuejs.org/" target="_blank" rel="noopener">official documentation</a>
|
||||
provides you with all information you need to get started.
|
||||
</WelcomeItem>
|
||||
|
||||
<WelcomeItem>
|
||||
<template #icon>
|
||||
<ToolingIcon />
|
||||
</template>
|
||||
<template #heading>Tooling</template>
|
||||
|
||||
This project is served and bundled with
|
||||
<a href="https://vitejs.dev/guide/features.html" target="_blank" rel="noopener">Vite</a>. The
|
||||
recommended IDE setup is
|
||||
<a href="https://code.visualstudio.com/" target="_blank" rel="noopener">VSCode</a> +
|
||||
<a href="https://github.com/johnsoncodehk/volar" target="_blank" rel="noopener">Volar</a>. If
|
||||
you need to test your components and web pages, check out
|
||||
<a href="https://www.cypress.io/" target="_blank" rel="noopener">Cypress</a> and
|
||||
<a href="https://on.cypress.io/component" target="_blank" rel="noopener"
|
||||
>Cypress Component Testing</a
|
||||
>.
|
||||
|
||||
<br />
|
||||
|
||||
More instructions are available in <code>README.md</code>.
|
||||
</WelcomeItem>
|
||||
|
||||
<WelcomeItem>
|
||||
<template #icon>
|
||||
<EcosystemIcon />
|
||||
</template>
|
||||
<template #heading>Ecosystem</template>
|
||||
|
||||
Get official tools and libraries for your project:
|
||||
<a href="https://pinia.vuejs.org/" target="_blank" rel="noopener">Pinia</a>,
|
||||
<a href="https://router.vuejs.org/" target="_blank" rel="noopener">Vue Router</a>,
|
||||
<a href="https://test-utils.vuejs.org/" target="_blank" rel="noopener">Vue Test Utils</a>, and
|
||||
<a href="https://github.com/vuejs/devtools" target="_blank" rel="noopener">Vue Dev Tools</a>. If
|
||||
you need more resources, we suggest paying
|
||||
<a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">Awesome Vue</a>
|
||||
a visit.
|
||||
</WelcomeItem>
|
||||
|
||||
<WelcomeItem>
|
||||
<template #icon>
|
||||
<CommunityIcon />
|
||||
</template>
|
||||
<template #heading>Community</template>
|
||||
|
||||
Got stuck? Ask your question on
|
||||
<a href="https://chat.vuejs.org" target="_blank" rel="noopener">Vue Land</a>, our official
|
||||
Discord server, or
|
||||
<a href="https://stackoverflow.com/questions/tagged/vue.js" target="_blank" rel="noopener"
|
||||
>StackOverflow</a
|
||||
>. You should also subscribe to
|
||||
<a href="https://news.vuejs.org" target="_blank" rel="noopener">our mailing list</a> and follow
|
||||
the official
|
||||
<a href="https://twitter.com/vuejs" target="_blank" rel="noopener">@vuejs</a>
|
||||
twitter account for latest news in the Vue world.
|
||||
</WelcomeItem>
|
||||
|
||||
<WelcomeItem>
|
||||
<template #icon>
|
||||
<SupportIcon />
|
||||
</template>
|
||||
<template #heading>Support Vue</template>
|
||||
|
||||
As an independent project, Vue relies on community backing for its sustainability. You can help
|
||||
us by
|
||||
<a href="https://vuejs.org/sponsor/" target="_blank" rel="noopener">becoming a sponsor</a>.
|
||||
</WelcomeItem>
|
||||
</template>
|
@ -0,0 +1,87 @@
|
||||
<template>
|
||||
<div class="item">
|
||||
<i>
|
||||
<slot name="icon"></slot>
|
||||
</i>
|
||||
<div class="details">
|
||||
<h3>
|
||||
<slot name="heading"></slot>
|
||||
</h3>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.item {
|
||||
margin-top: 2rem;
|
||||
display: flex;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.details {
|
||||
flex: 1;
|
||||
margin-left: 1rem;
|
||||
}
|
||||
|
||||
i {
|
||||
display: flex;
|
||||
place-items: center;
|
||||
place-content: center;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.2rem;
|
||||
font-weight: 500;
|
||||
margin-bottom: 0.4rem;
|
||||
color: var(--color-heading);
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.item {
|
||||
margin-top: 0;
|
||||
padding: 0.4rem 0 1rem calc(var(--section-gap) / 2);
|
||||
}
|
||||
|
||||
i {
|
||||
top: calc(50% - 25px);
|
||||
left: -26px;
|
||||
position: absolute;
|
||||
border: 1px solid var(--color-border);
|
||||
background: var(--color-background);
|
||||
border-radius: 8px;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.item:before {
|
||||
content: ' ';
|
||||
border-left: 1px solid var(--color-border);
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: calc(50% + 25px);
|
||||
height: calc(50% - 25px);
|
||||
}
|
||||
|
||||
.item:after {
|
||||
content: ' ';
|
||||
border-left: 1px solid var(--color-border);
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: calc(50% + 25px);
|
||||
height: calc(50% - 25px);
|
||||
}
|
||||
|
||||
.item:first-of-type:before {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.item:last-of-type:after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,11 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
|
||||
import { mount } from '@vue/test-utils'
|
||||
import HelloWorld from '../HelloWorld.vue'
|
||||
|
||||
describe('HelloWorld', () => {
|
||||
it('renders properly', () => {
|
||||
const wrapper = mount(HelloWorld, { props: { msg: 'Hello Vitest' } })
|
||||
expect(wrapper.text()).toContain('Hello Vitest')
|
||||
})
|
||||
})
|
@ -0,0 +1,7 @@
|
||||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor">
|
||||
<path
|
||||
d="M15 4a1 1 0 1 0 0 2V4zm0 11v-1a1 1 0 0 0-1 1h1zm0 4l-.707.707A1 1 0 0 0 16 19h-1zm-4-4l.707-.707A1 1 0 0 0 11 14v1zm-4.707-1.293a1 1 0 0 0-1.414 1.414l1.414-1.414zm-.707.707l-.707-.707.707.707zM9 11v-1a1 1 0 0 0-.707.293L9 11zm-4 0h1a1 1 0 0 0-1-1v1zm0 4H4a1 1 0 0 0 1.707.707L5 15zm10-9h2V4h-2v2zm2 0a1 1 0 0 1 1 1h2a3 3 0 0 0-3-3v2zm1 1v6h2V7h-2zm0 6a1 1 0 0 1-1 1v2a3 3 0 0 0 3-3h-2zm-1 1h-2v2h2v-2zm-3 1v4h2v-4h-2zm1.707 3.293l-4-4-1.414 1.414 4 4 1.414-1.414zM11 14H7v2h4v-2zm-4 0c-.276 0-.525-.111-.707-.293l-1.414 1.414C5.42 15.663 6.172 16 7 16v-2zm-.707 1.121l3.414-3.414-1.414-1.414-3.414 3.414 1.414 1.414zM9 12h4v-2H9v2zm4 0a3 3 0 0 0 3-3h-2a1 1 0 0 1-1 1v2zm3-3V3h-2v6h2zm0-6a3 3 0 0 0-3-3v2a1 1 0 0 1 1 1h2zm-3-3H3v2h10V0zM3 0a3 3 0 0 0-3 3h2a1 1 0 0 1 1-1V0zM0 3v6h2V3H0zm0 6a3 3 0 0 0 3 3v-2a1 1 0 0 1-1-1H0zm3 3h2v-2H3v2zm1-1v4h2v-4H4zm1.707 4.707l.586-.586-1.414-1.414-.586.586 1.414 1.414z"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
@ -0,0 +1,7 @@
|
||||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="17" fill="currentColor">
|
||||
<path
|
||||
d="M11 2.253a1 1 0 1 0-2 0h2zm-2 13a1 1 0 1 0 2 0H9zm.447-12.167a1 1 0 1 0 1.107-1.666L9.447 3.086zM1 2.253L.447 1.42A1 1 0 0 0 0 2.253h1zm0 13H0a1 1 0 0 0 1.553.833L1 15.253zm8.447.833a1 1 0 1 0 1.107-1.666l-1.107 1.666zm0-14.666a1 1 0 1 0 1.107 1.666L9.447 1.42zM19 2.253h1a1 1 0 0 0-.447-.833L19 2.253zm0 13l-.553.833A1 1 0 0 0 20 15.253h-1zm-9.553-.833a1 1 0 1 0 1.107 1.666L9.447 14.42zM9 2.253v13h2v-13H9zm1.553-.833C9.203.523 7.42 0 5.5 0v2c1.572 0 2.961.431 3.947 1.086l1.107-1.666zM5.5 0C3.58 0 1.797.523.447 1.42l1.107 1.666C2.539 2.431 3.928 2 5.5 2V0zM0 2.253v13h2v-13H0zm1.553 13.833C2.539 15.431 3.928 15 5.5 15v-2c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM5.5 15c1.572 0 2.961.431 3.947 1.086l1.107-1.666C9.203 13.523 7.42 13 5.5 13v2zm5.053-11.914C11.539 2.431 12.928 2 14.5 2V0c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM14.5 2c1.573 0 2.961.431 3.947 1.086l1.107-1.666C18.203.523 16.421 0 14.5 0v2zm3.5.253v13h2v-13h-2zm1.553 12.167C18.203 13.523 16.421 13 14.5 13v2c1.573 0 2.961.431 3.947 1.086l1.107-1.666zM14.5 13c-1.92 0-3.703.523-5.053 1.42l1.107 1.666C11.539 15.431 12.928 15 14.5 15v-2z"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
@ -0,0 +1,7 @@
|
||||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="20" fill="currentColor">
|
||||
<path
|
||||
d="M11.447 8.894a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm0 1.789a1 1 0 1 0 .894-1.789l-.894 1.789zM7.447 7.106a1 1 0 1 0-.894 1.789l.894-1.789zM10 9a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0H8zm9.447-5.606a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm2 .789a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zM18 5a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0h-2zm-5.447-4.606a1 1 0 1 0 .894-1.789l-.894 1.789zM9 1l.447-.894a1 1 0 0 0-.894 0L9 1zm-2.447.106a1 1 0 1 0 .894 1.789l-.894-1.789zm-6 3a1 1 0 1 0 .894 1.789L.553 4.106zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zm-2-.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 2.789a1 1 0 1 0 .894-1.789l-.894 1.789zM2 5a1 1 0 1 0-2 0h2zM0 7.5a1 1 0 1 0 2 0H0zm8.553 12.394a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 1a1 1 0 1 0 .894 1.789l-.894-1.789zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zM8 19a1 1 0 1 0 2 0H8zm2-2.5a1 1 0 1 0-2 0h2zm-7.447.394a1 1 0 1 0 .894-1.789l-.894 1.789zM1 15H0a1 1 0 0 0 .553.894L1 15zm1-2.5a1 1 0 1 0-2 0h2zm12.553 2.606a1 1 0 1 0 .894 1.789l-.894-1.789zM17 15l.447.894A1 1 0 0 0 18 15h-1zm1-2.5a1 1 0 1 0-2 0h2zm-7.447-5.394l-2 1 .894 1.789 2-1-.894-1.789zm-1.106 1l-2-1-.894 1.789 2 1 .894-1.789zM8 9v2.5h2V9H8zm8.553-4.894l-2 1 .894 1.789 2-1-.894-1.789zm.894 0l-2-1-.894 1.789 2 1 .894-1.789zM16 5v2.5h2V5h-2zm-4.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zm-2.894-1l-2 1 .894 1.789 2-1L8.553.106zM1.447 5.894l2-1-.894-1.789-2 1 .894 1.789zm-.894 0l2 1 .894-1.789-2-1-.894 1.789zM0 5v2.5h2V5H0zm9.447 13.106l-2-1-.894 1.789 2 1 .894-1.789zm0 1.789l2-1-.894-1.789-2 1 .894 1.789zM10 19v-2.5H8V19h2zm-6.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zM2 15v-2.5H0V15h2zm13.447 1.894l2-1-.894-1.789-2 1 .894 1.789zM18 15v-2.5h-2V15h2z"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
@ -0,0 +1,7 @@
|
||||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor">
|
||||
<path
|
||||
d="M10 3.22l-.61-.6a5.5 5.5 0 0 0-7.666.105 5.5 5.5 0 0 0-.114 7.665L10 18.78l8.39-8.4a5.5 5.5 0 0 0-.114-7.665 5.5 5.5 0 0 0-7.666-.105l-.61.61z"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
@ -0,0 +1,19 @@
|
||||
<!-- This icon is from <https://github.com/Templarian/MaterialDesign>, distributed under Apache 2.0 (https://www.apache.org/licenses/LICENSE-2.0) license-->
|
||||
<template>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
aria-hidden="true"
|
||||
role="img"
|
||||
class="iconify iconify--mdi"
|
||||
width="24"
|
||||
height="24"
|
||||
preserveAspectRatio="xMidYMid meet"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M20 18v-4h-3v1h-2v-1H9v1H7v-1H4v4h16M6.33 8l-1.74 4H7v-1h2v1h6v-1h2v1h2.41l-1.74-4H6.33M9 5v1h6V5H9m12.84 7.61c.1.22.16.48.16.8V18c0 .53-.21 1-.6 1.41c-.4.4-.85.59-1.4.59H4c-.55 0-1-.19-1.4-.59C2.21 19 2 18.53 2 18v-4.59c0-.32.06-.58.16-.8L4.5 7.22C4.84 6.41 5.45 6 6.33 6H7V5c0-.55.18-1 .57-1.41C7.96 3.2 8.44 3 9 3h6c.56 0 1.04.2 1.43.59c.39.41.57.86.57 1.41v1h.67c.88 0 1.49.41 1.83 1.22l2.34 5.39z"
|
||||
fill="currentColor"
|
||||
></path>
|
||||
</svg>
|
||||
</template>
|
@ -0,0 +1,121 @@
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
DockviewApi,
|
||||
DockviewComponent,
|
||||
type DockviewDndOverlayEvent,
|
||||
type DockviewPanelRenderer,
|
||||
type DroptargetOverlayModel,
|
||||
type IContentRenderer,
|
||||
type ITabRenderer,
|
||||
type IWatermarkRenderer
|
||||
} from 'dockview-core'
|
||||
import { ref, onMounted, watch, onBeforeUnmount } from 'vue'
|
||||
import {
|
||||
VueContentRenderer,
|
||||
VueTabRenderer,
|
||||
VueWatermarkRenderer,
|
||||
type ComponentInterface
|
||||
} from './utils'
|
||||
|
||||
interface Props {
|
||||
// onReady: (event: DockviewReadyEvent) => void;
|
||||
components: Record<string, any>
|
||||
tabComponents?: Record<string, any>
|
||||
// watermarkComponent?: React.FunctionComponent<IWatermarkPanelProps>;
|
||||
// onDidDrop?: (event: DockviewDidDropEvent) => void;
|
||||
// onWillDrop?: (event: DockviewWillDropEvent) => void;
|
||||
// showDndOverlay?: (event: DockviewDndOverlayEvent) => boolean;
|
||||
hideBorders?: boolean;
|
||||
className?: string;
|
||||
disableAutoResizing?: boolean;
|
||||
// defaultTabComponent?: React.FunctionComponent<IDockviewPanelHeaderProps>;
|
||||
// rightHeaderActionsComponent?: React.FunctionComponent<IDockviewHeaderActionsProps>;
|
||||
// leftHeaderActionsComponent?: React.FunctionComponent<IDockviewHeaderActionsProps>;
|
||||
// prefixHeaderActionsComponent?: React.FunctionComponent<IDockviewHeaderActionsProps>;
|
||||
singleTabMode?: 'fullwidth' | 'default';
|
||||
disableFloatingGroups?: boolean;
|
||||
floatingGroupBounds?:
|
||||
| 'boundedWithinViewport'
|
||||
| {
|
||||
minimumHeightWithinViewport?: number;
|
||||
minimumWidthWithinViewport?: number;
|
||||
};
|
||||
debug?: boolean;
|
||||
defaultRenderer?: DockviewPanelRenderer;
|
||||
rootOverlayModel?: DroptargetOverlayModel
|
||||
locked?: boolean;
|
||||
disableDnd?: boolean;
|
||||
}
|
||||
|
||||
interface Emits {
|
||||
(event: 'ready', value: { api: DockviewApi }): void
|
||||
(event: 'showDndOverlay', value: DockviewDndOverlayEvent):void
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
|
||||
const emit = defineEmits<Emits>()
|
||||
|
||||
const el = ref<HTMLElement | null>(null)
|
||||
const instance = ref<DockviewComponent | null>(null)
|
||||
|
||||
watch(() => props.components, (newValue, oldValue) => {
|
||||
if (instance.value) {
|
||||
instance.value.updateOptions({ components: newValue })
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
if (!el.value) {
|
||||
throw new Error('element is not mounted')
|
||||
}
|
||||
|
||||
const dockview = new DockviewComponent({
|
||||
parentElement: el.value,
|
||||
frameworkComponentFactory: {
|
||||
content: {
|
||||
createComponent: (id: string, componentId: string, component: any): IContentRenderer => {
|
||||
console.log('dockview-vue: createComponent')
|
||||
|
||||
return new VueContentRenderer(component as ComponentInterface)
|
||||
}
|
||||
},
|
||||
tab: {
|
||||
createComponent: (id: string, componentId: string, component: any): ITabRenderer => {
|
||||
return new VueTabRenderer(component as ComponentInterface)
|
||||
}
|
||||
},
|
||||
watermark: {
|
||||
createComponent: (id: string, componentId: string, component: any): IWatermarkRenderer => {
|
||||
return new VueWatermarkRenderer(component as ComponentInterface)
|
||||
}
|
||||
}
|
||||
},
|
||||
frameworkComponents: props.components,
|
||||
disableAutoResizing: props.disableAutoResizing,
|
||||
frameworkTabComponents: props.tabComponents,
|
||||
singleTabMode: props.singleTabMode,
|
||||
disableFloatingGroups: props.disableFloatingGroups,
|
||||
floatingGroupBounds: props.floatingGroupBounds,
|
||||
defaultRenderer: props.defaultRenderer,
|
||||
debug: props.debug,
|
||||
rootOverlayModel: props.rootOverlayModel,
|
||||
locked: props.locked,
|
||||
disableDnd: props.disableDnd,
|
||||
})
|
||||
|
||||
instance.value = dockview
|
||||
emit("ready", { api: new DockviewApi(dockview) })
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (instance.value) {
|
||||
instance.value.dispose()
|
||||
}
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="el" />
|
||||
</template>
|
@ -0,0 +1,127 @@
|
||||
import { defineComponent, h, type ComponentOptionsBase, type PropType } from 'vue'
|
||||
import {
|
||||
DockviewComponent,
|
||||
DockviewApi,
|
||||
type IContentRenderer,
|
||||
type ITabRenderer,
|
||||
type IWatermarkRenderer
|
||||
} from 'dockview-core'
|
||||
import { VueContentRenderer, VueTabRenderer, VueWatermarkRenderer } from './utils'
|
||||
|
||||
type ComponentInterface = ComponentOptionsBase<any, any, any, any, any, any, any, any>
|
||||
|
||||
export interface DockviewReadyEvent {
|
||||
api: DockviewApi
|
||||
}
|
||||
|
||||
export type DVProps = {
|
||||
readonly components: { [index: string]: any }
|
||||
readonly tabComponents?: { [index: string]: any }
|
||||
}
|
||||
|
||||
export type DVEmits = {
|
||||
onReady(event: { api: DockviewApi }): void
|
||||
}
|
||||
|
||||
type RawBindings = {}
|
||||
|
||||
// function mountComponent() {
|
||||
// createVNode()
|
||||
// }
|
||||
|
||||
export default defineComponent(
|
||||
// <DVProps, RawBindings, {}, {}, {}, {}, {}, DVEmits>
|
||||
{
|
||||
props: {
|
||||
components: {
|
||||
type: Object as PropType<{ [index: string]: any }>,
|
||||
required: true
|
||||
},
|
||||
tabComponents: Object as PropType<{ [index: string]: any }>
|
||||
},
|
||||
// type inference enabled
|
||||
render() {
|
||||
return h('div')
|
||||
},
|
||||
methods: {},
|
||||
// setup(props, ctx) {
|
||||
// // called once
|
||||
// // return () => {
|
||||
// // // called on re-render
|
||||
// // }
|
||||
// },
|
||||
data() {
|
||||
return {
|
||||
count: 1
|
||||
}
|
||||
},
|
||||
setup(props, ctx) {
|
||||
// getCurrentInstance()
|
||||
// console.log('props', props.keyA)
|
||||
// watch(
|
||||
// () => props.keyA,
|
||||
// (a, b) => {
|
||||
// console.log('asaa')
|
||||
// }
|
||||
// )
|
||||
},
|
||||
watch: {
|
||||
props: {
|
||||
handler(a, b) {
|
||||
console.log('a,b')
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
const element = this.$el as HTMLElement
|
||||
|
||||
this.$props.components
|
||||
|
||||
console.log('dockview-vue: mounted vue wrapper', this.$props.components)
|
||||
|
||||
const instance = new DockviewComponent({
|
||||
parentElement: element,
|
||||
frameworkComponents: this.$props.components,
|
||||
frameworkComponentFactory: {
|
||||
content: {
|
||||
createComponent: (
|
||||
id: string,
|
||||
componentId: string,
|
||||
component: any
|
||||
): IContentRenderer => {
|
||||
console.log('dockview-vue: createComponent', this.$props.components)
|
||||
|
||||
return new VueContentRenderer(component as ComponentInterface)
|
||||
}
|
||||
},
|
||||
tab: {
|
||||
createComponent: (id: string, componentId: string, component: any): ITabRenderer => {
|
||||
return new VueTabRenderer(component as ComponentInterface)
|
||||
}
|
||||
},
|
||||
watermark: {
|
||||
createComponent: (
|
||||
id: string,
|
||||
componentId: string,
|
||||
component: any
|
||||
): IWatermarkRenderer => {
|
||||
return new VueWatermarkRenderer(component as ComponentInterface)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const api = new DockviewApi(instance)
|
||||
|
||||
|
||||
|
||||
this.$emit('ready', { api });
|
||||
|
||||
// this.$emit('')
|
||||
|
||||
// this.name // type: string | undefined
|
||||
// this.msg // type: string
|
||||
// this.count // type: number
|
||||
}
|
||||
}
|
||||
)
|
151
packages/dockview-examples/vue-project/src/dockview-vue/utils.ts
Normal file
151
packages/dockview-examples/vue-project/src/dockview-vue/utils.ts
Normal file
@ -0,0 +1,151 @@
|
||||
import type {
|
||||
DockviewGroupPanel,
|
||||
GroupPanelPartInitParameters,
|
||||
IContentRenderer,
|
||||
ITabRenderer,
|
||||
IWatermarkRenderer,
|
||||
PanelUpdateEvent,
|
||||
Parameters,
|
||||
WatermarkRendererInitParameters
|
||||
} from 'dockview-core'
|
||||
import { createVNode, type ComponentOptionsBase, render, cloneVNode, mergeProps } from 'vue'
|
||||
|
||||
export type ComponentInterface = ComponentOptionsBase<any, any, any, any, any, any, any, any>
|
||||
|
||||
/**
|
||||
* TODO List
|
||||
*
|
||||
* 1. handle vue context-ish stuff (appContext? provides?)
|
||||
*
|
||||
*
|
||||
*
|
||||
* @see https://vuejs.org/api/render-function.html#clonevnode
|
||||
* @see https://vuejs.org/api/render-function.html#mergeprops
|
||||
*/
|
||||
export function mountVueComponent(component: ComponentInterface, props: any, element: HTMLElement) {
|
||||
let vNode = createVNode(component, props)
|
||||
|
||||
render(vNode, element)
|
||||
|
||||
return {
|
||||
update: (newProps: any) => {
|
||||
vNode = cloneVNode(vNode, mergeProps(props, newProps))
|
||||
render(vNode, element)
|
||||
},
|
||||
dispose: () => {
|
||||
render(null, element)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class VueContentRenderer implements IContentRenderer {
|
||||
private _element: HTMLElement
|
||||
private _renderDisposable: { update: (props: any) => void; dispose: () => void } | undefined
|
||||
|
||||
get element(): HTMLElement {
|
||||
return this._element
|
||||
}
|
||||
|
||||
constructor(private readonly component: ComponentInterface) {
|
||||
this._element = document.createElement('div')
|
||||
this.element.className = 'dv-vue-part'
|
||||
}
|
||||
|
||||
init(parameters: GroupPanelPartInitParameters): void {
|
||||
const props = {
|
||||
params: parameters.params,
|
||||
api: parameters.api,
|
||||
containerApi: parameters.containerApi
|
||||
}
|
||||
|
||||
this._renderDisposable?.dispose()
|
||||
this._renderDisposable = mountVueComponent(this.component, props, this.element)
|
||||
}
|
||||
|
||||
update(event: PanelUpdateEvent<Parameters>): void {
|
||||
const params = event.params
|
||||
// TODO: handle prop updates somehow?
|
||||
this._renderDisposable?.update(params)
|
||||
}
|
||||
|
||||
focus(): void {
|
||||
// TODO: make optional on interface
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._renderDisposable?.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
export class VueTabRenderer implements ITabRenderer {
|
||||
private _element: HTMLElement
|
||||
private _renderDisposable: { update: (props: any) => void; dispose: () => void } | undefined
|
||||
|
||||
get element(): HTMLElement {
|
||||
return this._element
|
||||
}
|
||||
|
||||
constructor(private readonly component: ComponentInterface) {
|
||||
this._element = document.createElement('div')
|
||||
this.element.className = 'dv-vue-part'
|
||||
}
|
||||
|
||||
init(parameters: GroupPanelPartInitParameters): void {
|
||||
const props = {
|
||||
params: parameters.params,
|
||||
api: parameters.api,
|
||||
containerApi: parameters.containerApi
|
||||
}
|
||||
|
||||
this._renderDisposable?.dispose()
|
||||
this._renderDisposable = mountVueComponent(this.component, props, this.element)
|
||||
}
|
||||
|
||||
update(event: PanelUpdateEvent<Parameters>): void {
|
||||
const params = event.params
|
||||
// TODO: handle prop updates somehow?
|
||||
this._renderDisposable?.update(params)
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._renderDisposable?.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
export class VueWatermarkRenderer implements IWatermarkRenderer {
|
||||
private _element: HTMLElement
|
||||
private _renderDisposable: { update: (props: any) => void; dispose: () => void } | undefined
|
||||
|
||||
get element(): HTMLElement {
|
||||
return this._element
|
||||
}
|
||||
|
||||
constructor(private readonly component: ComponentInterface) {
|
||||
this._element = document.createElement('div')
|
||||
this.element.className = 'dv-vue-part'
|
||||
}
|
||||
|
||||
init(parameters: WatermarkRendererInitParameters): void {
|
||||
const props = {
|
||||
group: parameters.group,
|
||||
containerApi: parameters.containerApi
|
||||
}
|
||||
|
||||
this._renderDisposable?.dispose()
|
||||
this._renderDisposable = mountVueComponent(this.component, props, this.element)
|
||||
}
|
||||
|
||||
updateParentGroup(group: DockviewGroupPanel, visible: boolean): void {
|
||||
// TODO: make optional on interface
|
||||
}
|
||||
|
||||
update(event: PanelUpdateEvent<Parameters>): void {
|
||||
const params = event.params
|
||||
// TODO: handle prop updates somehow?
|
||||
this._renderDisposable?.update(params)
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._renderDisposable?.dispose()
|
||||
}
|
||||
}
|
14
packages/dockview-examples/vue-project/src/main.ts
Normal file
14
packages/dockview-examples/vue-project/src/main.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import './assets/main.css'
|
||||
|
||||
import { createApp } from 'vue'
|
||||
import { createPinia } from 'pinia'
|
||||
|
||||
import App from './App.vue'
|
||||
import router from './router'
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
app.use(createPinia())
|
||||
app.use(router)
|
||||
|
||||
app.mount('#app')
|
23
packages/dockview-examples/vue-project/src/router/index.ts
Normal file
23
packages/dockview-examples/vue-project/src/router/index.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import HomeView from '../views/HomeView.vue'
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
routes: [
|
||||
{
|
||||
path: '/',
|
||||
name: 'home',
|
||||
component: HomeView
|
||||
},
|
||||
{
|
||||
path: '/about',
|
||||
name: 'about',
|
||||
// route level code-splitting
|
||||
// this generates a separate chunk (About.[hash].js) for this route
|
||||
// which is lazy-loaded when the route is visited.
|
||||
component: () => import('../views/AboutView.vue')
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
export default router
|
12
packages/dockview-examples/vue-project/src/stores/counter.ts
Normal file
12
packages/dockview-examples/vue-project/src/stores/counter.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { ref, computed } from 'vue'
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
export const useCounterStore = defineStore('counter', () => {
|
||||
const count = ref(0)
|
||||
const doubleCount = computed(() => count.value * 2)
|
||||
function increment() {
|
||||
count.value++
|
||||
}
|
||||
|
||||
return { count, doubleCount, increment }
|
||||
})
|
@ -0,0 +1,15 @@
|
||||
<template>
|
||||
<div class="about">
|
||||
<h1>This is an about page</h1>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
@media (min-width: 1024px) {
|
||||
.about {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
defineEmits({});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<main>
|
||||
<div>hi</div>
|
||||
</main>
|
||||
</template>
|
@ -0,0 +1,26 @@
|
||||
<script setup lang="ts">
|
||||
import type { DockviewApi, DockviewPanelApi } from 'dockview-core';
|
||||
import { ref, watch } from 'vue';
|
||||
|
||||
const props = defineProps<{api: DockviewPanelApi, containerApi: DockviewApi, params:{ time:number}}>();
|
||||
|
||||
console.log(props.api, props.containerApi, props.params);
|
||||
|
||||
const params = ref(props.params)
|
||||
|
||||
watch(() => props.params,(a,b) => {
|
||||
console.log("watch",a,b);
|
||||
params.value = b
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<main>
|
||||
<div>hi</div>
|
||||
<div>{{ params.time }}</div>
|
||||
</main>
|
||||
</template>
|
@ -0,0 +1,12 @@
|
||||
<script setup lang="ts">
|
||||
import type { DockviewApi, DockviewPanelApi } from 'dockview-core';
|
||||
|
||||
const props = defineProps<{api: DockviewPanelApi, containerApi: DockviewApi, params:{ time:number}}>();
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div style="width:100px;height:100%">
|
||||
<div>hi</div>
|
||||
</div>
|
||||
</template>
|
@ -0,0 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import TheWelcome from '../components/TheWelcome.vue'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<main>
|
||||
<TheWelcome />
|
||||
</main>
|
||||
</template>
|
@ -0,0 +1,20 @@
|
||||
<script setup lang="ts">
|
||||
import TestComponent from './testComponent.vue';
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="about">
|
||||
<h1>This is a test page</h1>
|
||||
<TestComponent/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
@media (min-width: 1024px) {
|
||||
.about {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,70 @@
|
||||
|
||||
<script>
|
||||
import { defineComponent,ref } from 'vue'
|
||||
// import DockviewVue from '../dockview-vue/dockviewVue';
|
||||
import {DockviewVue} from 'dockview-vue';
|
||||
import DefaultPanel from "./DefaultPanel.vue";
|
||||
import AnotherPanel from "./AnotherPanel.vue"
|
||||
import HeaderPanel from './HeaderPanel.vue';
|
||||
|
||||
// import {AgGridVue} from "ag-grid-vue3"
|
||||
|
||||
|
||||
import "dockview-core/dist/styles/dockview.css";
|
||||
|
||||
|
||||
export default defineComponent({
|
||||
// type inference enabled
|
||||
props: {
|
||||
// name: String,
|
||||
// msg: { type: String, required: true }
|
||||
},
|
||||
// data() {
|
||||
// return {
|
||||
// // valueA: "something"
|
||||
// }
|
||||
// },
|
||||
components: {
|
||||
"dockview-vue": DockviewVue
|
||||
},
|
||||
methods: {
|
||||
onReady: (params) => {
|
||||
console.log('api ready',params);
|
||||
|
||||
const panel1 = params.api.addPanel({
|
||||
id:'panel_1',
|
||||
component:"default"
|
||||
});
|
||||
|
||||
setInterval(() => {
|
||||
panel1.api.updateParameters({time: Date.now()});
|
||||
}, 5000)
|
||||
|
||||
params.api.addPanel({
|
||||
id:'panel_2',
|
||||
component:"default"
|
||||
});
|
||||
}
|
||||
},
|
||||
setup(props,ctx) {
|
||||
|
||||
return {
|
||||
components: {default:DefaultPanel, another:AnotherPanel},
|
||||
headerPanel:HeaderPanel
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>hello world</div>
|
||||
<div>{{ valueA }}</div>
|
||||
<dockview-vue
|
||||
style="width:100%; height:100%"
|
||||
class="dockview-theme-abyss"
|
||||
:components="components"
|
||||
:rightHeaderActionsComponent="headerPanel"
|
||||
@ready="onReady"
|
||||
/>
|
||||
</template>
|
||||
|
14
packages/dockview-examples/vue-project/tsconfig.app.json
Normal file
14
packages/dockview-examples/vue-project/tsconfig.app.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"extends": "@vue/tsconfig/tsconfig.dom.json",
|
||||
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
|
||||
"exclude": ["src/**/__tests__/*"],
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
}
|
||||
}
|
14
packages/dockview-examples/vue-project/tsconfig.json
Normal file
14
packages/dockview-examples/vue-project/tsconfig.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"files": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.node.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.app.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.vitest.json"
|
||||
}
|
||||
]
|
||||
}
|
19
packages/dockview-examples/vue-project/tsconfig.node.json
Normal file
19
packages/dockview-examples/vue-project/tsconfig.node.json
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"extends": "@tsconfig/node20/tsconfig.json",
|
||||
"include": [
|
||||
"vite.config.*",
|
||||
"vitest.config.*",
|
||||
"cypress.config.*",
|
||||
"nightwatch.conf.*",
|
||||
"playwright.config.*"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"noEmit": true,
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
||||
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Bundler",
|
||||
"types": ["node"]
|
||||
}
|
||||
}
|
11
packages/dockview-examples/vue-project/tsconfig.vitest.json
Normal file
11
packages/dockview-examples/vue-project/tsconfig.vitest.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"extends": "./tsconfig.app.json",
|
||||
"exclude": [],
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.vitest.tsbuildinfo",
|
||||
|
||||
"lib": [],
|
||||
"types": ["node", "jsdom"]
|
||||
}
|
||||
}
|
18
packages/dockview-examples/vue-project/vite.config.ts
Normal file
18
packages/dockview-examples/vue-project/vite.config.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { fileURLToPath, URL } from 'node:url'
|
||||
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import vueJsx from '@vitejs/plugin-vue-jsx'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
vue(),
|
||||
vueJsx(),
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': fileURLToPath(new URL('./src', import.meta.url))
|
||||
}
|
||||
}
|
||||
})
|
14
packages/dockview-examples/vue-project/vitest.config.ts
Normal file
14
packages/dockview-examples/vue-project/vitest.config.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { mergeConfig, defineConfig, configDefaults } from 'vitest/config'
|
||||
import viteConfig from './vite.config'
|
||||
|
||||
export default mergeConfig(
|
||||
viteConfig,
|
||||
defineConfig({
|
||||
test: {
|
||||
environment: 'jsdom',
|
||||
exclude: [...configDefaults.exclude, 'e2e/*'],
|
||||
root: fileURLToPath(new URL('./', import.meta.url))
|
||||
}
|
||||
})
|
||||
)
|
2128
packages/dockview-examples/vue-project/yarn.lock
Normal file
2128
packages/dockview-examples/vue-project/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
56
packages/dockview-react/README.md
Normal file
56
packages/dockview-react/README.md
Normal file
@ -0,0 +1,56 @@
|
||||
<div align="center">
|
||||
<h1>dockview</h1>
|
||||
|
||||
<p>Zero dependency layout manager supporting tabs, groups, grids and splitviews with ReactJS support written in TypeScript</p>
|
||||
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
[![npm version](https://badge.fury.io/js/dockview.svg)](https://www.npmjs.com/package/dockview)
|
||||
[![npm](https://img.shields.io/npm/dm/dockview)](https://www.npmjs.com/package/dockview)
|
||||
[![CI Build](https://github.com/mathuo/dockview/workflows/CI/badge.svg)](https://github.com/mathuo/dockview/actions?query=workflow%3ACI)
|
||||
[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=mathuo_dockview&metric=coverage)](https://sonarcloud.io/summary/overall?id=mathuo_dockview)
|
||||
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=mathuo_dockview&metric=alert_status)](https://sonarcloud.io/summary/overall?id=mathuo_dockview)
|
||||
[![Bundle Phobia](https://badgen.net/bundlephobia/minzip/dockview)](https://bundlephobia.com/result?p=dockview)
|
||||
|
||||
##
|
||||
|
||||
Please see the website: https://dockview.dev
|
||||
|
||||
## Features
|
||||
|
||||
- Serialization / deserialization with full layout management
|
||||
- Support for split-views, grid-views and 'dockable' views
|
||||
- Themeable and customizable
|
||||
- Tab and Group docking / Drag n' Drop
|
||||
- Popout Windows
|
||||
- Floating Groups
|
||||
- Extensive API
|
||||
- Supports Shadow DOMs
|
||||
- High test coverage
|
||||
- Documentation website with live examples
|
||||
- Transparent builds and Code Analysis
|
||||
- Security at mind - verifed publishing and builds through GitHub Actions
|
||||
|
||||
Want to verify our builds? Go [here](https://www.npmjs.com/package/dockview#Provenance).
|
||||
|
||||
## Quick start
|
||||
|
||||
Dockview has a peer dependency on `react >= 16.8.0` and `react-dom >= 16.8.0`. You can install dockview from [npm](https://www.npmjs.com/package/dockview).
|
||||
|
||||
```
|
||||
npm install --save dockview
|
||||
```
|
||||
|
||||
Within your project you must import or reference the stylesheet at `dockview/dist/styles/dockview.css` and attach a theme.
|
||||
|
||||
```css
|
||||
@import '~dockview/dist/styles/dockview.css';
|
||||
```
|
||||
|
||||
You should also attach a dockview theme to an element containing your components. For example:
|
||||
|
||||
```html
|
||||
<body classname="dockview-theme-dark"></body>
|
||||
```
|
6
packages/dockview-react/gulpfile.js
Normal file
6
packages/dockview-react/gulpfile.js
Normal file
@ -0,0 +1,6 @@
|
||||
const gulp = require('gulp');
|
||||
const buildfile = require('../../scripts/build');
|
||||
|
||||
buildfile.init();
|
||||
|
||||
gulp.task('run', gulp.series(['sass']));
|
34
packages/dockview-react/jest.config.ts
Normal file
34
packages/dockview-react/jest.config.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import { JestConfigWithTsJest } from 'ts-jest';
|
||||
|
||||
const config: JestConfigWithTsJest = {
|
||||
preset: 'ts-jest',
|
||||
roots: ['<rootDir>/packages/dockview-react'],
|
||||
modulePaths: ['<rootDir>/packages/dockview-react/src'],
|
||||
displayName: { name: 'dockview', color: 'blue' },
|
||||
rootDir: '../../',
|
||||
collectCoverageFrom: [
|
||||
'<rootDir>/packages/dockview-react/src/**/*.{js,jsx,ts,tsx}',
|
||||
],
|
||||
setupFiles: [
|
||||
// '<rootDir>/packages/dockview-react/src/__tests__/__mocks__/resizeObserver.js',
|
||||
],
|
||||
setupFilesAfterEnv: ['<rootDir>/jest-setup.ts'],
|
||||
coveragePathIgnorePatterns: ['/node_modules/'],
|
||||
modulePathIgnorePatterns: [
|
||||
// '<rootDir>/packages/dockview-react/src/__tests__/__mocks__',
|
||||
// '<rootDir>/packages/dockview-react/src/__tests__/__test_utils__',
|
||||
],
|
||||
coverageDirectory: '<rootDir>/packages/dockview-react/coverage/',
|
||||
testResultsProcessor: 'jest-sonar-reporter',
|
||||
testEnvironment: 'jsdom',
|
||||
transform: {
|
||||
'^.+\\.tsx?$': [
|
||||
'ts-jest',
|
||||
{
|
||||
tsconfig: '<rootDir>/tsconfig.test.json',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
59
packages/dockview-react/package.json
Normal file
59
packages/dockview-react/package.json
Normal file
@ -0,0 +1,59 @@
|
||||
{
|
||||
"name": "dockview-react",
|
||||
"version": "0.0.0-beta-0",
|
||||
"description": "Zero dependency layout manager supporting tabs, grids and splitviews with ReactJS support",
|
||||
"keywords": [
|
||||
"splitview",
|
||||
"split-view",
|
||||
"gridview",
|
||||
"grid-view",
|
||||
"dockview",
|
||||
"dock-view",
|
||||
"grid",
|
||||
"tabs",
|
||||
"layout",
|
||||
"layout manager",
|
||||
"dock layout",
|
||||
"dock",
|
||||
"docking",
|
||||
"splitter",
|
||||
"drag-and-drop",
|
||||
"drag",
|
||||
"drop",
|
||||
"react",
|
||||
"react-component"
|
||||
],
|
||||
"homepage": "https://github.com/mathuo/dockview",
|
||||
"bugs": {
|
||||
"url": "https://github.com/mathuo/dockview/issues"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mathuo/dockview.git"
|
||||
},
|
||||
"license": "MIT",
|
||||
"author": "https://github.com/mathuo",
|
||||
"main": "./dist/cjs/index.js",
|
||||
"module": "./dist/esm/index.js",
|
||||
"types": "./dist/cjs/index.d.ts",
|
||||
"files": [
|
||||
"dist",
|
||||
"README.md"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "npm run build:package && npm run build:bundles",
|
||||
"build:bundles": "rollup -c",
|
||||
"build:cjs": "cross-env ../../node_modules/.bin/tsc --build ./tsconfig.json --verbose --extendedDiagnostics",
|
||||
"build:css": "gulp sass",
|
||||
"build:esm": "cross-env ../../node_modules/.bin/tsc --build ./tsconfig.esm.json --verbose --extendedDiagnostics",
|
||||
"build:package": "npm run build:cjs && npm run build:esm && npm run build:css",
|
||||
"clean": "rimraf dist/ .build/ .rollup.cache/",
|
||||
"prepublishOnly": "npm run rebuild && npm run test",
|
||||
"rebuild": "npm run clean && npm run build",
|
||||
"test": "cross-env ../../node_modules/.bin/jest --selectProjects dockview",
|
||||
"test:cov": "cross-env ../../node_modules/.bin/jest --selectProjects dockview --coverage"
|
||||
},
|
||||
"dependencies": {
|
||||
"dockview": "^1.10.1"
|
||||
}
|
||||
}
|
113
packages/dockview-react/rollup.config.js
Normal file
113
packages/dockview-react/rollup.config.js
Normal file
@ -0,0 +1,113 @@
|
||||
/* eslint-disable */
|
||||
|
||||
const { join } = require('path');
|
||||
const typescript = require('@rollup/plugin-typescript');
|
||||
const terser = require('@rollup/plugin-terser');
|
||||
const postcss = require('rollup-plugin-postcss');
|
||||
const nodeResolve = require('@rollup/plugin-node-resolve');
|
||||
|
||||
const { name, version, homepage, license } = require('./package.json');
|
||||
const main = join(__dirname, './scripts/rollupEntryTarget.ts');
|
||||
const mainNoStyles = join(__dirname, './src/index.ts');
|
||||
const outputDir = join(__dirname, 'dist');
|
||||
|
||||
function outputFile(format, isMinified, withStyles) {
|
||||
let filename = join(outputDir, name);
|
||||
|
||||
if (format !== 'umd') {
|
||||
filename += `.${format}`;
|
||||
}
|
||||
if (isMinified) {
|
||||
filename += '.min';
|
||||
}
|
||||
if (!withStyles) {
|
||||
filename += '.noStyle';
|
||||
}
|
||||
|
||||
return `${filename}.js`;
|
||||
}
|
||||
|
||||
function getInput(options) {
|
||||
const { withStyles } = options;
|
||||
|
||||
if (withStyles) {
|
||||
return main;
|
||||
}
|
||||
|
||||
return mainNoStyles;
|
||||
}
|
||||
|
||||
function createBundle(format, options) {
|
||||
const { withStyles, isMinified } = options;
|
||||
const input = getInput(options);
|
||||
const file = outputFile(format, isMinified, withStyles);
|
||||
|
||||
const external = [];
|
||||
|
||||
const output = {
|
||||
file,
|
||||
format,
|
||||
sourcemap: true,
|
||||
globals: {},
|
||||
banner: [
|
||||
`/**`,
|
||||
` * ${name}`,
|
||||
` * @version ${version}`,
|
||||
` * @link ${homepage}`,
|
||||
` * @license ${license}`,
|
||||
` */`,
|
||||
].join('\n'),
|
||||
};
|
||||
|
||||
const plugins = [
|
||||
nodeResolve({
|
||||
include: ['node_modules/dockview-core/**'],
|
||||
}),
|
||||
typescript({
|
||||
tsconfig: 'tsconfig.esm.json',
|
||||
}),
|
||||
];
|
||||
|
||||
if (isMinified) {
|
||||
plugins.push(terser());
|
||||
}
|
||||
if (withStyles) {
|
||||
plugins.push(postcss());
|
||||
}
|
||||
|
||||
if (format === 'umd') {
|
||||
output['name'] = name;
|
||||
}
|
||||
|
||||
external.push('react', 'react-dom');
|
||||
|
||||
if (format === 'umd') {
|
||||
output.globals['react'] = 'React';
|
||||
output.globals['react-dom'] = 'ReactDOM';
|
||||
}
|
||||
|
||||
return {
|
||||
input,
|
||||
output,
|
||||
plugins,
|
||||
external,
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = [
|
||||
// amd
|
||||
createBundle('amd', { withStyles: false, isMinified: false }),
|
||||
createBundle('amd', { withStyles: true, isMinified: false }),
|
||||
createBundle('amd', { withStyles: false, isMinified: true }),
|
||||
createBundle('amd', { withStyles: true, isMinified: true }),
|
||||
// umd
|
||||
createBundle('umd', { withStyles: false, isMinified: false }),
|
||||
createBundle('umd', { withStyles: true, isMinified: false }),
|
||||
createBundle('umd', { withStyles: false, isMinified: true }),
|
||||
createBundle('umd', { withStyles: true, isMinified: true }),
|
||||
// cjs
|
||||
createBundle('cjs', { withStyles: true, isMinified: false }),
|
||||
// esm
|
||||
createBundle('esm', { withStyles: true, isMinified: false }),
|
||||
createBundle('esm', { withStyles: true, isMinified: true }),
|
||||
];
|
2
packages/dockview-react/scripts/rollupEntryTarget.ts
Normal file
2
packages/dockview-react/scripts/rollupEntryTarget.ts
Normal file
@ -0,0 +1,2 @@
|
||||
import '../dist/styles/dockview.css';
|
||||
export * from '../src/index';
|
5
packages/dockview-react/src/__tests__/empty.spec.ts
Normal file
5
packages/dockview-react/src/__tests__/empty.spec.ts
Normal file
@ -0,0 +1,5 @@
|
||||
describe('empty', () => {
|
||||
test('that passes', () => {
|
||||
expect(true).toBeTruthy();
|
||||
});
|
||||
});
|
0
packages/dockview-react/src/index.scss
Normal file
0
packages/dockview-react/src/index.scss
Normal file
1
packages/dockview-react/src/index.ts
Normal file
1
packages/dockview-react/src/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from 'dockview';
|
14
packages/dockview-react/tsconfig.esm.json
Normal file
14
packages/dockview-react/tsconfig.esm.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"module": "ES2020",
|
||||
"moduleResolution": "node",
|
||||
"target": "es6",
|
||||
"outDir": "dist/esm",
|
||||
"tsBuildInfoFile": ".build/tsconfig.tsbuildinfo.esm",
|
||||
"jsx": "react",
|
||||
"rootDir": "src"
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["**/node_modules", "src/__tests__"]
|
||||
}
|
11
packages/dockview-react/tsconfig.json
Normal file
11
packages/dockview-react/tsconfig.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "dist/cjs",
|
||||
"tsBuildInfoFile": ".build/tsconfig.tsbuildinfo.cjs",
|
||||
"jsx": "react",
|
||||
"rootDir": "src"
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["**/node_modules", "src/__tests__"]
|
||||
}
|
5
packages/dockview-react/typedoc.json
Normal file
5
packages/dockview-react/typedoc.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": ["../../typedoc.base.json"],
|
||||
"entryPoints": ["src/index.ts"],
|
||||
"exclude": ["**/dist/**"]
|
||||
}
|
56
packages/dockview-vue/README.md
Normal file
56
packages/dockview-vue/README.md
Normal file
@ -0,0 +1,56 @@
|
||||
<div align="center">
|
||||
<h1>dockview</h1>
|
||||
|
||||
<p>Zero dependency layout manager supporting tabs, groups, grids and splitviews with ReactJS support written in TypeScript</p>
|
||||
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
[![npm version](https://badge.fury.io/js/dockview.svg)](https://www.npmjs.com/package/dockview)
|
||||
[![npm](https://img.shields.io/npm/dm/dockview)](https://www.npmjs.com/package/dockview)
|
||||
[![CI Build](https://github.com/mathuo/dockview/workflows/CI/badge.svg)](https://github.com/mathuo/dockview/actions?query=workflow%3ACI)
|
||||
[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=mathuo_dockview&metric=coverage)](https://sonarcloud.io/summary/overall?id=mathuo_dockview)
|
||||
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=mathuo_dockview&metric=alert_status)](https://sonarcloud.io/summary/overall?id=mathuo_dockview)
|
||||
[![Bundle Phobia](https://badgen.net/bundlephobia/minzip/dockview)](https://bundlephobia.com/result?p=dockview)
|
||||
|
||||
##
|
||||
|
||||
Please see the website: https://dockview.dev
|
||||
|
||||
## Features
|
||||
|
||||
- Serialization / deserialization with full layout management
|
||||
- Support for split-views, grid-views and 'dockable' views
|
||||
- Themeable and customizable
|
||||
- Tab and Group docking / Drag n' Drop
|
||||
- Popout Windows
|
||||
- Floating Groups
|
||||
- Extensive API
|
||||
- Supports Shadow DOMs
|
||||
- High test coverage
|
||||
- Documentation website with live examples
|
||||
- Transparent builds and Code Analysis
|
||||
- Security at mind - verifed publishing and builds through GitHub Actions
|
||||
|
||||
Want to verify our builds? Go [here](https://www.npmjs.com/package/dockview#Provenance).
|
||||
|
||||
## Quick start
|
||||
|
||||
Dockview has a peer dependency on `react >= 16.8.0` and `react-dom >= 16.8.0`. You can install dockview from [npm](https://www.npmjs.com/package/dockview).
|
||||
|
||||
```
|
||||
npm install --save dockview
|
||||
```
|
||||
|
||||
Within your project you must import or reference the stylesheet at `dockview/dist/styles/dockview.css` and attach a theme.
|
||||
|
||||
```css
|
||||
@import '~dockview/dist/styles/dockview.css';
|
||||
```
|
||||
|
||||
You should also attach a dockview theme to an element containing your components. For example:
|
||||
|
||||
```html
|
||||
<body classname="dockview-theme-dark"></body>
|
||||
```
|
6
packages/dockview-vue/gulpfile.js
Normal file
6
packages/dockview-vue/gulpfile.js
Normal file
@ -0,0 +1,6 @@
|
||||
const gulp = require('gulp');
|
||||
const buildfile = require('../../scripts/build');
|
||||
|
||||
buildfile.init();
|
||||
|
||||
gulp.task('run', gulp.series(['sass']));
|
34
packages/dockview-vue/jest.config.ts
Normal file
34
packages/dockview-vue/jest.config.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import { JestConfigWithTsJest } from 'ts-jest';
|
||||
|
||||
const config: JestConfigWithTsJest = {
|
||||
preset: 'ts-jest',
|
||||
roots: ['<rootDir>/packages/dockview-vue'],
|
||||
modulePaths: ['<rootDir>/packages/dockview-vue/src'],
|
||||
displayName: { name: 'dockview', color: 'blue' },
|
||||
rootDir: '../../',
|
||||
collectCoverageFrom: [
|
||||
'<rootDir>/packages/dockview-vue/src/**/*.{js,jsx,ts,tsx}',
|
||||
],
|
||||
setupFiles: [
|
||||
// '<rootDir>/packages/dockview-vue/src/__tests__/__mocks__/resizeObserver.js',
|
||||
],
|
||||
setupFilesAfterEnv: ['<rootDir>/jest-setup.ts'],
|
||||
coveragePathIgnorePatterns: ['/node_modules/'],
|
||||
modulePathIgnorePatterns: [
|
||||
// '<rootDir>/packages/dockview-vue/src/__tests__/__mocks__',
|
||||
// '<rootDir>/packages/dockview-vue/src/__tests__/__test_utils__',
|
||||
],
|
||||
coverageDirectory: '<rootDir>/packages/dockview-vue/coverage/',
|
||||
testResultsProcessor: 'jest-sonar-reporter',
|
||||
testEnvironment: 'jsdom',
|
||||
transform: {
|
||||
'^.+\\.tsx?$': [
|
||||
'ts-jest',
|
||||
{
|
||||
tsconfig: '<rootDir>/tsconfig.test.json',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
61
packages/dockview-vue/package.json
Normal file
61
packages/dockview-vue/package.json
Normal file
@ -0,0 +1,61 @@
|
||||
{
|
||||
"name": "dockview-vue",
|
||||
"version": "0.0.0-beta-0",
|
||||
"description": "Zero dependency layout manager supporting tabs, grids and splitviews with ReactJS support",
|
||||
"keywords": [
|
||||
"splitview",
|
||||
"split-view",
|
||||
"gridview",
|
||||
"grid-view",
|
||||
"dockview",
|
||||
"dock-view",
|
||||
"grid",
|
||||
"tabs",
|
||||
"layout",
|
||||
"layout manager",
|
||||
"dock layout",
|
||||
"dock",
|
||||
"docking",
|
||||
"splitter",
|
||||
"drag-and-drop",
|
||||
"drag",
|
||||
"drop",
|
||||
"react",
|
||||
"react-component"
|
||||
],
|
||||
"main": "dist/dockview-vue.umd.js",
|
||||
"module": "dist/dockview-vue.es.js",
|
||||
"types": "dist/types/index.d.ts",
|
||||
"homepage": "https://github.com/mathuo/dockview",
|
||||
"bugs": {
|
||||
"url": "https://github.com/mathuo/dockview/issues"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mathuo/dockview.git"
|
||||
},
|
||||
"license": "MIT",
|
||||
"author": "https://github.com/mathuo",
|
||||
"files": [
|
||||
"dist",
|
||||
"README.md"
|
||||
],
|
||||
"scripts": {
|
||||
"build-only": "vite build",
|
||||
"build": "npm run build:package && npm run build:bundles",
|
||||
"build:bundles": "rollup -c",
|
||||
"build:cjs": "cross-env ../../node_modules/.bin/vue-tsc --build ./tsconfig.json --verbose --extendedDiagnostics",
|
||||
"build:css": "gulp sass",
|
||||
"build:esm": "cross-env ../../node_modules/.bin/vue-tsc --build ./tsconfig.esm.json --verbose --extendedDiagnostics",
|
||||
"build:package": "npm run build-only && npm run build:types",
|
||||
"clean": "rimraf dist/ .build/ .rollup.cache/",
|
||||
"prepublishOnly": "npm run rebuild && npm run test",
|
||||
"rebuild": "npm run clean && npm run build",
|
||||
"test": "cross-env ../../node_modules/.bin/jest --selectProjects dockview",
|
||||
"test:cov": "cross-env ../../node_modules/.bin/jest --selectProjects dockview --coverage",
|
||||
"build:types": "vue-tsc --project tsconfig.build-types.json --declaration --emitDeclarationOnly --outDir dist/types "
|
||||
},
|
||||
"dependencies": {
|
||||
"dockview-core": "^1.10.1"
|
||||
}
|
||||
}
|
113
packages/dockview-vue/rollup.config.js
Normal file
113
packages/dockview-vue/rollup.config.js
Normal file
@ -0,0 +1,113 @@
|
||||
/* eslint-disable */
|
||||
|
||||
const { join } = require('path');
|
||||
const typescript = require('@rollup/plugin-typescript');
|
||||
const terser = require('@rollup/plugin-terser');
|
||||
const postcss = require('rollup-plugin-postcss');
|
||||
const nodeResolve = require('@rollup/plugin-node-resolve');
|
||||
|
||||
const { name, version, homepage, license } = require('./package.json');
|
||||
const main = join(__dirname, './scripts/rollupEntryTarget.ts');
|
||||
const mainNoStyles = join(__dirname, './src/index.ts');
|
||||
const outputDir = join(__dirname, 'dist');
|
||||
|
||||
function outputFile(format, isMinified, withStyles) {
|
||||
let filename = join(outputDir, name);
|
||||
|
||||
if (format !== 'umd') {
|
||||
filename += `.${format}`;
|
||||
}
|
||||
if (isMinified) {
|
||||
filename += '.min';
|
||||
}
|
||||
if (!withStyles) {
|
||||
filename += '.noStyle';
|
||||
}
|
||||
|
||||
return `${filename}.js`;
|
||||
}
|
||||
|
||||
function getInput(options) {
|
||||
const { withStyles } = options;
|
||||
|
||||
if (withStyles) {
|
||||
return main;
|
||||
}
|
||||
|
||||
return mainNoStyles;
|
||||
}
|
||||
|
||||
function createBundle(format, options) {
|
||||
const { withStyles, isMinified } = options;
|
||||
const input = getInput(options);
|
||||
const file = outputFile(format, isMinified, withStyles);
|
||||
|
||||
const external = [];
|
||||
|
||||
const output = {
|
||||
file,
|
||||
format,
|
||||
sourcemap: true,
|
||||
globals: {},
|
||||
banner: [
|
||||
`/**`,
|
||||
` * ${name}`,
|
||||
` * @version ${version}`,
|
||||
` * @link ${homepage}`,
|
||||
` * @license ${license}`,
|
||||
` */`,
|
||||
].join('\n'),
|
||||
};
|
||||
|
||||
const plugins = [
|
||||
nodeResolve({
|
||||
include: ['node_modules/dockview-core/**'],
|
||||
}),
|
||||
typescript({
|
||||
tsconfig: 'tsconfig.esm.json',
|
||||
}),
|
||||
];
|
||||
|
||||
if (isMinified) {
|
||||
plugins.push(terser());
|
||||
}
|
||||
if (withStyles) {
|
||||
plugins.push(postcss());
|
||||
}
|
||||
|
||||
if (format === 'umd') {
|
||||
output['name'] = name;
|
||||
}
|
||||
|
||||
external.push('react', 'react-dom');
|
||||
|
||||
if (format === 'umd') {
|
||||
output.globals['react'] = 'React';
|
||||
output.globals['react-dom'] = 'ReactDOM';
|
||||
}
|
||||
|
||||
return {
|
||||
input,
|
||||
output,
|
||||
plugins,
|
||||
external,
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = [
|
||||
// amd
|
||||
createBundle('amd', { withStyles: false, isMinified: false }),
|
||||
createBundle('amd', { withStyles: true, isMinified: false }),
|
||||
createBundle('amd', { withStyles: false, isMinified: true }),
|
||||
createBundle('amd', { withStyles: true, isMinified: true }),
|
||||
// umd
|
||||
createBundle('umd', { withStyles: false, isMinified: false }),
|
||||
createBundle('umd', { withStyles: true, isMinified: false }),
|
||||
createBundle('umd', { withStyles: false, isMinified: true }),
|
||||
createBundle('umd', { withStyles: true, isMinified: true }),
|
||||
// cjs
|
||||
createBundle('cjs', { withStyles: true, isMinified: false }),
|
||||
// esm
|
||||
createBundle('esm', { withStyles: true, isMinified: false }),
|
||||
createBundle('esm', { withStyles: true, isMinified: true }),
|
||||
];
|
2
packages/dockview-vue/scripts/rollupEntryTarget.ts
Normal file
2
packages/dockview-vue/scripts/rollupEntryTarget.ts
Normal file
@ -0,0 +1,2 @@
|
||||
import '../dist/styles/dockview.css';
|
||||
export * from '../src/index';
|
5
packages/dockview-vue/src/__tests__/empty.spec.ts
Normal file
5
packages/dockview-vue/src/__tests__/empty.spec.ts
Normal file
@ -0,0 +1,5 @@
|
||||
describe('empty', () => {
|
||||
test('that passes', () => {
|
||||
expect(true).toBeTruthy();
|
||||
});
|
||||
});
|
285
packages/dockview-vue/src/dockview/dockview.vue
Normal file
285
packages/dockview-vue/src/dockview/dockview.vue
Normal file
@ -0,0 +1,285 @@
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
DockviewApi,
|
||||
DockviewComponent,
|
||||
type IContentRenderer,
|
||||
type ITabRenderer,
|
||||
type IWatermarkRenderer,
|
||||
type IDockviewPanelProps,
|
||||
type IDockviewPanelHeaderProps,
|
||||
type IGroupPanelBaseProps,
|
||||
type IWatermarkPanelProps,
|
||||
type DockviewOptions,
|
||||
PROPERTY_KEYS,
|
||||
type DockviewFrameworkOptions,
|
||||
type DockviewReadyEvent,
|
||||
} from 'dockview-core';
|
||||
import {
|
||||
ref,
|
||||
onMounted,
|
||||
defineProps,
|
||||
defineEmits,
|
||||
watch,
|
||||
onBeforeUnmount,
|
||||
} from 'vue';
|
||||
import {
|
||||
VueContentRenderer,
|
||||
VueHeaderActionsRenderer,
|
||||
VueTabRenderer,
|
||||
VueWatermarkRenderer,
|
||||
type VueComponent,
|
||||
} from '../utils';
|
||||
|
||||
interface VueProps {
|
||||
components: Record<string, VueComponent<IDockviewPanelProps>>;
|
||||
tabComponents?: Record<string, VueComponent<IDockviewPanelHeaderProps>>;
|
||||
watermarkComponent?: VueComponent<IWatermarkPanelProps>;
|
||||
defaultTabComponent?: VueComponent<IDockviewPanelHeaderProps>;
|
||||
rightHeaderActionsComponent?: VueComponent<IGroupPanelBaseProps>;
|
||||
leftHeaderActionsComponent?: VueComponent<IGroupPanelBaseProps>;
|
||||
prefixHeaderActionsComponent?: VueComponent<IGroupPanelBaseProps>;
|
||||
}
|
||||
|
||||
const VUE_PROPERTIES = (() => {
|
||||
const _value: Record<keyof VueProps, undefined> = {
|
||||
components: undefined,
|
||||
tabComponents: undefined,
|
||||
watermarkComponent: undefined,
|
||||
defaultTabComponent: undefined,
|
||||
rightHeaderActionsComponent: undefined,
|
||||
leftHeaderActionsComponent: undefined,
|
||||
prefixHeaderActionsComponent: undefined,
|
||||
};
|
||||
|
||||
return Object.keys(_value) as (keyof VueProps)[];
|
||||
})();
|
||||
|
||||
type VueEvents = {
|
||||
ready: [event: DockviewReadyEvent];
|
||||
};
|
||||
|
||||
const DEFAULT_REACT_TAB = 'props.defaultTabComponent';
|
||||
|
||||
export type IDockviewVueProps = DockviewOptions & VueProps;
|
||||
|
||||
function extractCoreOptions(props: IDockviewVueProps): DockviewOptions {
|
||||
const coreOptions = (PROPERTY_KEYS as (keyof DockviewOptions)[]).reduce(
|
||||
(obj, key) => {
|
||||
(obj as any)[key] = props[key];
|
||||
return obj;
|
||||
},
|
||||
{} as Partial<DockviewOptions>
|
||||
);
|
||||
|
||||
return coreOptions as DockviewOptions;
|
||||
}
|
||||
|
||||
const emit = defineEmits<VueEvents>();
|
||||
const props = defineProps<IDockviewVueProps>();
|
||||
|
||||
const el = ref<HTMLElement | null>(null);
|
||||
const instance = ref<DockviewComponent | null>(null);
|
||||
|
||||
PROPERTY_KEYS.forEach((coreOptionKey) => {
|
||||
watch(
|
||||
() => props[coreOptionKey],
|
||||
(newValue, oldValue) => {
|
||||
if (instance.value) {
|
||||
instance.value.updateOptions({ [coreOptionKey]: newValue });
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.components,
|
||||
(newValue, oldValue) => {
|
||||
if (instance.value) {
|
||||
instance.value.updateOptions({ frameworkComponents: newValue });
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => [props.tabComponents, props.defaultTabComponent],
|
||||
([newTabComponents, newDefaultTabComponent], oldValue) => {
|
||||
if (instance.value) {
|
||||
const frameworkTabComponents = newTabComponents ?? {};
|
||||
|
||||
if (newDefaultTabComponent) {
|
||||
frameworkTabComponents[DEFAULT_REACT_TAB] =
|
||||
newDefaultTabComponent;
|
||||
}
|
||||
|
||||
instance.value.updateOptions({
|
||||
defaultTabComponent: newDefaultTabComponent
|
||||
? DEFAULT_REACT_TAB
|
||||
: undefined,
|
||||
frameworkTabComponents,
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.watermarkComponent,
|
||||
(newValue, oldValue) => {
|
||||
if (instance.value) {
|
||||
instance.value.updateOptions({
|
||||
watermarkFrameworkComponent: newValue,
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.leftHeaderActionsComponent,
|
||||
(newValue, oldValue) => {
|
||||
if (instance.value) {
|
||||
instance.value.updateOptions({
|
||||
headerLeftActionComponent: newValue
|
||||
? (group) => {
|
||||
return new VueHeaderActionsRenderer(
|
||||
newValue as VueComponent,
|
||||
group
|
||||
);
|
||||
}
|
||||
: undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.rightHeaderActionsComponent,
|
||||
(newValue, oldValue) => {
|
||||
if (instance.value) {
|
||||
instance.value.updateOptions({
|
||||
headerRightActionComponent: newValue
|
||||
? (group) => {
|
||||
return new VueHeaderActionsRenderer(
|
||||
newValue as VueComponent,
|
||||
group
|
||||
);
|
||||
}
|
||||
: undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.prefixHeaderActionsComponent,
|
||||
(newValue, oldValue) => {
|
||||
if (instance.value) {
|
||||
instance.value.updateOptions({
|
||||
headerPrefixActionComponent: newValue
|
||||
? (group) => {
|
||||
return new VueHeaderActionsRenderer(
|
||||
newValue as VueComponent,
|
||||
group
|
||||
);
|
||||
}
|
||||
: undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
if (!el.value) {
|
||||
throw new Error('element is not mounted');
|
||||
}
|
||||
|
||||
const frameworkTabComponents = props.tabComponents ?? {};
|
||||
|
||||
if (props.defaultTabComponent) {
|
||||
frameworkTabComponents[DEFAULT_REACT_TAB] = props.defaultTabComponent;
|
||||
}
|
||||
|
||||
const frameworkOptions: DockviewFrameworkOptions = {
|
||||
parentElement: el.value,
|
||||
frameworkComponentFactory: {
|
||||
content: {
|
||||
createComponent: (
|
||||
id: string,
|
||||
componentId: string,
|
||||
component: any
|
||||
): IContentRenderer => {
|
||||
return new VueContentRenderer(component);
|
||||
},
|
||||
},
|
||||
tab: {
|
||||
createComponent: (
|
||||
id: string,
|
||||
componentId: string,
|
||||
component: any
|
||||
): ITabRenderer => {
|
||||
return new VueTabRenderer(component);
|
||||
},
|
||||
},
|
||||
watermark: {
|
||||
createComponent: (
|
||||
id: string,
|
||||
componentId: string,
|
||||
component: any
|
||||
): IWatermarkRenderer => {
|
||||
return new VueWatermarkRenderer(component);
|
||||
},
|
||||
},
|
||||
// action: {
|
||||
// createComponent: (id: string, componentId: string, component: any): IWatermarkRenderer => {
|
||||
// return new VueHeaderActionRenderer(component)
|
||||
// }
|
||||
// }
|
||||
},
|
||||
frameworkComponents: props.components,
|
||||
frameworkTabComponents,
|
||||
headerLeftActionComponent: props.leftHeaderActionsComponent
|
||||
? (group) => {
|
||||
return new VueHeaderActionsRenderer(
|
||||
props.leftHeaderActionsComponent as VueComponent,
|
||||
group
|
||||
);
|
||||
}
|
||||
: undefined,
|
||||
headerPrefixActionComponent: props.prefixHeaderActionsComponent
|
||||
? (group) => {
|
||||
return new VueHeaderActionsRenderer(
|
||||
props.prefixHeaderActionsComponent as VueComponent,
|
||||
group
|
||||
);
|
||||
}
|
||||
: undefined,
|
||||
headerRightActionComponent: props.rightHeaderActionsComponent
|
||||
? (group) => {
|
||||
return new VueHeaderActionsRenderer(
|
||||
props.rightHeaderActionsComponent as VueComponent,
|
||||
group
|
||||
);
|
||||
}
|
||||
: undefined,
|
||||
defaultTabComponent: props.defaultTabComponent
|
||||
? DEFAULT_REACT_TAB
|
||||
: undefined,
|
||||
};
|
||||
|
||||
const dockview = new DockviewComponent({
|
||||
...extractCoreOptions(props),
|
||||
...frameworkOptions,
|
||||
});
|
||||
|
||||
instance.value = dockview;
|
||||
emit('ready', { api: new DockviewApi(dockview) });
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (instance.value) {
|
||||
instance.value.dispose();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="el" />
|
||||
</template>
|
0
packages/dockview-vue/src/index.scss
Normal file
0
packages/dockview-vue/src/index.scss
Normal file
5
packages/dockview-vue/src/index.ts
Normal file
5
packages/dockview-vue/src/index.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export * from 'dockview-core';
|
||||
|
||||
import DockviewVue from './dockview/dockview.vue';
|
||||
export { DockviewVue };
|
||||
export * from './dockview/dockview.vue';
|
236
packages/dockview-vue/src/utils.ts
Normal file
236
packages/dockview-vue/src/utils.ts
Normal file
@ -0,0 +1,236 @@
|
||||
import type {
|
||||
DockviewApi,
|
||||
DockviewGroupPanel,
|
||||
DockviewGroupPanelApi,
|
||||
GroupPanelPartInitParameters,
|
||||
IContentRenderer,
|
||||
IHeaderActionsRenderer,
|
||||
ITabRenderer,
|
||||
IWatermarkRenderer,
|
||||
PanelUpdateEvent,
|
||||
Parameters,
|
||||
WatermarkRendererInitParameters,
|
||||
} from 'dockview-core';
|
||||
import {
|
||||
createVNode,
|
||||
type ComponentOptionsBase,
|
||||
render,
|
||||
cloneVNode,
|
||||
mergeProps,
|
||||
type DefineComponent,
|
||||
} from 'vue';
|
||||
|
||||
export type ComponentInterface = ComponentOptionsBase<
|
||||
any,
|
||||
any,
|
||||
any,
|
||||
any,
|
||||
any,
|
||||
any,
|
||||
any,
|
||||
any
|
||||
>;
|
||||
|
||||
export type VueComponent<T = any> = DefineComponent<T>;
|
||||
|
||||
/**
|
||||
* TODO List
|
||||
*
|
||||
* 1. handle vue context-ish stuff (appContext? provides?)
|
||||
*
|
||||
*
|
||||
*
|
||||
* @see https://vuejs.org/api/render-function.html#clonevnode
|
||||
* @see https://vuejs.org/api/render-function.html#mergeprops
|
||||
*/
|
||||
export function mountVueComponent<T extends Record<string, any>>(
|
||||
component: VueComponent<T>,
|
||||
props: T,
|
||||
element: HTMLElement
|
||||
) {
|
||||
let vNode = createVNode(component, props);
|
||||
|
||||
render(vNode, element);
|
||||
|
||||
return {
|
||||
update: (newProps: any) => {
|
||||
vNode = cloneVNode(vNode, mergeProps(props, newProps));
|
||||
render(vNode, element);
|
||||
},
|
||||
dispose: () => {
|
||||
render(null, element);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export class VueContentRenderer implements IContentRenderer {
|
||||
private _element: HTMLElement;
|
||||
private _renderDisposable:
|
||||
| { update: (props: any) => void; dispose: () => void }
|
||||
| undefined;
|
||||
|
||||
get element(): HTMLElement {
|
||||
return this._element;
|
||||
}
|
||||
|
||||
constructor(private readonly component: VueComponent) {
|
||||
this._element = document.createElement('div');
|
||||
this.element.className = 'dv-vue-part';
|
||||
}
|
||||
|
||||
init(parameters: GroupPanelPartInitParameters): void {
|
||||
const props = {
|
||||
params: parameters.params,
|
||||
api: parameters.api,
|
||||
containerApi: parameters.containerApi,
|
||||
};
|
||||
|
||||
this._renderDisposable?.dispose();
|
||||
this._renderDisposable = mountVueComponent(
|
||||
this.component,
|
||||
props,
|
||||
this.element
|
||||
);
|
||||
}
|
||||
|
||||
update(event: PanelUpdateEvent<Parameters>): void {
|
||||
const params = event.params;
|
||||
// TODO: handle prop updates somehow?
|
||||
this._renderDisposable?.update(params);
|
||||
}
|
||||
|
||||
focus(): void {
|
||||
// TODO: make optional on interface
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._renderDisposable?.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
export class VueTabRenderer implements ITabRenderer {
|
||||
private _element: HTMLElement;
|
||||
private _renderDisposable:
|
||||
| { update: (props: any) => void; dispose: () => void }
|
||||
| undefined;
|
||||
|
||||
get element(): HTMLElement {
|
||||
return this._element;
|
||||
}
|
||||
|
||||
constructor(private readonly component: VueComponent) {
|
||||
this._element = document.createElement('div');
|
||||
this.element.className = 'dv-vue-part';
|
||||
}
|
||||
|
||||
init(parameters: GroupPanelPartInitParameters): void {
|
||||
const props = {
|
||||
params: parameters.params,
|
||||
api: parameters.api,
|
||||
containerApi: parameters.containerApi,
|
||||
};
|
||||
|
||||
this._renderDisposable?.dispose();
|
||||
this._renderDisposable = mountVueComponent(
|
||||
this.component,
|
||||
props,
|
||||
this.element
|
||||
);
|
||||
}
|
||||
|
||||
update(event: PanelUpdateEvent<Parameters>): void {
|
||||
const params = event.params;
|
||||
// TODO: handle prop updates somehow?
|
||||
this._renderDisposable?.update(params);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._renderDisposable?.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
export class VueWatermarkRenderer implements IWatermarkRenderer {
|
||||
private _element: HTMLElement;
|
||||
private _renderDisposable:
|
||||
| { update: (props: any) => void; dispose: () => void }
|
||||
| undefined;
|
||||
|
||||
get element(): HTMLElement {
|
||||
return this._element;
|
||||
}
|
||||
|
||||
constructor(private readonly component: VueComponent) {
|
||||
this._element = document.createElement('div');
|
||||
this.element.className = 'dv-vue-part';
|
||||
}
|
||||
|
||||
init(parameters: WatermarkRendererInitParameters): void {
|
||||
const props = {
|
||||
group: parameters.group,
|
||||
containerApi: parameters.containerApi,
|
||||
};
|
||||
|
||||
this._renderDisposable?.dispose();
|
||||
this._renderDisposable = mountVueComponent(
|
||||
this.component,
|
||||
props,
|
||||
this.element
|
||||
);
|
||||
}
|
||||
|
||||
updateParentGroup(group: DockviewGroupPanel, visible: boolean): void {
|
||||
// TODO: make optional on interface
|
||||
}
|
||||
|
||||
update(event: PanelUpdateEvent<Parameters>): void {
|
||||
const params = event.params;
|
||||
// TODO: handle prop updates somehow?
|
||||
this._renderDisposable?.update(params);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._renderDisposable?.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
export class VueHeaderActionsRenderer implements IHeaderActionsRenderer {
|
||||
private _element: HTMLElement;
|
||||
private _renderDisposable:
|
||||
| { update: (props: any) => void; dispose: () => void }
|
||||
| undefined;
|
||||
|
||||
get element(): HTMLElement {
|
||||
return this._element;
|
||||
}
|
||||
|
||||
constructor(
|
||||
private readonly component: VueComponent,
|
||||
group: DockviewGroupPanel
|
||||
) {
|
||||
this._element = document.createElement('div');
|
||||
this.element.className = 'dv-vue-header-action-part';
|
||||
}
|
||||
|
||||
init(params: {
|
||||
containerApi: DockviewApi;
|
||||
api: DockviewGroupPanelApi;
|
||||
}): void {
|
||||
console.log('meeee', this.component);
|
||||
const props = {
|
||||
api: params.api,
|
||||
containerApi: params.containerApi,
|
||||
};
|
||||
|
||||
this._renderDisposable?.dispose();
|
||||
this._renderDisposable = mountVueComponent(
|
||||
this.component,
|
||||
props,
|
||||
this.element
|
||||
);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
console.log('dispose');
|
||||
this._renderDisposable?.dispose();
|
||||
}
|
||||
}
|
10
packages/dockview-vue/tsconfig.app.json
Normal file
10
packages/dockview-vue/tsconfig.app.json
Normal file
@ -0,0 +1,10 @@
|
||||
// tsconfig.app.json
|
||||
{
|
||||
"extends": "@vue/tsconfig/tsconfig.json",
|
||||
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
|
||||
"exclude": ["src/**/__tests__/*", "src/**/*.cy.ts"],
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"baseUrl": "."
|
||||
}
|
||||
}
|
10
packages/dockview-vue/tsconfig.build-types.json
Normal file
10
packages/dockview-vue/tsconfig.build-types.json
Normal file
@ -0,0 +1,10 @@
|
||||
// tsconfig.build-types.json
|
||||
{
|
||||
"include": ["src/**/*"],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"**/*.cy.ts",
|
||||
"**/*.spec.ts",
|
||||
"**/__tests__/**/*"
|
||||
]
|
||||
}
|
9
packages/dockview-vue/tsconfig.config.json
Normal file
9
packages/dockview-vue/tsconfig.config.json
Normal file
@ -0,0 +1,9 @@
|
||||
// tsconfig.config.json
|
||||
{
|
||||
"extends": "@vue/tsconfig/tsconfig.json",
|
||||
"include": ["vite.config.*", "vitest.config.*", "cypress.config.*"],
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"types": ["node"]
|
||||
}
|
||||
}
|
5
packages/dockview-vue/tsconfig.json
Normal file
5
packages/dockview-vue/tsconfig.json
Normal file
@ -0,0 +1,5 @@
|
||||
// tsconfig.json
|
||||
{
|
||||
"files": [],
|
||||
"references": [{ "path": "./tsconfig.config.json" }, { "path": "./tsconfig.app.json" }]
|
||||
}
|
5
packages/dockview-vue/typedoc.json
Normal file
5
packages/dockview-vue/typedoc.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": ["../../typedoc.base.json"],
|
||||
"entryPoints": ["src/index.ts"],
|
||||
"exclude": ["**/dist/**"]
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user