feat: multiple framework support work

This commit is contained in:
mathuo 2024-03-27 21:32:39 +00:00
parent 61f3c252d4
commit b0d98102fc
No known key found for this signature in database
GPG Key ID: C6EEDEFD6CA07281
100 changed files with 3157 additions and 611 deletions

View File

@ -47,6 +47,7 @@
"@typescript-eslint/parser": "^6.17.0", "@typescript-eslint/parser": "^6.17.0",
"@vitejs/plugin-vue": "^5.0.4", "@vitejs/plugin-vue": "^5.0.4",
"@vue/tsconfig": "^0.5.1", "@vue/tsconfig": "^0.5.1",
"concurrently": "^8.2.2",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"eslint": "^8.56.0", "eslint": "^8.56.0",
"fs-extra": "^11.2.0", "fs-extra": "^11.2.0",
@ -71,6 +72,7 @@
"typescript": "^5.3.3", "typescript": "^5.3.3",
"vite": "^5.1.5", "vite": "^5.1.5",
"vue": "^3.4.21", "vue": "^3.4.21",
"vue-sfc-loader": "^0.1.0",
"vue-tsc": "^2.0.5" "vue-tsc": "^2.0.5"
}, },
"engines": { "engines": {

View File

@ -1,12 +1,17 @@
import { Position, positionToDirection } from '../dnd/droptarget'; import { Position, positionToDirection } from '../dnd/droptarget';
import { DockviewComponent } from '../dockview/dockviewComponent'; import { DockviewComponent } from '../dockview/dockviewComponent';
import { DockviewGroupPanel } from '../dockview/dockviewGroupPanel'; import { DockviewGroupPanel } from '../dockview/dockviewGroupPanel';
import { DockviewGroupLocation } from '../dockview/dockviewGroupPanelModel'; import {
DockviewGroupChangeEvent,
DockviewGroupLocation,
} from '../dockview/dockviewGroupPanelModel';
import { Emitter, Event } from '../events'; import { Emitter, Event } from '../events';
import { MutableDisposable } from '../lifecycle';
import { GridviewPanelApi, GridviewPanelApiImpl } from './gridviewPanelApi'; import { GridviewPanelApi, GridviewPanelApiImpl } from './gridviewPanelApi';
export interface DockviewGroupPanelApi extends GridviewPanelApi { export interface DockviewGroupPanelApi extends GridviewPanelApi {
readonly onDidLocationChange: Event<DockviewGroupPanelFloatingChangeEvent>; readonly onDidLocationChange: Event<DockviewGroupPanelFloatingChangeEvent>;
readonly onDidActivePanelChange: Event<DockviewGroupChangeEvent>;
readonly location: DockviewGroupLocation; readonly location: DockviewGroupLocation;
/** /**
* If you require the Window object * If you require the Window object
@ -27,6 +32,8 @@ export interface DockviewGroupPanelFloatingChangeEvent {
const NOT_INITIALIZED_MESSAGE = 'DockviewGroupPanelApiImpl not initialized'; const NOT_INITIALIZED_MESSAGE = 'DockviewGroupPanelApiImpl not initialized';
export class DockviewGroupPanelApiImpl extends GridviewPanelApiImpl { export class DockviewGroupPanelApiImpl extends GridviewPanelApiImpl {
private readonly _mutableDisposable = new MutableDisposable();
private _group: DockviewGroupPanel | undefined; private _group: DockviewGroupPanel | undefined;
readonly _onDidLocationChange = readonly _onDidLocationChange =
@ -34,6 +41,10 @@ export class DockviewGroupPanelApiImpl extends GridviewPanelApiImpl {
readonly onDidLocationChange: Event<DockviewGroupPanelFloatingChangeEvent> = readonly onDidLocationChange: Event<DockviewGroupPanelFloatingChangeEvent> =
this._onDidLocationChange.event; this._onDidLocationChange.event;
private readonly _onDidActivePanelChange =
new Emitter<DockviewGroupChangeEvent>();
readonly onDidActivePanelChange = this._onDidActivePanelChange.event;
get location(): DockviewGroupLocation { get location(): DockviewGroupLocation {
if (!this._group) { if (!this._group) {
throw new Error(NOT_INITIALIZED_MESSAGE); throw new Error(NOT_INITIALIZED_MESSAGE);
@ -44,7 +55,11 @@ export class DockviewGroupPanelApiImpl extends GridviewPanelApiImpl {
constructor(id: string, private readonly accessor: DockviewComponent) { constructor(id: string, private readonly accessor: DockviewComponent) {
super(id, '__dockviewgroup__'); super(id, '__dockviewgroup__');
this.addDisposables(this._onDidLocationChange); this.addDisposables(
this._onDidLocationChange,
this._onDidActivePanelChange,
this._mutableDisposable
);
} }
close(): void { close(): void {
@ -116,5 +131,19 @@ export class DockviewGroupPanelApiImpl extends GridviewPanelApiImpl {
initialize(group: DockviewGroupPanel): void { initialize(group: DockviewGroupPanel): void {
this._group = group; this._group = group;
/**
* TODO: Annoying initialization order caveat
*
* Due to the order on initialization we know that the model isn't defined until later in the same stack-frame of setup.
* By queuing a microtask we can ensure the setup is completed within the same stack-frame, but after everything else has
* finished ensuring the `model` is defined.
*/
queueMicrotask(() => {
this._mutableDisposable.value =
this._group!.model.onDidActivePanelChange((event) => {
this._onDidActivePanelChange.fire(event);
});
});
} }
} }

View File

@ -1039,11 +1039,11 @@ export class DockviewComponent
updateOptions(options: Partial<DockviewComponentOptions>): void { updateOptions(options: Partial<DockviewComponentOptions>): void {
const changed_floatingGroupBounds = const changed_floatingGroupBounds =
options.floatingGroupBounds !== undefined && 'floatingGroupBounds' in options &&
options.floatingGroupBounds !== this.options.floatingGroupBounds; options.floatingGroupBounds !== this.options.floatingGroupBounds;
const changed_rootOverlayOptions = const changed_rootOverlayOptions =
options.rootOverlayModel !== undefined && 'rootOverlayModel' in options &&
options.rootOverlayModel !== this.options.rootOverlayModel; options.rootOverlayModel !== this.options.rootOverlayModel;
this._options = { ...this.options, ...options }; this._options = { ...this.options, ...options };

View File

@ -537,6 +537,7 @@ export class DockviewGroupPanelModel
this._rightHeaderActions.init({ this._rightHeaderActions.init({
containerApi: this._api, containerApi: this._api,
api: this.groupPanel.api, api: this.groupPanel.api,
group: this.groupPanel,
}); });
this.tabsContainer.setRightActionsElement( this.tabsContainer.setRightActionsElement(
this._rightHeaderActions.element this._rightHeaderActions.element
@ -552,6 +553,7 @@ export class DockviewGroupPanelModel
this._leftHeaderActions.init({ this._leftHeaderActions.init({
containerApi: this._api, containerApi: this._api,
api: this.groupPanel.api, api: this.groupPanel.api,
group: this.groupPanel,
}); });
this.tabsContainer.setLeftActionsElement( this.tabsContainer.setLeftActionsElement(
this._leftHeaderActions.element this._leftHeaderActions.element
@ -567,6 +569,7 @@ export class DockviewGroupPanelModel
this._prefixHeaderActions.init({ this._prefixHeaderActions.init({
containerApi: this._api, containerApi: this._api,
api: this.groupPanel.api, api: this.groupPanel.api,
group: this.groupPanel,
}); });
this.tabsContainer.setPrefixActionsElement( this.tabsContainer.setPrefixActionsElement(
this._prefixHeaderActions.element this._prefixHeaderActions.element
@ -845,10 +848,8 @@ export class DockviewGroupPanelModel
this._panels.splice(index, 1); this._panels.splice(index, 1);
if (this.mostRecentlyUsed.includes(panel)) { if (this.mostRecentlyUsed.includes(panel)) {
this.mostRecentlyUsed.splice( const index = this.mostRecentlyUsed.indexOf(panel);
this.mostRecentlyUsed.indexOf(panel), this.mostRecentlyUsed.splice(index, 1);
1
);
} }
const disposable = this._panelDisposables.get(panel.id); const disposable = this._panelDisposables.get(panel.id);

View File

@ -30,6 +30,7 @@ export interface IDockviewHeaderActionsProps {
export interface IGroupHeaderProps { export interface IGroupHeaderProps {
api: DockviewGroupPanelApi; api: DockviewGroupPanelApi;
containerApi: DockviewApi; containerApi: DockviewApi;
group: IDockviewGroupPanel;
} }
export interface IWatermarkPanelProps { export interface IWatermarkPanelProps {

View File

@ -21,6 +21,9 @@ import {
defineEmits, defineEmits,
watch, watch,
onBeforeUnmount, onBeforeUnmount,
markRaw,
toRaw,
getCurrentInstance,
} from 'vue'; } from 'vue';
import { import {
VueContentRenderer, VueContentRenderer,
@ -75,11 +78,18 @@ function extractCoreOptions(props: IDockviewVueProps): DockviewOptions {
} }
const emit = defineEmits<VueEvents>(); const emit = defineEmits<VueEvents>();
/**
* Anything here that is a Vue.js component should not be reactive
* i.e. markRaw(toRaw(...))
*/
const props = defineProps<IDockviewVueProps>(); const props = defineProps<IDockviewVueProps>();
const el = ref<HTMLElement | null>(null); const el = ref<HTMLElement | null>(null);
const instance = ref<DockviewComponent | null>(null); const instance = ref<DockviewComponent | null>(null);
PROPERTY_KEYS.forEach((coreOptionKey) => { PROPERTY_KEYS.forEach((coreOptionKey) => {
watch( watch(
() => props[coreOptionKey], () => props[coreOptionKey],
@ -141,6 +151,7 @@ watch(
? (group) => { ? (group) => {
return new VueHeaderActionsRenderer( return new VueHeaderActionsRenderer(
newValue as VueComponent, newValue as VueComponent,
getCurrentInstance()!,
group group
); );
} }
@ -159,6 +170,7 @@ watch(
? (group) => { ? (group) => {
return new VueHeaderActionsRenderer( return new VueHeaderActionsRenderer(
newValue as VueComponent, newValue as VueComponent,
getCurrentInstance()!,
group group
); );
} }
@ -176,7 +188,7 @@ watch(
headerPrefixActionComponent: newValue headerPrefixActionComponent: newValue
? (group) => { ? (group) => {
return new VueHeaderActionsRenderer( return new VueHeaderActionsRenderer(
newValue as VueComponent, newValue as VueComponent,getCurrentInstance()!,
group group
); );
} }
@ -206,7 +218,7 @@ onMounted(() => {
componentId: string, componentId: string,
component: any component: any
): IContentRenderer => { ): IContentRenderer => {
return new VueContentRenderer(component); return new VueContentRenderer(component,getCurrentInstance()!);
}, },
}, },
tab: { tab: {
@ -215,7 +227,7 @@ onMounted(() => {
componentId: string, componentId: string,
component: any component: any
): ITabRenderer => { ): ITabRenderer => {
return new VueTabRenderer(component); return new VueTabRenderer(component,getCurrentInstance()!);
}, },
}, },
watermark: { watermark: {
@ -224,7 +236,7 @@ onMounted(() => {
componentId: string, componentId: string,
component: any component: any
): IWatermarkRenderer => { ): IWatermarkRenderer => {
return new VueWatermarkRenderer(component); return new VueWatermarkRenderer(component,getCurrentInstance()!);
}, },
}, },
// action: { // action: {
@ -238,7 +250,7 @@ onMounted(() => {
headerLeftActionComponent: props.leftHeaderActionsComponent headerLeftActionComponent: props.leftHeaderActionsComponent
? (group) => { ? (group) => {
return new VueHeaderActionsRenderer( return new VueHeaderActionsRenderer(
props.leftHeaderActionsComponent as VueComponent, props.leftHeaderActionsComponent as VueComponent,getCurrentInstance()!,
group group
); );
} }
@ -246,7 +258,7 @@ onMounted(() => {
headerPrefixActionComponent: props.prefixHeaderActionsComponent headerPrefixActionComponent: props.prefixHeaderActionsComponent
? (group) => { ? (group) => {
return new VueHeaderActionsRenderer( return new VueHeaderActionsRenderer(
props.prefixHeaderActionsComponent as VueComponent, props.prefixHeaderActionsComponent as VueComponent,getCurrentInstance()!,
group group
); );
} }
@ -254,7 +266,7 @@ onMounted(() => {
headerRightActionComponent: props.rightHeaderActionsComponent headerRightActionComponent: props.rightHeaderActionsComponent
? (group) => { ? (group) => {
return new VueHeaderActionsRenderer( return new VueHeaderActionsRenderer(
props.rightHeaderActionsComponent as VueComponent, props.rightHeaderActionsComponent as VueComponent,getCurrentInstance()!,
group group
); );
} }
@ -270,7 +282,25 @@ onMounted(() => {
...frameworkOptions, ...frameworkOptions,
}); });
instance.value = dockview; const { clientWidth, clientHeight } = el.value;
dockview.layout(clientWidth, clientHeight);
/**
* !!! THIS IS VERY IMPORTANT
*
* Since we store a reference to `DockviewComponent` within the Vue.js world Vue.js will 'deeply Proxyify' the object
* since this is how Vue.js does its reactivity magic.
*
* We do not want Vue.js to touch the `DockviewComponent` reference since it does not need to be reactive in accordance
* to the Vue.js reactivity model and since `DockviewComponent` is written in plain TypeScript allowing Vue.js
* to proxify the reference will cause all kinds of unexpected issues
*
* @see https://vuejs.org/guide/extras/reactivity-in-depth.html
* @see https://vuejs.org/api/reactivity-advanced.html#markraw
*/
instance.value = markRaw(dockview);
emit('ready', { api: new DockviewApi(dockview) }); emit('ready', { api: new DockviewApi(dockview) });
}); });

View File

@ -1,9 +1,8 @@
import type { import type {
DockviewApi,
DockviewGroupPanel, DockviewGroupPanel,
DockviewGroupPanelApi,
GroupPanelPartInitParameters, GroupPanelPartInitParameters,
IContentRenderer, IContentRenderer,
IGroupHeaderProps,
IHeaderActionsRenderer, IHeaderActionsRenderer,
ITabRenderer, ITabRenderer,
IWatermarkRenderer, IWatermarkRenderer,
@ -18,6 +17,7 @@ import {
cloneVNode, cloneVNode,
mergeProps, mergeProps,
type DefineComponent, type DefineComponent,
type ComponentInternalInstance,
} from 'vue'; } from 'vue';
export type ComponentInterface = ComponentOptionsBase< export type ComponentInterface = ComponentOptionsBase<
@ -45,16 +45,22 @@ export type VueComponent<T = any> = DefineComponent<T>;
*/ */
export function mountVueComponent<T extends Record<string, any>>( export function mountVueComponent<T extends Record<string, any>>(
component: VueComponent<T>, component: VueComponent<T>,
parent: ComponentInternalInstance,
props: T, props: T,
element: HTMLElement element: HTMLElement
) { ) {
let vNode = createVNode(component, props); let vNode = createVNode(component, Object.freeze(props));
vNode.appContext = parent.appContext;
render(vNode, element); render(vNode, element);
let runningProps = props;
return { return {
update: (newProps: any) => { update: (newProps: any) => {
vNode = cloneVNode(vNode, mergeProps(props, newProps)); runningProps = { ...props, newProps };
vNode = cloneVNode(vNode, Object.freeze(runningProps));
render(vNode, element); render(vNode, element);
}, },
dispose: () => { dispose: () => {
@ -73,7 +79,10 @@ export class VueContentRenderer implements IContentRenderer {
return this._element; return this._element;
} }
constructor(private readonly component: VueComponent) { constructor(
private readonly component: VueComponent,
private readonly parent: ComponentInternalInstance
) {
this._element = document.createElement('div'); this._element = document.createElement('div');
this.element.className = 'dv-vue-part'; this.element.className = 'dv-vue-part';
this.element.style.height = '100%'; this.element.style.height = '100%';
@ -90,6 +99,7 @@ export class VueContentRenderer implements IContentRenderer {
this._renderDisposable?.dispose(); this._renderDisposable?.dispose();
this._renderDisposable = mountVueComponent( this._renderDisposable = mountVueComponent(
this.component, this.component,
this.parent,
props, props,
this.element this.element
); );
@ -120,7 +130,10 @@ export class VueTabRenderer implements ITabRenderer {
return this._element; return this._element;
} }
constructor(private readonly component: VueComponent) { constructor(
private readonly component: VueComponent,
private readonly parent: ComponentInternalInstance
) {
this._element = document.createElement('div'); this._element = document.createElement('div');
this.element.className = 'dv-vue-part'; this.element.className = 'dv-vue-part';
this.element.style.height = '100%'; this.element.style.height = '100%';
@ -137,6 +150,7 @@ export class VueTabRenderer implements ITabRenderer {
this._renderDisposable?.dispose(); this._renderDisposable?.dispose();
this._renderDisposable = mountVueComponent( this._renderDisposable = mountVueComponent(
this.component, this.component,
this.parent,
props, props,
this.element this.element
); );
@ -163,7 +177,10 @@ export class VueWatermarkRenderer implements IWatermarkRenderer {
return this._element; return this._element;
} }
constructor(private readonly component: VueComponent) { constructor(
private readonly component: VueComponent,
private readonly parent: ComponentInternalInstance
) {
this._element = document.createElement('div'); this._element = document.createElement('div');
this.element.className = 'dv-vue-part'; this.element.className = 'dv-vue-part';
this.element.style.height = '100%'; this.element.style.height = '100%';
@ -179,6 +196,7 @@ export class VueWatermarkRenderer implements IWatermarkRenderer {
this._renderDisposable?.dispose(); this._renderDisposable?.dispose();
this._renderDisposable = mountVueComponent( this._renderDisposable = mountVueComponent(
this.component, this.component,
this.parent,
props, props,
this.element this.element
); );
@ -211,32 +229,27 @@ export class VueHeaderActionsRenderer implements IHeaderActionsRenderer {
constructor( constructor(
private readonly component: VueComponent, private readonly component: VueComponent,
private readonly parent: ComponentInternalInstance,
group: DockviewGroupPanel group: DockviewGroupPanel
) { ) {
this._element = document.createElement('div'); this._element = document.createElement('div');
this.element.className = 'dv-vue-header-action-part'; this.element.className = 'dv-vue-header-action-part';
this._element.style.width = '100%';
this._element.style.height = '100%';
} }
init(params: { init(params: IGroupHeaderProps): void {
containerApi: DockviewApi; console.log(params);
api: DockviewGroupPanelApi;
}): void {
console.log('meeee', this.component);
const props = {
api: params.api,
containerApi: params.containerApi,
};
this._renderDisposable?.dispose(); this._renderDisposable?.dispose();
this._renderDisposable = mountVueComponent( this._renderDisposable = mountVueComponent(
this.component, this.component,
props, this.parent,
{ ...params },
this.element this.element
); );
} }
dispose(): void { dispose(): void {
console.log('dispose');
this._renderDisposable?.dispose(); this._renderDisposable?.dispose();
} }
} }

View File

@ -129,10 +129,11 @@ export const DockviewReact = React.forwardRef(
const prevProps = React.useRef<Partial<IDockviewReactProps>>({}); const prevProps = React.useRef<Partial<IDockviewReactProps>>({});
React.useEffect(() => { React.useEffect(
() => {
const changes: Partial<DockviewOptions> = {}; const changes: Partial<DockviewOptions> = {};
Object.keys(PROPERTY_KEYS).forEach((propKey) => { PROPERTY_KEYS.forEach((propKey) => {
const key = propKey as keyof DockviewOptions; const key = propKey as keyof DockviewOptions;
const propValue = props[key]; const propValue = props[key];
@ -146,7 +147,11 @@ export const DockviewReact = React.forwardRef(
} else { } else {
// not yet fully initialized // not yet fully initialized
} }
}, PROPERTY_KEYS.map((key) => props[key]).filter(Boolean));
prevProps.current = props;
},
PROPERTY_KEYS.map((key) => props[key])
);
React.useEffect(() => { React.useEffect(() => {
if (!domRef.current) { if (!domRef.current) {

View File

@ -1,37 +0,0 @@
---
slug: dockview-1.12.0-release
title: Dockview 1.12.0
tags: [release]
---
# Release Notes
Please reference docs @ [dockview.dev](https://dockview.dev).
## 🛠 Miscs
- Create framework packages in preperation for multiple framework support
These are still in active development and will be offical support soon.
- Create `dockview-react` package
- Create `dockview-angular` package
- Create `dockview-vue` package
- Move various type definitions from `dockview` to `dockview-core` in preperation for multiple framework support
- Move `IGroupPanelBaseProps` from `dockview` to `dockview-core`
- Move `IDockviewPanelHeaderProps` from `dockview` to `dockview-core`
- Move `IDockviewPanelProps` from `dockview` to `dockview-core`
- Move `IDockviewHeaderActionsProps ` from `dockview` to `dockview-core`
- Move `IGroupHeaderProps` from `dockview` to `dockview-core`
- Move `IWatermarkPanelProps` from `dockview` to `dockview-core`
- Move `DockviewReadyEvent` from `dockview` to `dockview-core`
- Depreciate `dockview` (React) `canDisplayOverlay` in favour of the `onUnhandledDragOverEvent` api event
## 🔥 Breaking changes
- Replace `dockview-core` DockviewComponent `canDisplayOverlay` option with `onUnhandledDragOverEvent` event
- Rename `createRightHeaderActionsElement` to `headerRightActionComponent`
- Rename `createLeftHeaderActionsElement` to `headerLeftActionComponent`
- Rename `createPrefixHeaderActionsElement` to `headerPrefixActionComponent`

View File

@ -0,0 +1,41 @@
---
slug: dockview-1.13.0-release
title: Dockview 1.13.0
tags: [release]
---
# Release Notes
Please reference docs @ [dockview.dev](https://dockview.dev).
## 🚀 Features
- Add `onDidActivePanelChange` event to group api [#541](https://github.com/mathuo/dockview/pull/541)
## 🛠 Miscs
- Create framework packages in preperation for multiple framework support [#541](https://github.com/mathuo/dockview/pull/541)
These are still in active development and will be offically support soon.
- Create `dockview-react` package
- Create `dockview-angular` package
- Create `dockview-vue` package
- Move various type definitions from `dockview` to `dockview-core` in preperation for multiple framework support [#541](https://github.com/mathuo/dockview/pull/541)
- Move `IGroupPanelBaseProps` from `dockview` to `dockview-core`
- Move `IDockviewPanelHeaderProps` from `dockview` to `dockview-core`
- Move `IDockviewPanelProps` from `dockview` to `dockview-core`
- Move `IDockviewHeaderActionsProps ` from `dockview` to `dockview-core`
- Move `IGroupHeaderProps` from `dockview` to `dockview-core`
- Move `IWatermarkPanelProps` from `dockview` to `dockview-core`
- Move `DockviewReadyEvent` from `dockview` to `dockview-core`
- [dockview] Depreciate `canDisplayOverlay` in favour of the `onUnhandledDragOverEvent` api event [#541](https://github.com/mathuo/dockview/pull/541)
## 🔥 Breaking changes
- [dockview-core] Replace DockviewComponent `canDisplayOverlay` option with `onUnhandledDragOverEvent` event [#541](https://github.com/mathuo/dockview/pull/541)
- [dockview-core] Rename `createRightHeaderActionsElement` to `headerRightActionComponent` [#541](https://github.com/mathuo/dockview/pull/541)
- [dockview-core] Rename `createLeftHeaderActionsElement` to `headerLeftActionComponent` [#541](https://github.com/mathuo/dockview/pull/541)
- [dockview-core] Rename `createPrefixHeaderActionsElement` to `headerPrefixActionComponent` [#541](https://github.com/mathuo/dockview/pull/541)

View File

@ -3,12 +3,11 @@ title: Nested Instances
--- ---
import { MultiFrameworkContainer } from '@site/src/components/ui/container'; import { CodeRunner } from '@site/src/components/ui/codeRunner';
import NestedDockview from '@site/sandboxes/nested-dockview/src/app';
# Nested Dockviews # Nested Dockviews
You can safely create multiple dockview instances within one page and nest dockviews within other dockviews. You can safely create multiple dockview instances within one page and nest dockviews within other dockviews.
If you wish to interact with the drop event from one dockview instance in another dockview instance you can implement the `showDndOverlay` and `onDidDrop` props on `DockviewReact`. If you wish to interact with the drop event from one dockview instance in another dockview instance you can implement the `showDndOverlay` and `onDidDrop` props on `DockviewReact`.
<MultiFrameworkContainer sandboxId="nested-dockview" react={NestedDockview} /> <CodeRunner id="dockview/nested" />

View File

@ -2,7 +2,6 @@
title: Constraints title: Constraints
--- ---
import LiveExample from '@site/src/components/ui/exampleFrame';
import { DocRef } from '@site/src/components/ui/reference/docRef' import { DocRef } from '@site/src/components/ui/reference/docRef'
:::warning :::warning
@ -13,5 +12,5 @@ Constraints come with several caveats. They are not serialized with layouts and
## Live Example ## Live Example
<LiveExample framework="react" id="dockview/constraints"/> <CodeRunner id="dockview/constraints"/>

View File

@ -2,7 +2,6 @@
title: Group Controls title: Group Controls
--- ---
import LiveExample from '@site/src/components/ui/exampleFrame';
import { DocRef } from '@site/src/components/ui/reference/docRef'; import { DocRef } from '@site/src/components/ui/reference/docRef';
This section describes how you can customize the header component of each group. This section describes how you can customize the header component of each group.
@ -39,5 +38,5 @@ return <DockviewReact
## Live Example ## Live Example
<LiveExample framework="react" id="dockview/group-actions"/> <CodeRunner id="dockview/group-actions"/>

View File

@ -3,7 +3,6 @@ title: Floating Groups
--- ---
import useBaseUrl from '@docusaurus/useBaseUrl'; import useBaseUrl from '@docusaurus/useBaseUrl';
import LiveExample from '@site/src/components/ui/exampleFrame';
import { DocRef } from '@site/src/components/ui/reference/docRef'; import { DocRef } from '@site/src/components/ui/reference/docRef';
This section describes floating groups. This section describes floating groups.
@ -76,4 +75,4 @@ You can check whether a group is floating via the `group.api.location` property.
## Live Example ## Live Example
<LiveExample framework="react" id="dockview/floating-groups"/> <CodeRunner id="dockview/floating-groups"/>

View File

@ -3,7 +3,6 @@ title: Hidden Header
--- ---
import useBaseUrl from '@docusaurus/useBaseUrl'; import useBaseUrl from '@docusaurus/useBaseUrl';
import LiveExample from '@site/src/components/ui/exampleFrame';
import { DocRef } from '@site/src/components/ui/reference/docRef'; import { DocRef } from '@site/src/components/ui/reference/docRef';
You may wish to hide the header section of a group. This can achieved through the `hidden` variable on `panel.group.header`. You may wish to hide the header section of a group. This can achieved through the `hidden` variable on `panel.group.header`.

View File

@ -2,8 +2,7 @@
title: Locked Groups title: Locked Groups
--- ---
import { MultiFrameworkContainer } from '@site/src/components/ui/container'; import { CodeRunner } from '@site/src/components/ui/codeRunner';
import DockviewLockedGroup from '@site/sandboxes/lockedgroup-dockview/src/app';
## Locked group ## Locked group
@ -21,7 +20,4 @@ panel.group.locked = 'no-drop-target';
Use `true` to keep drop zones top, right, bottom, left for the group. Use `no-drop-target` to disable all drop zones. For you to get a Use `true` to keep drop zones top, right, bottom, left for the group. Use `no-drop-target` to disable all drop zones. For you to get a
better understanding of what this means, try and drag the panels in the example below to the locked groups. better understanding of what this means, try and drag the panels in the example below to the locked groups.
<MultiFrameworkContainer <CodeRunner id="dockview/locked"/>
sandboxId="lockedgroup-dockview"
react={DockviewLockedGroup}
/>

View File

@ -3,7 +3,6 @@ title: Maximized Groups
--- ---
import { DocRef } from '@site/src/components/ui/reference/docRef'; import { DocRef } from '@site/src/components/ui/reference/docRef';
import LiveExample from '@site/src/components/ui/exampleFrame';
This section described how to maxmimize groups. This section described how to maxmimize groups.
@ -51,7 +50,7 @@ The methods exist on the panel `api` object for convenience.
## Live Examples ## Live Examples
<LiveExample framework="react" id="dockview/maximize-group"/> <CodeRunner id="dockview/maximize-group"/>

View File

@ -2,7 +2,6 @@
title: Popout Windows title: Popout Windows
--- ---
import LiveExample from '@site/src/components/ui/exampleFrame';
import { DocRef } from '@site/src/components/ui/reference/docRef'; import { DocRef } from '@site/src/components/ui/reference/docRef';
This section describes have to create popout windows. This section describes have to create popout windows.
@ -57,4 +56,4 @@ in it's original location within the grid. If the dock cannot determine the orig
choose a new location. choose a new location.
<LiveExample framework="react" id="dockview/popout-group"/> <CodeRunner id="dockview/popout-group"/>

View File

@ -2,7 +2,6 @@
title: Resizing title: Resizing
--- ---
import LiveExample from '@site/src/components/ui/exampleFrame';
import { DocRef } from '@site/src/components/ui/reference/docRef'; import { DocRef } from '@site/src/components/ui/reference/docRef';
<DocRef declaration="DockviewGroupPanelApi" methods={['height', 'width', 'setSize', 'onDidDimensionsChange']} /> <DocRef declaration="DockviewGroupPanelApi" methods={['height', 'width', 'setSize', 'onDidDimensionsChange']} />
@ -34,4 +33,4 @@ props.api.group.api.setSize({
You can see an example invoking both approaches below. You can see an example invoking both approaches below.
<LiveExample framework="react" id="dockview/resize"/> <CodeRunner framework="react" id="dockview/resize"/>

View File

@ -5,7 +5,6 @@ title: Locked
import useBaseUrl from '@docusaurus/useBaseUrl'; import useBaseUrl from '@docusaurus/useBaseUrl';
import { DocRef } from '@site/src/components/ui/reference/docRef'; import { DocRef } from '@site/src/components/ui/reference/docRef';
import LiveExample from '@site/src/components/ui/exampleFrame';
This section describes how to lock the dock to prevent movement. This section describes how to lock the dock to prevent movement.
@ -13,4 +12,4 @@ This section describes how to lock the dock to prevent movement.
You may want to combine this with `disableDnd={true}` to provide a locked grid with no dnd funtionality. See [Disable Dnd](/docs/core/dnd/disable) for more. You may want to combine this with `disableDnd={true}` to provide a locked grid with no dnd funtionality. See [Disable Dnd](/docs/core/dnd/disable) for more.
::: :::
<LiveExample framework='react' id='dockview/locked'/> <CodeRunner id='dockview/locked'/>

View File

@ -3,8 +3,6 @@ title: Overview
sidebar_position: 0 sidebar_position: 0
--- ---
import LiveExample from '@site/src/components/ui/exampleFrame';
This section provided a core overview. This section provided a core overview.
The component takes a collection of [Options](/docs/api/dockview/options) as inputs and The component takes a collection of [Options](/docs/api/dockview/options) as inputs and
@ -33,10 +31,3 @@ const component = new DockviewComponent({
``` ```
</FrameworkSpecific> </FrameworkSpecific>
## Container Resizing
The component will automatically resize to it's container.
<LiveExample framework="react" id="dockview/resize-container"/>
# Disposal Pattern

View File

@ -4,7 +4,7 @@ sidebar_position: 1
--- ---
import { DocRef } from '@site/src/components/ui/reference/docRef'; import { DocRef } from '@site/src/components/ui/reference/docRef';
import LiveExample from '@site/src/components/ui/exampleFrame'; import { CodeRunner } from '@site/src/components/ui/codeRunner';
This section describes how to add a new panel and the options you can provide. This section describes how to add a new panel and the options you can provide.
@ -48,7 +48,7 @@ api.addPanel({
api.setTitle('my_new_custom_title'); api.setTitle('my_new_custom_title');
``` ```
<LiveExample framework="react" id="dockview/update-title" height={250}/> <CodeRunner id="dockview/update-title" height={250}/>
## Provide a custom Tab renderer ## Provide a custom Tab renderer

View File

@ -4,11 +4,9 @@ sidebar_postiion: 5
--- ---
import { MultiFrameworkContainer } from '@site/src/components/ui/container'; import { MultiFrameworkContainer } from '@site/src/components/ui/container';
import { CodeRunner } from '@site/src/components/ui/codeRunner';
import RenderingDockview from '@site/sandboxes/rendering-dockview/src/app'; import RenderingDockview from '@site/sandboxes/rendering-dockview/src/app';
import LiveExample from '@site/src/components/ui/exampleFrame';
Rendering type is an important consideration when creating your application and whether your panels should be destroyed when hidden. Rendering type is an important consideration when creating your application and whether your panels should be destroyed when hidden.
:::info :::info
@ -70,7 +68,7 @@ api.addPanel({
## Live Example ## Live Example
<LiveExample framework="react" id="dockview/render-mode"/> <CodeRunner id="dockview/render-mode"/>
By default `DockviewReact` only adds to the DOM those panels that are visible, By default `DockviewReact` only adds to the DOM those panels that are visible,
@ -130,3 +128,4 @@ Toggling the checkbox you can see that when you only render those panels which a
sandboxId="rendering-dockview" sandboxId="rendering-dockview"
react={RenderingDockview} react={RenderingDockview}
/> />

View File

@ -4,7 +4,7 @@ title: Resizing
This section describes how to programatically resize a panel. This section describes how to programatically resize a panel.
import LiveExample from '@site/src/components/ui/exampleFrame'; import { CodeRunner } from '@site/src/components/ui/codeRunner';
import { DocRef } from '@site/src/components/ui/reference/docRef'; import { DocRef } from '@site/src/components/ui/reference/docRef';
<DocRef declaration="DockviewPanelApi" methods={['height', 'width', 'setSize', 'onDidDimensionsChange']} /> <DocRef declaration="DockviewPanelApi" methods={['height', 'width', 'setSize', 'onDidDimensionsChange']} />
@ -37,4 +37,4 @@ props.api.group.api.setSize({
You can see an example invoking both approaches below. You can see an example invoking both approaches below.
<LiveExample framework="react" id="dockview/resize"/> <CodeRunner id="dockview/resize"/>

View File

@ -4,7 +4,7 @@ sidebar_position: 2
--- ---
import { MultiFrameworkContainer } from '@site/src/components/ui/container'; import { MultiFrameworkContainer } from '@site/src/components/ui/container';
import CustomHeadersDockview from '@site/sandboxes/customheader-dockview/src/app'; import { CodeRunner } from '@site/src/components/ui/codeRunner';
import DockviewNative from '@site/sandboxes/fullwidthtab-dockview/src/app'; import DockviewNative from '@site/sandboxes/fullwidthtab-dockview/src/app';
import { attach as attachNativeDockview } from '@site/sandboxes/javascript/fullwidthtab-dockview/src/app'; import { attach as attachNativeDockview } from '@site/sandboxes/javascript/fullwidthtab-dockview/src/app';
import { DocRef } from '@site/src/components/ui/reference/docRef'; import { DocRef } from '@site/src/components/ui/reference/docRef';
@ -99,10 +99,7 @@ As a simple example the below attaches a custom event handler for the context me
The below example uses a custom tab renderer to reigster a popover when the user right clicked on a tab. The below example uses a custom tab renderer to reigster a popover when the user right clicked on a tab.
This still makes use of the `DockviewDefaultTab` since it's only a minor change. This still makes use of the `DockviewDefaultTab` since it's only a minor change.
<MultiFrameworkContainer <CodeRunner id="dockview/custom-header"/>
sandboxId="customheader-dockview"
react={CustomHeadersDockview}
/>
## Full Width Tab ## Full Width Tab
@ -126,15 +123,7 @@ return <DockviewReactComponent singleTabMode="fullwidth" />
typescript={attachNativeDockview} typescript={attachNativeDockview}
/> />
import DockviewTabheight from '@site/sandboxes/tabheight-dockview/src/app';
import { attach as attachTabHeightDockview } from '@site/sandboxes/javascript/tabheight-dockview/src/app';
## Tab Height ## Tab Height
Tab height can be controlled through CSS. Tab height can be controlled through CSS.
<MultiFrameworkContainer
sandboxId="tabheight-dockview"
react={DockviewTabheight}
typescript={attachTabHeightDockview}
/>

View File

@ -43,4 +43,4 @@ panel.api.updateParameters({
## Live Example ## Live Example
<LiveExample framework="react" id="dockview/update-parameters"/> <CodeRunner id="dockview/update-parameters"/>

View File

@ -2,8 +2,6 @@
title: Scrolling title: Scrolling
--- ---
import LiveExample from '@site/src/components/ui/exampleFrame';
It's important to understand how to configure the scrollbar within a panel. It's important to understand how to configure the scrollbar within a panel.
A panel will appear with a scrollbar if the the contents of your view has a fixed height. A panel will appear with a scrollbar if the the contents of your view has a fixed height.
@ -17,4 +15,4 @@ The following example contains three views:
- **Panel 2** (`height: 2000px`): A scrollbar does appear since a fixed height has been used. - **Panel 2** (`height: 2000px`): A scrollbar does appear since a fixed height has been used.
- **Panel 3**: `height: 100%` and a child component with `overflow: auto` which will enable scrollbars. - **Panel 3**: `height: 100%` and a child component with `overflow: auto` which will enable scrollbars.
<LiveExample framework="react" id="dockview/scrollbars"/> <CodeRunner id="dockview/scrollbars"/>

View File

@ -2,8 +2,7 @@
title: Loading State title: Loading State
--- ---
import { MultiFrameworkContainer } from '@site/src/components/ui/container'; import { CodeRunner } from '@site/src/components/ui/codeRunner';
import LiveExample from '@site/src/components/ui/exampleFrame';
import { DocRef } from '@site/src/components/ui/reference/docRef'; import { DocRef } from '@site/src/components/ui/reference/docRef';
This section described loading a dock layout. This section described loading a dock layout.
@ -43,5 +42,6 @@ return <DockviewComponent onReady={onReady}/>;
# Live Example # Live Example
<LiveExample framework="react" id="dockview/layout"/> <CodeRunner id="dockview/layout"/>

View File

@ -2,9 +2,7 @@
title: Saving State title: Saving State
--- ---
import { CodeRunner } from '@site/src/components/ui/codeRunner';
import { MultiFrameworkContainer } from '@site/src/components/ui/container';
import LiveExample from '@site/src/components/ui/exampleFrame';
import { DocRef } from '@site/src/components/ui/reference/docRef'; import { DocRef } from '@site/src/components/ui/reference/docRef';
This section describes how to serialize a dockview instance. This section describes how to serialize a dockview instance.
@ -39,5 +37,4 @@ return <DockviewComponent onReady={onReady}/>
# Live Example # Live Example
<LiveExample framework="react" id="dockview/layout"/> <CodeRunner id="dockview/layout"/>

View File

@ -5,7 +5,6 @@ title: Watermark
import useBaseUrl from '@docusaurus/useBaseUrl'; import useBaseUrl from '@docusaurus/useBaseUrl';
import { DocRef } from '@site/src/components/ui/reference/docRef'; import { DocRef } from '@site/src/components/ui/reference/docRef';
import LiveExample from '@site/src/components/ui/exampleFrame';
When there is nothing else to display. When there is nothing else to display.
@ -28,4 +27,4 @@ The following properties can be set to configure the behaviours of floating grou
## Live Examples ## Live Examples
<LiveExample framework="react" id="dockview/watermark"/> <CodeRunner id="dockview/watermark"/>

View File

@ -5,6 +5,4 @@ sidebar_position: 3
A *tabview* can be created using a dock and preventing some default behaviours. A *tabview* can be created using a dock and preventing some default behaviours.
import LiveExample from '@site/src/components/ui/exampleFrame'; <CodeRunner id='dockview/tabview' />
<LiveExample framework='react' id='dockview/tabview' />

View File

@ -7,7 +7,7 @@ sidebar_position: 0
Learn how to install Dockview for a selection of frameworks. Learn how to install Dockview for a selection of frameworks.
<FrameworkSpecific framework='JavaScript'> <FrameworkSpecific framework='JavaScript'>
Firstly, install the `dockvire-core` library: Firstly, install the `dockview-core` library:
```sh ```sh
npm install dockview-core npm install dockview-core
@ -22,8 +22,3 @@ npm install dockview
``` ```
</FrameworkSpecific> </FrameworkSpecific>
import { IsolatedCodeExample } from '@site/src/components/ui/isolatedCodeExample';
<IsolatedCodeExample id="dockview/basic" framework='react'/>
<IsolatedCodeExample id="dockview/basic" framework='vue'/>

View File

@ -5,9 +5,7 @@ description: Gridview Documentation
import { MultiFrameworkContainer } from '@site/src/components/ui/container'; import { MultiFrameworkContainer } from '@site/src/components/ui/container';
import SimpleGridview from '@site/sandboxes/simple-gridview/src/app'; import SimpleGridview from '@site/sandboxes/simple-gridview/src/app';
import EditorGridview from '@site/sandboxes/editor-gridview/src/app'; import EditorGridview from '@site/sandboxes/editor-gridview/src/app';
// import SimpleGridview from '@site/sandboxes/simple-gridview/src/app';
import { EventsGridview } from '@site/src/components/gridview/events'; import { EventsGridview } from '@site/src/components/gridview/events';
// import IDEExample from '@site/sandboxes/ide-example/src/app';
import Link from '@docusaurus/Link'; import Link from '@docusaurus/Link';
import { DocRef } from '@site/src/components/ui/reference/docRef'; import { DocRef } from '@site/src/components/ui/reference/docRef';

View File

@ -4,10 +4,9 @@ sidebar_position: 0
--- ---
import { MultiFrameworkContainer } from '@site/src/components/ui/container'; import { MultiFrameworkContainer } from '@site/src/components/ui/container';
import { CodeRunner } from '@site/src/components/ui/codeRunner';
import SimpleDockview from '@site/sandboxes/simple-dockview/src/app';
import DockviewExampleApp from '@site/sandboxes/example-app-dockview/src/app'; import DockviewExampleApp from '@site/sandboxes/example-app-dockview/src/app';
import { attach as attachSimpleDockview } from '@site/sandboxes/javascript/simple-dockview/src/app';
<MultiFrameworkContainer <MultiFrameworkContainer
@ -20,11 +19,7 @@ import { attach as attachSimpleDockview } from '@site/sandboxes/javascript/simpl
Dockview is an abstraction built on top of [Gridviews](./gridview) where each view is a container of many tabbed panels. Dockview is an abstraction built on top of [Gridviews](./gridview) where each view is a container of many tabbed panels.
<MultiFrameworkContainer <CodeRunner id="dockview/basic"/>
sandboxId="simple-dockview"
react={SimpleDockview}
typescript={attachSimpleDockview}
/>
<br /> <br />
@ -60,19 +55,3 @@ const MyComponent = (props: IDockviewPanelProps<{ title: string }>) => {
return <div>{`My first panel has the title: ${props.params.title}`}</div>; return <div>{`My first panel has the title: ${props.params.title}`}</div>;
}; };
``` ```

View File

@ -4,12 +4,9 @@ description: A zero dependency layout manager supporting ReactJS and Vanilla Typ
title: Introduction title: Introduction
--- ---
import { MultiFrameworkContainer } from '@site/src/components/ui/container';
import { SimpleSplitview } from '@site/src/components/simpleSplitview'; import { SimpleSplitview } from '@site/src/components/simpleSplitview';
import { SimpleGridview } from '@site/src/components/simpleGridview'; import { SimpleGridview } from '@site/src/components/simpleGridview';
import { SimplePaneview } from '@site/src/components/simplePaneview'; import { SimplePaneview } from '@site/src/components/simplePaneview';
// import DockviewDemo from '@site/sandboxes/demo-dockview/src/app';
import Link from '@docusaurus/Link'; import Link from '@docusaurus/Link';
**dockview** is a zero dependency layout manager that supports tab, grids and splitviews. **dockview** is a zero dependency layout manager that supports tab, grids and splitviews.
@ -35,11 +32,6 @@ There are 4 components you may want to use:
<h2>Dockview</h2> <h2>Dockview</h2>
</Link> </Link>
{/* <MultiFrameworkContainer
height={500}
sandboxId="demo-dockview"
react={DockviewDemo}
/> */}
<Link to="./components/splitview"> <Link to="./components/splitview">
<h2>Splitview</h2> <h2>Splitview</h2>

View File

@ -5,11 +5,13 @@
"scripts": { "scripts": {
"build": "npm run create-templates && docusaurus build", "build": "npm run create-templates && docusaurus build",
"clear": "docusaurus clear", "clear": "docusaurus clear",
"start": "docusaurus start", "start": "concurrently \"docusaurus start\" \"npm run start-esm-server\"",
"start-esm-server": "node web-server/index.mjs",
"swizzle": "docusaurus swizzle @docusaurus/theme-classic", "swizzle": "docusaurus swizzle @docusaurus/theme-classic",
"docs:version": "docusaurus docs:version", "docs:version": "docusaurus docs:version",
"typecheck": "tsc", "typecheck": "tsc",
"create-templates": "node scripts/buildTemplates.mjs" "create-templates": "node scripts/buildTemplates.mjs",
"create-templates:local": "node scripts/buildTemplates.mjs --local"
}, },
"browserslist": { "browserslist": {
"production": [ "production": [

View File

@ -1,5 +1,6 @@
import fs from 'fs-extra'; import fs from 'fs-extra';
import * as path from 'path'; import * as path from 'path';
import { argv } from 'process';
import { fileURLToPath } from 'url'; import { fileURLToPath } from 'url';
@ -8,7 +9,7 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
const REACT_VERSION = '18.2.0'; const REACT_VERSION = '18.2.0';
const VUE_VERSION = '3.4.21'; const VUE_VERSION = '3.4.21';
const DOCKVIEW_VERSION = '1.11.0'; const DOCKVIEW_VERSION = '1.11.0';
const USE_LOCAL_CDN = true; const USE_LOCAL_CDN = argv.slice(2).includes('--local');
const local = 'http://localhost:1111'; const local = 'http://localhost:1111';
@ -35,7 +36,7 @@ const DOCKVIEW_CDN = {
'dockview-vue': `${local}/dockview-vue/dist/dockview-vue.es.js`, 'dockview-vue': `${local}/dockview-vue/dist/dockview-vue.es.js`,
}, },
}, },
js: { typescript: {
remote: { remote: {
'dockview-core': `https://cdn.jsdelivr.net/npm/dockview-core@${DOCKVIEW_VERSION}/dist/dockview-core.esm.js`, 'dockview-core': `https://cdn.jsdelivr.net/npm/dockview-core@${DOCKVIEW_VERSION}/dist/dockview-core.esm.js`,
'dockview-core/': `https://cdn.jsdelivr.net/npm/dockview-core@${DOCKVIEW_VERSION}/`, 'dockview-core/': `https://cdn.jsdelivr.net/npm/dockview-core@${DOCKVIEW_VERSION}/`,
@ -57,8 +58,9 @@ const IMPORTS_PATHS = {
vue: { vue: {
vue: `https://cdn.jsdelivr.net/npm/vue@${VUE_VERSION}/dist/vue.esm-browser.js`, vue: `https://cdn.jsdelivr.net/npm/vue@${VUE_VERSION}/dist/vue.esm-browser.js`,
'@vue/reactivity': `https://esm.sh/@vue/reactivity@${VUE_VERSION}`, '@vue/reactivity': `https://esm.sh/@vue/reactivity@${VUE_VERSION}`,
'vue-sfc-loader': `https://cdn.jsdelivr.net/npm/vue3-sfc-loader@0.9.5/dist/vue3-sfc-loader.js`,
}, },
js: {}, typescript: {},
angular: {}, angular: {},
}; };
@ -82,7 +84,7 @@ const input_dir = path.join(__dirname, '../templates');
const output = path.join(__dirname, '../static/templates'); const output = path.join(__dirname, '../static/templates');
const COMPONENTS = ['dockview']; const COMPONENTS = ['dockview'];
const FRAMEWORKS = ['react', 'vue']; const FRAMEWORKS = ['react', 'vue', 'typescript'];
const list = []; const list = [];

View File

@ -3,7 +3,6 @@ import HomepageFeatures from '.';
import { BrowserHeader } from '../ui/browserHeader'; import { BrowserHeader } from '../ui/browserHeader';
import { MultiFrameworkContainer } from '../ui/container'; import { MultiFrameworkContainer } from '../ui/container';
import * as React from 'react'; import * as React from 'react';
// import DockviewDemo from '@site/sandboxes/demo-dockview/src/app';
import DockviewDemo2 from '@site/sandboxes/dockview-app/src/app'; import DockviewDemo2 from '@site/sandboxes/dockview-app/src/app';
export const Introduction = () => { export const Introduction = () => {
@ -25,11 +24,6 @@ export const Introduction = () => {
</div> </div>
<div style={{ padding: '20px' }}> <div style={{ padding: '20px' }}>
<BrowserHeader /> <BrowserHeader />
{/* <MultiFrameworkContainer
height={750}
sandboxId="demo-dockview"
react={DockviewDemo}
/> */}
</div> </div>
<div style={{ padding: '20px' }}> <div style={{ padding: '20px' }}>
<BrowserHeader /> <BrowserHeader />

View File

@ -11,7 +11,7 @@ const frameworks = [
const activeFrameworkGlobal = new DockviewEmitter<string>({ replay: true }); const activeFrameworkGlobal = new DockviewEmitter<string>({ replay: true });
function useActiveFramework(): [string, (value: string) => void] { export function useActiveFramework(): [string, (value: string) => void] {
const [value, setValue] = React.useState<string>( const [value, setValue] = React.useState<string>(
localStorage.getItem('dv-docs-framework') ?? frameworks[0].value localStorage.getItem('dv-docs-framework') ?? frameworks[0].value
); );

View File

@ -0,0 +1,66 @@
import * as React from 'react';
import { useActiveFramework } from '../frameworkSpecific';
import BrowserOnly from '@docusaurus/BrowserOnly';
const BASE_SANDBOX_URL =
'https://codesandbox.io/s/github/mathuo/dockview/tree/master/packages/docs';
export const _CodeRunner = (props: {
id: string;
framework: string;
height: number;
}) => {
useActiveFramework();
const sandboxUrl = `${BASE_SANDBOX_URL}/templates/${props.id}/${props.framework}`;
const path = `/templates/${props.id}/${props.framework}/index.html`;
return (
<div>
<iframe
src={path}
style={{ width: '100%', height: `${props.height ?? 300}px` }}
/>
<div style={{ display: 'flex', justifyContent: 'flex-end' }}>
<CodeSandbox url={sandboxUrl} />
</div>
</div>
);
};
export const CodeRunner = (props: { id: string; height: number }) => {
const [framework] = useActiveFramework();
return (
<BrowserOnly>
{() => (
<_CodeRunner {...props} framework={framework.toLowerCase()} />
)}
</BrowserOnly>
);
};
const CodeSandbox = (props: { url: string }) => {
return (
<span
className="codesandbox-button"
style={{ display: 'flex', alignItems: 'center' }}
>
<span className="codesandbox-button-pretext">{`Open in `}</span>
<a
href={props.url}
target={'_blank'}
rel="noopener"
className="codesandbox-button-content"
>
<span
style={{
fontWeight: 'bold',
paddingRight: '4px',
}}
>
CodeSandbox
</span>
</a>
</span>
);
};

View File

@ -1,16 +0,0 @@
import * as React from 'react';
export const IsolatedCodeExample = (props: {
id: string;
framework: string;
height: number;
}) => {
const path = `/templates/${props.id}/${props.framework}/index.html`;
return (
<iframe
src={path}
style={{ width: '100%', height: `${props.height ?? 300}px` }}
/>
);
};

View File

@ -2,6 +2,7 @@ import React from 'react';
// Import the original mapper // Import the original mapper
import MDXComponents from '@theme-original/MDXComponents'; import MDXComponents from '@theme-original/MDXComponents';
import { FrameworkSpecific } from '@site/src/components/frameworkSpecific'; import { FrameworkSpecific } from '@site/src/components/frameworkSpecific';
import { CodeRunner } from '../components/ui/codeRunner';
export default { export default {
// Re-use the default mapping // Re-use the default mapping
@ -9,4 +10,5 @@ export default {
// Map the "<Highlight>" tag to our Highlight component // Map the "<Highlight>" tag to our Highlight component
// `Highlight` will receive all props that were passed to `<Highlight>` in MDX // `Highlight` will receive all props that were passed to `<Highlight>` in MDX
FrameworkSpecific, FrameworkSpecific,
CodeRunner,
}; };

View File

@ -0,0 +1,47 @@
import 'dockview-core/dist/styles/dockview.css';
import {
DockviewApi,
DockviewComponent,
GroupPanelPartInitParameters,
IContentRenderer,
} from 'dockview-core';
class Panel implements IContentRenderer {
private readonly _element: HTMLElement;
get element(): HTMLElement {
return this._element;
}
constructor() {
this._element = document.createElement('div');
this._element.style.color = 'white';
}
init(parameters: GroupPanelPartInitParameters): void {
this._element.textContent = 'Hello World';
}
}
document.getElementById('app').className = 'dockview-theme-abyss';
const dockview = new DockviewComponent({
parentElement: document.getElementById('app'),
components: { default: Panel },
});
const api = new DockviewApi(dockview);
api.addPanel({
id: 'panel_1',
component: 'default',
title: 'Panel 1',
});
api.addPanel({
id: 'panel_2',
component: 'default',
position: { referencePanel: 'panel_1', direction: 'right' },
title: 'Panel 2',
});

View File

@ -36,7 +36,7 @@ const App = defineComponent({
'dockview-vue': DockviewVue, 'dockview-vue': DockviewVue,
Panel, Panel,
}, },
setup() { data() {
return { return {
components: { components: {
panel: Panel, panel: Panel,
@ -45,8 +45,6 @@ const App = defineComponent({
}, },
methods: { methods: {
onReady(event: DockviewReadyEvent) { onReady(event: DockviewReadyEvent) {
console.log('ready');
event.api.addPanel({ event.api.addPanel({
id: 'panel_1', id: 'panel_1',
component: 'panel', component: 'panel',

View File

@ -9,9 +9,5 @@ const rootElement = document.getElementById('app');
if (rootElement) { if (rootElement) {
const root = ReactDOMClient.createRoot(rootElement); const root = ReactDOMClient.createRoot(rootElement);
root.render( root.render(<App />);
<div className="app">
<App />
</div>
);
} }

View File

@ -0,0 +1,32 @@
{
"name": "dockview.update-parameters",
"description": "",
"keywords": [
"dockview"
],
"version": "1.0.0",
"main": "src/index.tsx",
"dependencies": {
"dockview": "*",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/react": "^18.0.28",
"@types/react-dom": "^18.0.11",
"typescript": "^4.9.5",
"react-scripts": "*"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
},
"browserslist": [
">0.2%",
"not dead",
"not ie <= 11",
"not op_mini all"
]
}

View File

@ -0,0 +1,85 @@
import {
DockviewReact,
DockviewReadyEvent,
IDockviewPanelHeaderProps,
IDockviewPanelProps,
} from 'dockview';
import React from 'react';
interface CustomParams {
myValue: number;
}
const components = {
default: (props: IDockviewPanelProps<CustomParams>) => {
const [running, setRunning] = React.useState<boolean>(false);
React.useEffect(() => {
if (!running) {
return;
}
const interval = setInterval(() => {
props.api.updateParameters({ myValue: Date.now() });
}, 1000);
props.api.updateParameters({ myValue: Date.now() });
return () => {
clearInterval(interval);
};
}, [running]);
return (
<div style={{ height: '100%', padding: '20px', color: 'white' }}>
<div>{props.api.title}</div>
<button onClick={() => setRunning(!running)}>
{running ? 'Stop' : 'Start'}
</button>
<span>{`value: ${props.params.myValue}`}</span>
</div>
);
},
};
const tabComponents = {
default: (props: IDockviewPanelHeaderProps<CustomParams>) => {
return (
<div>
<div>{`custom tab: ${props.api.title}`}</div>
<span>{`value: ${props.params.myValue}`}</span>
</div>
);
},
};
export const App: React.FC = (props: { theme?: string }) => {
const onReady = (event: DockviewReadyEvent) => {
event.api.addPanel({
id: 'panel_1',
component: 'default',
tabComponent: 'default',
params: {
myValue: Date.now(),
},
});
event.api.addPanel({
id: 'panel_2',
component: 'default',
tabComponent: 'default',
params: {
myValue: Date.now(),
},
});
};
return (
<DockviewReact
components={components}
tabComponents={tabComponents}
onReady={onReady}
className={props.theme || 'dockview-theme-abyss'}
/>
);
};
export default App;

View File

@ -0,0 +1,13 @@
import React from 'react';
import ReactDOMClient from 'react-dom/client';
import 'dockview/dist/styles/dockview.css';
import App from './app.tsx';
const rootElement = document.getElementById('app');
if (rootElement) {
const root = ReactDOMClient.createRoot(rootElement);
root.render(<App />);
}

View File

@ -0,0 +1,18 @@
{
"compilerOptions": {
"outDir": "build/dist",
"module": "esnext",
"target": "es5",
"lib": ["es6", "dom"],
"sourceMap": true,
"allowJs": true,
"jsx": "react-jsx",
"moduleResolution": "node",
"rootDir": "src",
"forceConsistentCasingInFileNames": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noImplicitAny": true,
"strictNullChecks": true
}
}

View File

@ -0,0 +1,190 @@
import 'dockview-core/dist/styles/dockview.css';
import { PropType, createApp, defineComponent } from 'vue';
import { DockviewVue } from 'dockview-vue';
import {
DockviewReadyEvent,
IDockviewPanelHeaderProps,
IDockviewPanelProps,
} from 'dockview-core';
const Panel = defineComponent({
name: 'Panel',
props: {
api: {
type: Object as PropType<IDockviewPanelProps['api']>,
required: true,
},
containerApi: {
type: Object as PropType<IDockviewPanelProps['containerApi']>,
required: true,
},
params: {
type: Object as PropType<IDockviewPanelProps['params']>,
required: true,
},
},
data() {
return {
running: false,
title: '',
};
},
methods: {
onClick() {
this.running = !this.running;
},
},
watch: {
running(newValue, oldValue) {
if (!newValue) {
return;
}
console.log('interval');
const interval = setInterval(() => {
this.api.updateParameters({ myValue: Date.now() });
}, 1000);
this.api.updateParameters({ myValue: Date.now() });
return () => {
clearInterval(interval);
};
},
},
mounted() {
const disposable = this.api.onDidTitleChange(() => {
this.title = this.api.title;
});
this.title = this.api.title;
return () => {
disposable.dispose();
};
},
template: `
<div style="height:100%;padding:20px;color:white;">
<div>{{title}}</div>
<button v-if="running" @click="onClick">Stop</button>
<button v-if="!running" @click="onClick">Start</button>
<span>{{title}}</span>
</div>`,
});
interface CustomParams {
myValue: number;
}
const Tab = defineComponent({
name: 'Tab',
props: {
api: {
type: Object as PropType<
IDockviewPanelHeaderProps<CustomParams>['api']
>,
required: true,
},
containerApi: {
type: Object as PropType<
IDockviewPanelHeaderProps<CustomParams>['containerApi']
>,
required: true,
},
params: {
type: Object as PropType<
IDockviewPanelHeaderProps<CustomParams>['params']
>,
required: true,
},
},
data() {
return {
myValue: this.params.myValue,
title: '',
};
},
methods: {
onClick() {
this.running = !this.running;
},
},
watch: {
params(newValue, oldValue) {
this.myValue = newValue.myValue;
},
running(newValue, oldValue) {
if (!newValue) {
return;
}
const interval = setInterval(() => {
this.api.updateParameters({ myValue: Date.now() });
}, 1000);
this.api.updateParameters({ myValue: Date.now() });
return () => {
clearInterval(interval);
};
},
},
template: `
<div>
<div>custom tab: {{title}}</div>
<span>value: {{myValue}}</span>
</div>`,
});
const App = defineComponent({
name: 'App',
components: {
'dockview-vue': DockviewVue,
Panel,
Tab,
},
data() {
return {
components: {
default: Panel,
},
tabComponents: {
default: Tab,
},
};
},
methods: {
onReady(event: DockviewReadyEvent) {
event.api.addPanel({
id: 'panel_1',
component: 'default',
tabComponent: 'default',
params: {
myValue: Date.now(),
},
});
event.api.addPanel({
id: 'panel_2',
component: 'default',
tabComponent: 'default',
params: {
myValue: Date.now(),
},
});
},
},
template: `
<dockview-vue
style="width:100%;height:100%"
class="dockview-theme-abyss"
@ready="onReady"
:components="components"
:tabComponents="tabComponents"
</dockview-vue>`,
});
const app = createApp(App);
app.config.errorHandler = (err) => {
console.log(err);
};
app.mount(document.getElementById('app')!);

View File

@ -18,6 +18,7 @@ import {
RightControls, RightControls,
} from './controls.tsx'; } from './controls.tsx';
import { usePanelApiMetadata } from './debugPanel.tsx'; import { usePanelApiMetadata } from './debugPanel.tsx';
import { LogLine, LogLines } from './logLines.tsx';
const components = { const components = {
default: (props: IDockviewPanelProps) => { default: (props: IDockviewPanelProps) => {
@ -83,9 +84,9 @@ const colors = [
let count = 0; let count = 0;
const DockviewDemo = (props: { theme?: string }) => { const DockviewDemo = (props: { theme?: string }) => {
const [logLines, setLogLines] = React.useState< const [logLines, setLogLines] = React.useState<LogLine[]>([]);
{ text: string; timestamp?: Date; backgroundColor?: string }[] const [emittedLogsOnCurrentStackFrame, setEmittedLogsOnCurrentStackFrame] =
>([]); React.useState<LogLine[]>([]);
const [panels, setPanels] = React.useState<string[]>([]); const [panels, setPanels] = React.useState<string[]>([]);
const [groups, setGroups] = React.useState<string[]>([]); const [groups, setGroups] = React.useState<string[]>([]);
@ -94,41 +95,47 @@ const DockviewDemo = (props: { theme?: string }) => {
const [activePanel, setActivePanel] = React.useState<string>(); const [activePanel, setActivePanel] = React.useState<string>();
const [activeGroup, setActiveGroup] = React.useState<string>(); const [activeGroup, setActiveGroup] = React.useState<string>();
const [pending, setPending] = React.useState<
{ text: string; timestamp?: Date }[]
>([]);
const addLogLine = (message: string) => { const addLogLine = (message: string) => {
setPending((line) => [ setEmittedLogsOnCurrentStackFrame((line) => [
{ text: message, timestamp: new Date() }, { text: message, timestamp: new Date() },
...line, ...line,
]); ]);
}; };
React.useLayoutEffect(() => { React.useLayoutEffect(() => {
if (pending.length === 0) { if (emittedLogsOnCurrentStackFrame.length === 0) {
return; return;
} }
const color = colors[count++ % colors.length]; const color = colors[count++ % colors.length];
setLogLines((lines) => [ setLogLines((lines) => [
...pending.map((_) => ({ ..._, backgroundColor: color })), ...emittedLogsOnCurrentStackFrame.map((_) => ({
..._,
backgroundColor: color,
})),
...lines, ...lines,
]); ]);
setPending([]); setEmittedLogsOnCurrentStackFrame([]);
}, [pending]); }, [emittedLogsOnCurrentStackFrame]);
const onReady = (event: DockviewReadyEvent) => { const onReady = (event: DockviewReadyEvent) => {
setApi(event.api); setApi(event.api);
};
event.api.onDidAddPanel((event) => { React.useEffect(() => {
if (!api) {
return;
}
const disposables = [
api.onDidAddPanel((event) => {
setPanels((_) => [..._, event.id]); setPanels((_) => [..._, event.id]);
addLogLine(`Panel Added ${event.id}`); addLogLine(`Panel Added ${event.id}`);
}); }),
event.api.onDidActivePanelChange((event) => { api.onDidActivePanelChange((event) => {
setActivePanel(event?.id); setActivePanel(event?.id);
addLogLine(`Panel Activated ${event?.id}`); addLogLine(`Panel Activated ${event?.id}`);
}); }),
event.api.onDidRemovePanel((event) => { api.onDidRemovePanel((event) => {
setPanels((_) => { setPanels((_) => {
const next = [..._]; const next = [..._];
next.splice( next.splice(
@ -139,14 +146,14 @@ const DockviewDemo = (props: { theme?: string }) => {
return next; return next;
}); });
addLogLine(`Panel Removed ${event.id}`); addLogLine(`Panel Removed ${event.id}`);
}); }),
event.api.onDidAddGroup((event) => { api.onDidAddGroup((event) => {
setGroups((_) => [..._, event.id]); setGroups((_) => [..._, event.id]);
addLogLine(`Group Added ${event.id}`); addLogLine(`Group Added ${event.id}`);
}); }),
event.api.onDidRemoveGroup((event) => { api.onDidRemoveGroup((event) => {
setGroups((_) => { setGroups((_) => {
const next = [..._]; const next = [..._];
next.splice( next.splice(
@ -157,26 +164,31 @@ const DockviewDemo = (props: { theme?: string }) => {
return next; return next;
}); });
addLogLine(`Group Removed ${event.id}`); addLogLine(`Group Removed ${event.id}`);
}); }),
api.onDidActiveGroupChange((event) => {
event.api.onDidActiveGroupChange((event) => {
setActiveGroup(event?.id); setActiveGroup(event?.id);
addLogLine(`Group Activated ${event?.id}`); addLogLine(`Group Activated ${event?.id}`);
}); }),
];
let success = false;
const state = localStorage.getItem('dv-demo-state'); const state = localStorage.getItem('dv-demo-state');
if (state) { if (state) {
try { try {
event.api.fromJSON(JSON.parse(state)); api.fromJSON(JSON.parse(state));
return; success = true;
} catch { } catch {
localStorage.removeItem('dv-demo-state'); localStorage.removeItem('dv-demo-state');
} }
return;
} }
defaultConfig(event.api); if (!success) {
}; defaultConfig(api);
}
return disposables.forEach((disposable) => disposable.dispose());
}, [api]);
return ( return (
<div <div
@ -223,59 +235,13 @@ const DockviewDemo = (props: { theme?: string }) => {
/> />
<div <div
style={{ style={{
// height: '200px',
width: '300px', width: '300px',
backgroundColor: 'black', backgroundColor: 'black',
color: 'white', color: 'white',
overflow: 'auto', overflow: 'auto',
}} }}
> >
{logLines.map((line, i) => { <LogLines lines={logLines} />
return (
<div
style={{
height: '30px',
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
fontSize: '13px',
display: 'flex',
alignItems: 'center',
backgroundColor: line.backgroundColor,
}}
key={i}
>
<span
style={{
display: 'inline-block',
width: '20px',
color: 'gray',
borderRight: '1px solid gray',
marginRight: '4px',
paddingLeft: '2px',
height: '100%',
}}
>
{logLines.length - i}
</span>
<span>
{line.timestamp && (
<span
style={{
fontSize: '0.7em',
padding: '0px 2px',
}}
>
{line.timestamp
.toISOString()
.substring(11, 23)}
</span>
)}
<span>{line.text}</span>
</span>
</div>
);
})}
</div> </div>
</div> </div>
</div> </div>

View File

@ -9,9 +9,5 @@ const rootElement = document.getElementById('app');
if (rootElement) { if (rootElement) {
const root = ReactDOMClient.createRoot(rootElement); const root = ReactDOMClient.createRoot(rootElement);
root.render( root.render(<App />);
<div className="app">
<App />
</div>
);
} }

View File

@ -0,0 +1,54 @@
import React from 'react';
export type LogLine = {
text: string;
timestamp?: Date;
backgroundColor?: string;
};
export const LogLines = (props: { lines: LogLine[] }) => {
return props.lines.map((line, i) => {
return (
<div
style={{
height: '30px',
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
fontSize: '13px',
display: 'flex',
alignItems: 'center',
backgroundColor: line.backgroundColor,
}}
key={i}
>
<span
style={{
display: 'inline-block',
width: '20px',
color: 'gray',
borderRight: '1px solid gray',
marginRight: '4px',
paddingLeft: '2px',
height: '100%',
}}
>
{props.lines.length - i}
</span>
<span>
{line.timestamp && (
<span
style={{
fontSize: '0.7em',
padding: '0px 2px',
}}
>
{line.timestamp.toISOString().substring(11, 23)}
</span>
)}
<span>{line.text}</span>
</span>
</div>
);
});
};

View File

@ -9,9 +9,5 @@ const rootElement = document.getElementById('app');
if (rootElement) { if (rootElement) {
const root = ReactDOMClient.createRoot(rootElement); const root = ReactDOMClient.createRoot(rootElement);
root.render( root.render(<App />);
<div className="app">
<App />
</div>
);
} }

View File

@ -9,9 +9,5 @@ const rootElement = document.getElementById('app');
if (rootElement) { if (rootElement) {
const root = ReactDOMClient.createRoot(rootElement); const root = ReactDOMClient.createRoot(rootElement);
root.render( root.render(<App />);
<div className="app">
<App />
</div>
);
} }

View File

@ -26,14 +26,6 @@ const components = {
}, },
}; };
const counter = (() => {
let i = 0;
return {
next: () => ++i,
};
})();
function loadDefaultLayout(api: DockviewApi) { function loadDefaultLayout(api: DockviewApi) {
api.addPanel({ api.addPanel({
id: 'panel_1', id: 'panel_1',

View File

@ -9,9 +9,5 @@ const rootElement = document.getElementById('app');
if (rootElement) { if (rootElement) {
const root = ReactDOMClient.createRoot(rootElement); const root = ReactDOMClient.createRoot(rootElement);
root.render( root.render(<App />);
<div className="app">
<App />
</div>
);
} }

View File

@ -0,0 +1,264 @@
import 'dockview-core/dist/styles/dockview.css';
import { PropType, createApp, defineComponent } from 'vue';
import { DockviewVue } from 'dockview-vue';
import {
DockviewApi,
DockviewReadyEvent,
IDockviewHeaderActionsProps,
IDockviewPanelProps,
} from 'dockview-core';
let panelCount = 0;
const MaterialIcon = defineComponent({
name: 'MaterialIcon',
props: {
icon: {
type: String,
required: true,
},
title: {
type: String,
required: false,
},
},
emits: ['click'],
data() {
return {
title: this.title,
icon: this.icon,
};
},
methods: {
onClick() {
this.$emit('click');
},
},
template: `
<div
@click="onClick"
title="title"
style="display:flex;justify-content:center;align-items:center;width:30px;height:100%;font-size:18px;">
<span class="material-symbols-outlined" style="font-size:inherit;cursor:pointer;">
{{icon}}
</span>
</div>`,
});
const LeftAction = defineComponent({
name: 'LeftAction',
props: {
containerApi: {
type: Object as PropType<
IDockviewHeaderActionsProps['containerApi']
>,
required: true,
},
api: {
type: Object as PropType<IDockviewHeaderActionsProps['api']>,
required: true,
},
group: {
type: Object as PropType<IDockviewHeaderActionsProps['group']>,
required: true,
},
},
components: {
'material-icon': MaterialIcon,
},
methods: {
onClick() {
this.containerApi.addPanel({
id: (++panelCount).toString(),
title: `Tab ${panelCount}`,
component: 'default',
});
},
},
template: `
<div style="height:100%;color:white;padding:0px 4px;">
<material-icon @click="onClick" icon="add"></material-icon>
</div>`,
});
const RightAction = defineComponent({
name: 'RightAction',
props: {
containerApi: {
type: Object as PropType<
IDockviewHeaderActionsProps['containerApi']
>,
required: true,
},
api: {
type: Object as PropType<IDockviewHeaderActionsProps['api']>,
required: true,
},
group: {
type: Object as PropType<IDockviewHeaderActionsProps['group']>,
required: true,
},
},
components: {
'material-icon': MaterialIcon,
},
data() {
return {
floating: this.api.location.type === 'floating',
};
},
methods: {
onClick() {
if (this.floating) {
const group = this.containerApi.addGroup();
this.group.api.moveTo({ group });
} else {
this.containerApi.addFloatingGroup(this.group);
}
},
},
mounted() {
const disposable = this.group.api.onDidLocationChange((event) => {
this.floating = event.location.type === 'floating';
});
return () => {
disposable.dispose();
};
},
template: `
<div style="height:100%;color:white;padding:0px 4px">
<material-icon v-if="floating" @click="onClick" icon="jump_to_element"></material-icon>
<material-icon v-if="!floating" @click="onClick" icon="back_to_tab"></material-icon>
</div>`,
});
const Panel = defineComponent({
name: 'Panel',
props: {
api: {
type: Object as PropType<IDockviewPanelProps['api']>,
required: true,
},
containerApi: {
type: Object as PropType<IDockviewPanelProps['containerApi']>,
required: true,
},
params: {
type: Object as PropType<IDockviewPanelProps['params']>,
required: true,
},
},
data() {
return {
title: '',
};
},
mounted() {
const disposable = this.api.onDidTitleChange(() => {
this.title = this.api.title;
});
this.title = this.api.title;
return () => {
disposable.dispose();
};
},
template: `
<div style="color:white;">
<div>{{title}}</div>
</div>`,
});
const App = defineComponent({
name: 'App',
components: {
'dockview-vue': DockviewVue,
Panel,
LeftAction,
RightAction,
},
data() {
return {
components: {
default: Panel,
},
leftAction: LeftAction,
rightAction: RightAction,
api: null as DockviewApi | null,
bounds: undefined,
disableFloatingGroups: false,
};
},
methods: {
onAddFloatingGroup() {
this.api.addPanel({
id: (++panelCount).toString(),
title: `Tab ${panelCount}`,
component: 'default',
floating: { width: 250, height: 150, x: 50, y: 50 },
});
},
onToggleBounds() {
this.bounds =
this.bounds === undefined ? 'boundedWithinViewport' : undefined;
},
onToggleEnabled() {
this.disableFloatingGroups = !this.disableFloatingGroups;
},
onReady(event: DockviewReadyEvent) {
event.api.addPanel({
id: 'panel_1',
component: 'default',
title: 'Panel 1',
});
event.api.addPanel({
id: 'panel_2',
component: 'default',
title: 'Panel 2',
position: {
direction: 'right',
},
});
event.api.addPanel({
id: 'panel_3',
component: 'default',
title: 'Panel 3',
position: {
direction: 'below',
},
});
this.api = event.api;
},
},
template: `
<div style="display:flex;flex-direction:column;height:100%;">
<div style="height:25px">
<button @click="onAddFloatingGroup">Add Floating Group</button>
<button @click="onToggleBounds">{{'Bounds: ' + bounds}}</button>
<button @click="onToggleEnabled">{{'Disabled: ' + disableFloatingGroups}}</button>
</div>
<div style="flex-grow:1;">
<dockview-vue
style="width:100%;height:100%"
class="dockview-theme-abyss"
@ready="onReady"
:components="components"
:floatingGroupBounds="bounds"
:leftHeaderActionsComponent="leftAction"
:rightHeaderActionsComponent="rightAction"
:prefixHeaderActionsComponent="prefixAction"
:disableFloatingGroups="disableFloatingGroups"
</dockview-vue>
</div>
</div>`,
});
const app = createApp(App);
app.config.errorHandler = (err) => {
console.log(err);
};
app.mount(document.getElementById('app')!);

View File

@ -9,9 +9,5 @@ const rootElement = document.getElementById('app');
if (rootElement) { if (rootElement) {
const root = ReactDOMClient.createRoot(rootElement); const root = ReactDOMClient.createRoot(rootElement);
root.render( root.render(<App />);
<div className="app">
<App />
</div>
);
} }

View File

@ -0,0 +1,23 @@
.dockview-groupcontrol-demo {
height: 100%;
display: flex;
align-items: center;
color: white;
background-color: black;
padding: 0px 8px;
margin: 1px;
border: 1px dotted orange;
}
.dockview-groupcontrol-demo .dockview-groupcontrol-demo-group-active {
padding: 0px 8px;
}
.dockview-groupcontrol-demo .dockview-groupcontrol-demo-active-panel {
color: yellow;
padding: 0px 8px;
}

View File

@ -0,0 +1,216 @@
import 'dockview-core/dist/styles/dockview.css';
import { PropType, createApp, defineComponent } from 'vue';
import { DockviewVue } from 'dockview-vue';
import {
DockviewGroupPanelApi,
DockviewReadyEvent,
IDockviewHeaderActionsProps,
IDockviewPanelProps,
} from 'dockview-core';
import './app.css';
const LeftAction = defineComponent({
name: 'LeftAction',
props: {
containerApi: {
type: Object as PropType<
IDockviewHeaderActionsProps['containerApi']
>,
required: true,
},
api: {
type: Object as PropType<IDockviewHeaderActionsProps['api']>,
required: true,
},
group: {
type: Object as PropType<IDockviewHeaderActionsProps['group']>,
required: true,
},
},
data() {
return {
activePanel: null,
};
},
mounted() {
const disposable = this.api.onDidActivePanelChange((event) => {
this.activePanel = event.panel.id;
});
this.activePanel = this.group.activePanel.id;
return () => {
disposable.dispose();
};
},
template: `
<div class="dockview-groupcontrol-demo">
<span class="dockview-groupcontrol-demo-active-panel">
"Active Panel " {{ activePanel }}
</span>
</div>`,
});
const RightAction = defineComponent({
name: 'RightAction',
props: {
containerApi: {
type: Object as PropType<
IDockviewHeaderActionsProps['containerApi']
>,
required: true,
},
api: {
type: Object as PropType<IDockviewHeaderActionsProps['api']>,
required: true,
},
group: {
type: Object as PropType<IDockviewHeaderActionsProps['group']>,
required: true,
},
},
data() {
return {
isGroupActive: false,
};
},
mounted() {
const disposable = this.api.onDidActiveChange((event) => {
this.isGroupActive = event.isActive;
});
this.isActive = this.api.isActive;
return () => {
disposable.dispose();
};
},
template: `
<div class="dockview-groupcontrol-demo">
<span v-if="isGroupActive" style="color:green;" class="dockview-groupcontrol-demo-active-panel">
Group Active
</span>
<span v-if="!isGroupActive" style="color:red;" class="dockview-groupcontrol-demo-active-panel">
Group Inactive
</span>
</div>`,
});
const PrefixAction = defineComponent({
name: 'PrefixAction',
props: {
containerApi: {
type: Object as PropType<
IDockviewHeaderActionsProps['containerApi']
>,
required: true,
},
group: {
type: Object as PropType<IDockviewHeaderActionsProps['group']>,
required: true,
},
},
template: `<div class="dockview-groupcontrol-demo">🌲</div>`,
});
const Panel = defineComponent({
name: 'Panel',
props: {
api: {
type: Object as PropType<IDockviewPanelProps['api']>,
required: true,
},
containerApi: {
type: Object as PropType<IDockviewPanelProps['containerApi']>,
required: true,
},
params: {
type: Object as PropType<IDockviewPanelProps['params']>,
required: true,
},
},
data() {
return {
title: '',
};
},
mounted() {
const disposable = this.api.onDidTitleChange(() => {
this.title = this.api.title;
});
this.title = this.api.title;
return () => {
disposable.dispose();
};
},
template: `
<div style="color:white;">
<div>{{title}}</div>
</div>`,
});
const App = defineComponent({
name: 'App',
components: {
'dockview-vue': DockviewVue,
Panel,
LeftAction,
RightAction,
PrefixAction,
},
data() {
return {
components: {
default: Panel,
},
leftAction: LeftAction,
rightAction: RightAction,
prefixAction: PrefixAction,
};
},
methods: {
onReady(event: DockviewReadyEvent) {
event.api.addPanel({
id: 'panel_1',
component: 'default',
title: 'Panel 1',
});
event.api.addPanel({
id: 'panel_2',
component: 'default',
title: 'Panel 2',
position: {
direction: 'right',
},
});
event.api.addPanel({
id: 'panel_3',
component: 'default',
title: 'Panel 3',
position: {
direction: 'below',
},
});
},
},
template: `
<dockview-vue
style="width:100%;height:100%"
class="dockview-theme-abyss"
@ready="onReady"
:components="components"
:leftHeaderActionsComponent="leftAction"
:rightHeaderActionsComponent="rightAction"
:prefixHeaderActionsComponent="prefixAction"
</dockview-vue>`,
});
const app = createApp(App);
app.config.errorHandler = (err) => {
console.log(err);
};
app.mount(document.getElementById('app')!);

View File

@ -22,14 +22,6 @@ const components = {
}, },
}; };
const counter = (() => {
let i = 0;
return {
next: () => ++i,
};
})();
function loadDefaultLayout(api: DockviewApi) { function loadDefaultLayout(api: DockviewApi) {
api.addPanel({ api.addPanel({
id: 'panel_1', id: 'panel_1',

View File

@ -9,9 +9,5 @@ const rootElement = document.getElementById('app');
if (rootElement) { if (rootElement) {
const root = ReactDOMClient.createRoot(rootElement); const root = ReactDOMClient.createRoot(rootElement);
root.render( root.render(<App />);
<div className="app">
<App />
</div>
);
} }

View File

@ -0,0 +1,237 @@
import 'dockview-core/dist/styles/dockview.css';
import { PropType, createApp, defineComponent } from 'vue';
import { DockviewVue } from 'dockview-vue';
import {
DockviewApi,
DockviewReadyEvent,
IDockviewHeaderActionsProps,
IDockviewPanelProps,
} from 'dockview-core';
let panelCount = 0;
function loadDefaultLayout(api: DockviewApi) {
api.addPanel({
id: 'panel_1',
component: 'default',
});
api.addPanel({
id: 'panel_2',
component: 'default',
});
api.addPanel({
id: 'panel_3',
component: 'default',
});
}
const MaterialIcon = defineComponent({
name: 'MaterialIcon',
props: {
icon: {
type: String,
required: true,
},
title: {
type: String,
required: false,
},
},
emits: ['click'],
data() {
return {
title: this.title,
icon: this.icon,
};
},
methods: {
onClick() {
this.$emit('click');
},
},
template: `
<div
@click="onClick"
title="title"
style="display:flex;justify-content:center;align-items:center;width:30px;height:100%;font-size:18px;">
<span class="material-symbols-outlined" style="font-size:inherit;cursor:pointer;">
{{icon}}
</span>
</div>`,
});
const LeftAction = defineComponent({
name: 'LeftAction',
props: {
containerApi: {
type: Object as PropType<
IDockviewHeaderActionsProps['containerApi']
>,
required: true,
},
api: {
type: Object as PropType<IDockviewHeaderActionsProps['api']>,
required: true,
},
group: {
type: Object as PropType<IDockviewHeaderActionsProps['group']>,
required: true,
},
},
components: {
'material-icon': MaterialIcon,
},
methods: {
onClick() {
this.containerApi.addPanel({
id: (++panelCount).toString(),
title: `Tab ${panelCount}`,
component: 'default',
});
},
},
template: `
<div style="height:100%;color:white;padding:0px 4px;">
<material-icon @click="onClick" icon="add"></material-icon>
</div>`,
});
const Panel = defineComponent({
name: 'Panel',
props: {
api: {
type: Object as PropType<IDockviewPanelProps['api']>,
required: true,
},
containerApi: {
type: Object as PropType<IDockviewPanelProps['containerApi']>,
required: true,
},
params: {
type: Object as PropType<IDockviewPanelProps['params']>,
required: true,
},
},
data() {
return {
title: '',
};
},
mounted() {
const disposable = this.api.onDidTitleChange(() => {
this.title = this.api.title;
});
this.title = this.api.title;
return () => {
disposable.dispose();
};
},
template: `
<div style="color:white;">
<div>{{title}}</div>
</div>`,
});
const App = defineComponent({
name: 'App',
components: {
'dockview-vue': DockviewVue,
Panel,
LeftAction,
},
data() {
return {
components: {
default: Panel,
},
leftAction: LeftAction,
api: null as DockviewApi | null,
};
},
methods: {
onLoad() {
const layoutString = localStorage.getItem(
'dv-template/dockview/layout/vue'
);
let success = false;
if (layoutString) {
try {
const layout = JSON.parse(layoutString);
this.api.fromJSON(layout);
success = true;
} catch (err) {
console.error(err);
}
}
if (!success) {
loadDefaultLayout(this.api);
}
},
onSave() {
localStorage.setItem(
'dv-template/dockview/layout/vue',
JSON.stringify(this.api.toJSON())
);
},
onClear() {
localStorage.removeItem('dv-template/dockview/layout/vue');
},
onReady(event: DockviewReadyEvent) {
this.api = event.api;
this.onLoad();
},
},
watch: {
api(newValue, oldValue) {
if (!newValue) {
return;
}
const disposable = newValue.onDidLayoutChange(() => {
const layout = newValue.toJSON();
localStorage.setItem(
'dockview_persistence_layout',
JSON.stringify(layout)
);
});
return () => {
disposable.dispose();
};
},
},
template: `
<div style="display:flex;flex-direction:column;height:100%;">
<div style="height:25px">
<button @click="onLoad">Load</button>
<button @click="onSave">Save</button>
<button @click="onClear">Clear</button>
</div>
<div style="flex-grow:1;">
<dockview-vue
style="width:100%;height:100%"
class="dockview-theme-abyss"
@ready="onReady"
:components="components"
:floatingGroupBounds="bounds"
:leftHeaderActionsComponent="leftAction"
:rightHeaderActionsComponent="rightAction"
:prefixHeaderActionsComponent="prefixAction"
:disableFloatingGroups="disableFloatingGroups"
</dockview-vue>
</div>
</div>`,
});
const app = createApp(App);
app.config.errorHandler = (err) => {
console.log(err);
};
app.mount(document.getElementById('app')!);

View File

@ -9,9 +9,5 @@ const rootElement = document.getElementById('app');
if (rootElement) { if (rootElement) {
const root = ReactDOMClient.createRoot(rootElement); const root = ReactDOMClient.createRoot(rootElement);
root.render( root.render(<App />);
<div className="app">
<App />
</div>
);
} }

View File

@ -0,0 +1,107 @@
import 'dockview-core/dist/styles/dockview.css';
import { PropType, createApp, defineComponent } from 'vue';
import { DockviewVue } from 'dockview-vue';
import {
DockviewApi,
DockviewReadyEvent,
IDockviewPanelProps,
} from 'dockview-core';
const Panel = defineComponent({
name: 'Panel',
props: {
api: {
type: Object as PropType<IDockviewPanelProps['api']>,
required: true,
},
containerApi: {
type: Object as PropType<IDockviewPanelProps['containerApi']>,
required: true,
},
params: {
type: Object as PropType<IDockviewPanelProps['params']>,
required: true,
},
},
data() {
return {
title: '',
};
},
mounted() {
const disposable = this.api.onDidTitleChange(() => {
this.title = this.api.title;
});
this.title = this.api.title;
return () => {
disposable.dispose();
};
},
template: `
<div style="height:100%;padding:20px;">
<span style="color:white;">{{ title }}</span>
</div>`,
});
const App = defineComponent({
name: 'App',
components: {
'dockview-vue': DockviewVue,
},
data() {
return {
components: {
default: Panel,
},
};
},
methods: {
onReady(event: DockviewReadyEvent) {
event.api.addPanel({
id: 'panel_1',
component: 'default',
});
event.api.addPanel({
id: 'panel_2',
component: 'default',
position: {
direction: 'right',
referencePanel: 'panel_1',
},
});
event.api.addPanel({
id: 'panel_3',
component: 'default',
position: {
direction: 'below',
referencePanel: 'panel_1',
},
});
event.api.addPanel({
id: 'panel_4',
component: 'default',
});
event.api.addPanel({
id: 'panel_5',
component: 'default',
});
},
},
template: `
<dockview-vue
style="width:100%;height:100%"
class="dockview-theme-abyss"
@ready="onReady"
:components="components"
:locked=true
</dockview-vue>`,
});
const app = createApp(App);
app.config.errorHandler = (err) => {
console.log(err);
};
app.mount(document.getElementById('app')!);

View File

@ -7,7 +7,35 @@ import {
SerializedDockview, SerializedDockview,
} from 'dockview'; } from 'dockview';
import React from 'react'; import React from 'react';
import { Icon } from './utils.tsx';
const Icon = (props: {
icon: string;
title?: string;
onClick?: (event: React.MouseEvent) => void;
}) => {
return (
<div
title={props.title}
style={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
width: '30px',
height: '100%',
fontSize: '18px',
}}
onClick={props.onClick}
>
<span
style={{ fontSize: 'inherit', cursor: 'pointer' }}
className="material-symbols-outlined"
>
{props.icon}
</span>
</div>
);
};
const components = { const components = {
default: (props: IDockviewPanelProps<{ title: string }>) => { default: (props: IDockviewPanelProps<{ title: string }>) => {
@ -25,14 +53,6 @@ const components = {
}, },
}; };
const counter = (() => {
let i = 0;
return {
next: () => ++i,
};
})();
function loadDefaultLayout(api: DockviewApi) { function loadDefaultLayout(api: DockviewApi) {
api.addPanel({ api.addPanel({
id: 'panel_1', id: 'panel_1',

View File

@ -9,9 +9,5 @@ const rootElement = document.getElementById('app');
if (rootElement) { if (rootElement) {
const root = ReactDOMClient.createRoot(rootElement); const root = ReactDOMClient.createRoot(rootElement);
root.render( root.render(<App />);
<div className="app">
<App />
</div>
);
} }

View File

@ -1,30 +0,0 @@
import React from 'react';
export const Icon = (props: {
icon: string;
title?: string;
onClick?: (event: React.MouseEvent) => void;
}) => {
return (
<div
title={props.title}
style={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
width: '30px',
height: '100%',
fontSize: '18px',
}}
onClick={props.onClick}
>
<span
style={{ fontSize: 'inherit', cursor: 'pointer' }}
className="material-symbols-outlined"
>
{props.icon}
</span>
</div>
);
};

View File

@ -0,0 +1,243 @@
import 'dockview-core/dist/styles/dockview.css';
import { Prop, PropType, createApp, defineComponent } from 'vue';
import { DockviewVue } from 'dockview-vue';
import {
DockviewReadyEvent,
IDockviewHeaderActionsProps,
IDockviewPanelProps,
} from 'dockview-core';
let panelCount = 0;
const MaterialIcon = defineComponent({
name: 'MaterialIcon',
props: {
icon: {
type: String,
required: true,
},
title: {
type: String,
required: false,
},
},
emits: ['click'],
data() {
return {
title: this.title,
icon: this.icon,
};
},
methods: {
onClick() {
this.$emit('click');
},
},
template: `
<div
@click="onClick"
title="title"
style="display:flex;justify-content:center;align-items:center;width:30px;height:100%;font-size:18px;">
<span class="material-symbols-outlined" style="font-size:inherit;cursor:pointer;">
{{icon}}
</span>
</div>`,
});
const LeftAction = defineComponent({
name: 'LeftAction',
props: {
containerApi: {
type: Object as PropType<
IDockviewHeaderActionsProps['containerApi']
>,
required: true,
},
group: {
type: Object as PropType<IDockviewHeaderActionsProps['group']>,
required: true,
},
},
components: {
'material-icon': MaterialIcon,
},
methods: {
onClick() {
this.containerApi.addPanel({
id: (++panelCount).toString(),
title: `Tab ${panelCount}`,
component: 'default',
position: { referenceGroup: this.group },
});
},
},
template: `
<div style="height:100%;color:white;padding:0px 4px;">
<material-icon @click="onClick" icon="add"></material-icon>
</div>`,
});
const RightAction = defineComponent({
name: 'RightAction',
props: {
containerApi: {
type: Object as PropType<
IDockviewHeaderActionsProps['containerApi']
>,
required: true,
},
api: {
type: Object as PropType<IDockviewHeaderActionsProps['api']>,
required: true,
},
group: {
type: Object as PropType<IDockviewHeaderActionsProps['group']>,
required: true,
},
},
data() {
return {
maximized: false,
};
},
mounted() {
const disposable = this.containerApi.onDidMaximizedGroupChange(() => {
this.maximized = this.api.isMaximized();
});
this.maximized = this.api.isMaximized();
return () => {
disposable.dispose();
};
},
components: {
'material-icon': MaterialIcon,
},
methods: {
onClick() {
if (this.maximized) {
this.api.exitMaximized();
} else {
this.api.maximize();
}
},
},
template: `
<div style="height:100%;color:white;padding:0px 4px;">
<material-icon v-if="maximized" @click="onClick" icon="jump_to_element" ></material-icon>
<material-icon v-if="!maximized" @click="onClick" icon="back_to_tab"></material-icon>
</div>`,
});
const Panel = defineComponent({
name: 'Panel',
props: {
api: {
type: Object as PropType<IDockviewPanelProps['api']>,
required: true,
},
containerApi: {
type: Object as PropType<IDockviewPanelProps['containerApi']>,
required: true,
},
params: {
type: Object as PropType<IDockviewPanelProps['params']>,
required: true,
},
},
data() {
return {
title: '',
};
},
mounted() {
const disposable = this.api.onDidTitleChange(() => {
this.title = this.api.title;
});
this.title = this.api.title;
return () => {
disposable.dispose();
};
},
template: `
<div style="color:white;">
<div>{{title}}</div>
</div>`,
});
const App = defineComponent({
name: 'App',
components: {
'dockview-vue': DockviewVue,
Panel,
LeftAction,
RightAction,
},
data() {
return {
components: {
default: Panel,
},
leftAction: LeftAction,
rightAction: RightAction,
};
},
methods: {
onReady(event: DockviewReadyEvent) {
event.api.addPanel({
id: 'panel_1',
component: 'default',
});
event.api.addPanel({
id: 'panel_2',
component: 'default',
position: {
direction: 'right',
referencePanel: 'panel_1',
},
});
event.api.addPanel({
id: 'panel_3',
component: 'default',
position: {
direction: 'below',
referencePanel: 'panel_1',
},
});
event.api.addPanel({
id: 'panel_4',
component: 'default',
});
event.api.addPanel({
id: 'panel_5',
component: 'default',
});
},
},
computed: {
styleObject() {
return {
height: `${this.value}%`,
width: `${this.value}%`,
};
},
},
template: `
<dockview-vue
style="width:100%;height:100%"
class="dockview-theme-abyss"
@ready="onReady"
:components="components"
:leftHeaderActionsComponent="leftAction"
:rightHeaderActionsComponent="rightAction"
</dockview-vue>`,
});
const app = createApp(App);
app.config.errorHandler = (err) => {
console.log(err);
};
app.mount(document.getElementById('app')!);

View File

@ -0,0 +1,32 @@
{
"name": "dockview.resize-container",
"description": "",
"keywords": [
"dockview"
],
"version": "1.0.0",
"main": "src/index.tsx",
"dependencies": {
"dockview": "*",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/react": "^18.0.28",
"@types/react-dom": "^18.0.11",
"typescript": "^4.9.5",
"react-scripts": "*"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
},
"browserslist": [
">0.2%",
"not dead",
"not ie <= 11",
"not op_mini all"
]
}

View File

@ -0,0 +1,94 @@
import {
DockviewDidDropEvent,
DockviewDndOverlayEvent,
DockviewReact,
DockviewReadyEvent,
IDockviewPanelProps,
} from 'dockview';
import React from 'react';
const InnerDockview = () => {
const onReady = (event: DockviewReadyEvent) => {
event.api.addPanel({
id: 'panel_1',
component: 'default',
});
event.api.addPanel({
id: 'panel_2',
component: 'default',
});
event.api.addPanel({
id: 'panel_3',
component: 'default',
});
};
return (
<DockviewReact
onReady={onReady}
components={components}
className="nested-dockview"
/>
);
};
const components = {
default: (props: IDockviewPanelProps<{ title: string }>) => {
return (
<div
style={{
height: '100%',
padding: '20px',
background: 'var(--dv-group-view-background-color)',
}}
>
{props.params.title}
</div>
);
},
innerDockview: InnerDockview,
};
const NestedDockview = (props: { theme?: string }) => {
const onReady = (event: DockviewReadyEvent) => {
event.api.addPanel({
id: 'panel_1',
component: 'default',
});
event.api.addPanel({
id: 'panel_2',
component: 'default',
});
event.api.addPanel({
id: 'panel_3',
component: 'innerDockview',
position: { referencePanel: 'panel_2', direction: 'right' },
});
};
const showDndOverlay = (event: DockviewDndOverlayEvent) => {
// console.log(event.getData());
return false;
};
const onDidDrop = (event: DockviewDidDropEvent) => {
// event.getData();
};
return (
<DockviewReact
onReady={onReady}
components={components}
className={`${props.theme || 'dockview-theme-abyss'}`}
showDndOverlay={showDndOverlay}
onDidDrop={onDidDrop}
/>
);
};
export default NestedDockview;

View File

@ -0,0 +1,13 @@
import React from 'react';
import ReactDOMClient from 'react-dom/client';
import 'dockview/dist/styles/dockview.css';
import App from './app.tsx';
const rootElement = document.getElementById('app');
if (rootElement) {
const root = ReactDOMClient.createRoot(rootElement);
root.render(<App />);
}

View File

@ -0,0 +1,18 @@
{
"compilerOptions": {
"outDir": "build/dist",
"module": "esnext",
"target": "es5",
"lib": ["es6", "dom"],
"sourceMap": true,
"allowJs": true,
"jsx": "react-jsx",
"moduleResolution": "node",
"rootDir": "src",
"forceConsistentCasingInFileNames": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noImplicitAny": true,
"strictNullChecks": true
}
}

View File

@ -0,0 +1,131 @@
import 'dockview-core/dist/styles/dockview.css';
import { PropType, createApp, defineComponent } from 'vue';
import { DockviewVue } from 'dockview-vue';
import { DockviewReadyEvent, IDockviewPanelProps } from 'dockview-core';
const Panel = defineComponent({
name: 'Panel',
props: {
api: {
type: Object as PropType<IDockviewPanelProps['api']>,
required: true,
},
containerApi: {
type: Object as PropType<IDockviewPanelProps['containerApi']>,
required: true,
},
params: {
type: Object as PropType<IDockviewPanelProps['params']>,
required: true,
},
},
data() {
return {
title: '',
};
},
mounted() {
const disposable = this.api.onDidTitleChange(() => {
this.title = this.api.title;
});
this.title = this.api.title;
return () => {
disposable.dispose();
};
},
template: `
<div style="height:100%;padding:20px;color:white;">
<div>{{title}}</div>
</div>`,
});
const InnerDockview = defineComponent({
name: 'App',
components: {
'dockview-vue': DockviewVue,
Panel,
},
data() {
return {
components: {
default: Panel,
innerDockview: InnerDockview,
},
};
},
methods: {
onReady(event: DockviewReadyEvent) {
event.api.addPanel({
id: 'panel_1',
component: 'default',
});
event.api.addPanel({
id: 'panel_2',
component: 'default',
});
event.api.addPanel({
id: 'panel_3',
component: 'default',
});
},
},
template: `
<dockview-vue
style="width:100%;height:100%"
class="dockview-theme-abyss"
:components="components"
@ready="onReady"
</dockview-vue>`,
});
const App = defineComponent({
name: 'App',
components: {
'dockview-vue': DockviewVue,
Panel,
InnerDockview,
},
data() {
return {
components: {
default: Panel,
innerDockview: InnerDockview,
},
};
},
methods: {
onReady(event: DockviewReadyEvent) {
event.api.addPanel({
id: 'panel_1',
component: 'default',
});
event.api.addPanel({
id: 'panel_2',
component: 'default',
});
event.api.addPanel({
id: 'panel_3',
component: 'innerDockview',
position: { referencePanel: 'panel_2', direction: 'right' },
});
},
},
template: `
<dockview-vue
style="width:100%;height:100%"
class="dockview-theme-abyss"
:components="components"
@ready="onReady"
</dockview-vue>`,
});
const app = createApp(App);
app.config.errorHandler = (err) => {
console.log(err);
};
app.mount(document.getElementById('app')!);

View File

@ -9,9 +9,5 @@ const rootElement = document.getElementById('app');
if (rootElement) { if (rootElement) {
const root = ReactDOMClient.createRoot(rootElement); const root = ReactDOMClient.createRoot(rootElement);
root.render( root.render(<App />);
<div className="app">
<App />
</div>
);
} }

View File

@ -0,0 +1,266 @@
import 'dockview-core/dist/styles/dockview.css';
import { PropType, createApp, defineComponent } from 'vue';
import { DockviewVue } from 'dockview-vue';
import {
DockviewApi,
DockviewReadyEvent,
IDockviewHeaderActionsProps,
IDockviewPanelProps,
} from 'dockview-core';
let panelCount = 0;
const MaterialIcon = defineComponent({
name: 'MaterialIcon',
props: {
icon: {
type: String,
required: true,
},
title: {
type: String,
required: false,
},
},
emits: ['click'],
data() {
return {
title: this.title,
icon: this.icon,
};
},
methods: {
onClick() {
this.$emit('click');
},
},
template: `
<div
@click="onClick"
title="title"
style="display:flex;justify-content:center;align-items:center;width:30px;height:100%;font-size:18px;">
<span class="material-symbols-outlined" style="font-size:inherit;cursor:pointer;">
{{icon}}
</span>
</div>`,
});
const LeftAction = defineComponent({
name: 'LeftAction',
props: {
containerApi: {
type: Object as PropType<
IDockviewHeaderActionsProps['containerApi']
>,
required: true,
},
api: {
type: Object as PropType<IDockviewHeaderActionsProps['api']>,
required: true,
},
group: {
type: Object as PropType<IDockviewHeaderActionsProps['group']>,
required: true,
},
},
components: {
'material-icon': MaterialIcon,
},
methods: {
onClick() {
this.containerApi.addPanel({
id: (++panelCount).toString(),
title: `Tab ${panelCount}`,
component: 'default',
});
},
},
template: `
<div style="height:100%;color:white;padding:0px 4px;">
<material-icon @click="onClick" icon="add"></material-icon>
</div>`,
});
const RightAction = defineComponent({
name: 'RightAction',
props: {
containerApi: {
type: Object as PropType<
IDockviewHeaderActionsProps['containerApi']
>,
required: true,
},
api: {
type: Object as PropType<IDockviewHeaderActionsProps['api']>,
required: true,
},
group: {
type: Object as PropType<IDockviewHeaderActionsProps['group']>,
required: true,
},
},
components: {
'material-icon': MaterialIcon,
},
data() {
return {
isPopout: this.api.location.type === 'popout',
};
},
methods: {
onClick() {
if (this.isPopout) {
const group = this.containerApi.addGroup();
this.group.api.moveTo({ group });
} else {
this.containerApi.addPopoutGroup(this.group, {
popoutUrl: '/popout/index.html',
});
}
},
},
mounted() {
const disposable = this.group.api.onDidLocationChange((event) => {
this.isPopout = event.location.type === 'popout';
});
return () => {
disposable.dispose();
};
},
template: `
<div style="height:100%;color:white;padding:0px 4px">
<material-icon v-if="isPopout" @click="onClick" icon="jump_to_element"></material-icon>
<material-icon v-if="!isPopout" @click="onClick" icon="back_to_tab"></material-icon>
</div>`,
});
const Panel = defineComponent({
name: 'Panel',
props: {
api: {
type: Object as PropType<IDockviewPanelProps['api']>,
required: true,
},
containerApi: {
type: Object as PropType<IDockviewPanelProps['containerApi']>,
required: true,
},
params: {
type: Object as PropType<IDockviewPanelProps['params']>,
required: true,
},
},
data() {
return {
title: '',
};
},
mounted() {
const disposable = this.api.onDidTitleChange(() => {
this.title = this.api.title;
});
this.title = this.api.title;
return () => {
disposable.dispose();
};
},
template: `
<div style="color:white;">
<div>{{title}}</div>
</div>`,
});
const App = defineComponent({
name: 'App',
components: {
'dockview-vue': DockviewVue,
Panel,
LeftAction,
RightAction,
},
data() {
return {
components: {
default: Panel,
},
leftAction: LeftAction,
rightAction: RightAction,
api: null as DockviewApi | null,
bounds: undefined,
disableFloatingGroups: false,
};
},
methods: {
onAddFloatingGroup() {
this.api.addPanel({
id: (++panelCount).toString(),
title: `Tab ${panelCount}`,
component: 'default',
floating: { width: 250, height: 150, x: 50, y: 50 },
});
},
onToggleBounds() {
this.bounds =
this.bounds === undefined ? 'boundedWithinViewport' : undefined;
},
onToggleEnabled() {
this.disableFloatingGroups = !this.disableFloatingGroups;
},
onReady(event: DockviewReadyEvent) {
event.api.addPanel({
id: 'panel_1',
component: 'default',
title: 'Panel 1',
});
event.api.addPanel({
id: 'panel_2',
component: 'default',
title: 'Panel 2',
position: {
direction: 'right',
},
});
event.api.addPanel({
id: 'panel_3',
component: 'default',
title: 'Panel 3',
position: {
direction: 'below',
},
});
this.api = event.api;
},
},
template: `
<div style="display:flex;flex-direction:column;height:100%;">
<div style="height:25px">
<button @click="onAddFloatingGroup">Add Floating Group</button>
<button @click="onToggleBounds">{{'Bounds: ' + bounds}}</button>
<button @click="onToggleEnabled">{{'Disabled: ' + disableFloatingGroups}}</button>
</div>
<div style="flex-grow:1;">
<dockview-vue
style="width:100%;height:100%"
class="dockview-theme-abyss"
@ready="onReady"
:components="components"
:floatingGroupBounds="bounds"
:leftHeaderActionsComponent="leftAction"
:rightHeaderActionsComponent="rightAction"
:prefixHeaderActionsComponent="prefixAction"
:disableFloatingGroups="disableFloatingGroups"
</dockview-vue>
</div>
</div>`,
});
const app = createApp(App);
app.config.errorHandler = (err) => {
console.log(err);
};
app.mount(document.getElementById('app')!);

View File

@ -48,15 +48,14 @@ const components = {
}} }}
> >
<div>{props.api.title}</div> <div>{props.api.title}</div>
<input />
<div> <div>
{mode} {mode}
<button <button
onClick={() => { onClick={() => {
setMode( setMode(
mode === 'onlyWhenVisibile' mode === 'onlyWhenVisible'
? 'always' ? 'always'
: 'onlyWhenVisibile' : 'onlyWhenVisible'
); );
}} }}
> >

View File

@ -9,9 +9,5 @@ const rootElement = document.getElementById('app');
if (rootElement) { if (rootElement) {
const root = ReactDOMClient.createRoot(rootElement); const root = ReactDOMClient.createRoot(rootElement);
root.render( root.render(<App />);
<div className="app">
<App />
</div>
);
} }

View File

@ -0,0 +1,115 @@
import 'dockview-core/dist/styles/dockview.css';
import { PropType, createApp, defineComponent } from 'vue';
import { DockviewVue } from 'dockview-vue';
import { DockviewReadyEvent, IDockviewPanelProps } from 'dockview-core';
const Panel = defineComponent({
name: 'Panel',
props: {
api: {
type: Object as PropType<IDockviewPanelProps['api']>,
required: true,
},
containerApi: {
type: Object as PropType<IDockviewPanelProps['containerApi']>,
required: true,
},
params: {
type: Object as PropType<IDockviewPanelProps['params']>,
required: true,
},
},
data() {
return {
title: '',
renderer: null,
};
},
methods: {
onToggleRenderMode() {
this.api.setRenderer(
this.api.renderer === 'onlyWhenVisible'
? 'always'
: 'onlyWhenVisible'
);
},
},
mounted() {
const disposable = this.api.onDidTitleChange(() => {
this.title = this.api.title;
});
const disposable2 = this.api.onDidRendererChange((event) => {
this.renderer = event.renderer;
});
this.title = this.api.title;
this.renderer = this.api.renderer;
return () => {
disposable.dispose();
disposable2.dispose();
};
},
template: `
<div style="height:100%;color:white;">
<div>{{title}}</div>
<button @click="onToggleRenderMode">{{renderer}}</button>
</div>`,
});
const App = defineComponent({
name: 'App',
components: {
'dockview-vue': DockviewVue,
Panel,
},
data() {
return {
components: {
default: Panel,
},
};
},
methods: {
onReady(event: DockviewReadyEvent) {
event.api.addPanel({
id: 'panel_1',
component: 'default',
title: 'Panel 1',
});
event.api.addPanel({
id: 'panel_2',
component: 'default',
title: 'Panel 2',
position: { referencePanel: 'panel_1', direction: 'within' },
});
event.api.addPanel({
id: 'panel_3',
component: 'default',
title: 'Panel 3',
});
event.api.addPanel({
id: 'panel_4',
component: 'default',
title: 'Panel 4',
position: { referencePanel: 'panel_3', direction: 'below' },
});
},
},
template: `
<dockview-vue
style="width:100%;height:100%"
class="dockview-theme-abyss"
@ready="onReady"
:components="components"
</dockview-vue>`,
});
const app = createApp(App);
app.config.errorHandler = (err) => {
console.log(err);
};
app.mount(document.getElementById('app')!);

View File

@ -53,7 +53,7 @@ export const App: React.FC = (props: { theme?: string }) => {
position: { referencePanel: 'panel_1', direction: 'right' }, position: { referencePanel: 'panel_1', direction: 'right' },
}); });
const panel5 = event.api.addPanel({ event.api.addPanel({
id: 'panel_5', id: 'panel_5',
component: 'default', component: 'default',
params: { params: {
@ -62,9 +62,6 @@ export const App: React.FC = (props: { theme?: string }) => {
position: { referencePanel: 'panel_3', direction: 'right' }, position: { referencePanel: 'panel_3', direction: 'right' },
}); });
// panel5.group!.model.header.hidden = true;
// panel5.group!.model.locked = true;
event.api.addPanel({ event.api.addPanel({
id: 'panel_6', id: 'panel_6',
component: 'default', component: 'default',

View File

@ -9,9 +9,5 @@ const rootElement = document.getElementById('app');
if (rootElement) { if (rootElement) {
const root = ReactDOMClient.createRoot(rootElement); const root = ReactDOMClient.createRoot(rootElement);
root.render( root.render(<App />);
<div className="app">
<App />
</div>
);
} }

View File

@ -0,0 +1,150 @@
import 'dockview-core/dist/styles/dockview.css';
import { PropType, createApp, defineComponent } from 'vue';
import { DockviewVue } from 'dockview-vue';
import { DockviewReadyEvent, IDockviewPanelProps } from 'dockview-core';
const Panel = defineComponent({
name: 'Panel',
props: {
api: {
type: Object as PropType<IDockviewPanelProps['api']>,
required: true,
},
containerApi: {
type: Object as PropType<IDockviewPanelProps['containerApi']>,
required: true,
},
params: {
type: Object as PropType<IDockviewPanelProps['params']>,
required: true,
},
},
data() {
return {
title: '',
};
},
mounted() {
const disposable = this.api.onDidTitleChange(() => {
this.title = this.api.title;
});
this.title = this.api.title;
return () => {
disposable.dispose();
};
},
template: `
<div style="height:100%;padding:20px;color:white;">
<div>{{title}}</div>
</div>`,
});
const App = defineComponent({
name: 'App',
components: {
'dockview-vue': DockviewVue,
Panel,
},
data() {
return {
components: {
default: Panel,
},
value: 50,
};
},
methods: {
onReady(event: DockviewReadyEvent) {
const panel = event.api.addPanel({
id: 'panel_1',
component: 'default',
params: {
title: 'Panel 1',
},
});
panel.group.locked = true;
panel.group.header.hidden = true;
event.api.addPanel({
id: 'panel_2',
component: 'default',
params: {
title: 'Panel 2',
},
});
event.api.addPanel({
id: 'panel_3',
component: 'default',
params: {
title: 'Panel 3',
},
});
event.api.addPanel({
id: 'panel_4',
component: 'default',
params: {
title: 'Panel 4',
},
position: { referencePanel: 'panel_1', direction: 'right' },
});
event.api.addPanel({
id: 'panel_5',
component: 'default',
params: {
title: 'Panel 5',
},
position: { referencePanel: 'panel_3', direction: 'right' },
});
event.api.addPanel({
id: 'panel_6',
component: 'default',
params: {
title: 'Panel 6',
},
position: { referencePanel: 'panel_5', direction: 'below' },
});
event.api.addPanel({
id: 'panel_7',
component: 'default',
params: {
title: 'Panel 7',
},
position: { referencePanel: 'panel_6', direction: 'right' },
});
},
},
computed: {
styleObject() {
return {
height: `${this.value}%`,
width: `${this.value}%`,
};
},
},
template: `
<div style="height:100%;display:flex;flex-direction:column;">
<input v-model="value" type="range" min="1" max="100"></input>
<div :style="styleObject">
<dockview-vue
style="width:100%;height:100%"
class="dockview-theme-abyss"
@ready="onReady"
:components="components"
:disableFloatingGroups=true
</dockview-vue>
</div>
</div>`,
});
const app = createApp(App);
app.config.errorHandler = (err) => {
console.log(err);
};
app.mount(document.getElementById('app')!);

View File

@ -9,9 +9,5 @@ const rootElement = document.getElementById('app');
if (rootElement) { if (rootElement) {
const root = ReactDOMClient.createRoot(rootElement); const root = ReactDOMClient.createRoot(rootElement);
root.render( root.render(<App />);
<div className="app">
<App />
</div>
);
} }

View File

@ -0,0 +1,138 @@
import 'dockview-core/dist/styles/dockview.css';
import { PropType, createApp, defineComponent } from 'vue';
import { DockviewVue } from 'dockview-vue';
import { DockviewReadyEvent, IDockviewPanelProps } from 'dockview-core';
import './resize.css';
const Panel = defineComponent({
name: 'Panel',
props: {
api: {
type: Object as PropType<IDockviewPanelProps['api']>,
required: true,
},
containerApi: {
type: Object as PropType<IDockviewPanelProps['containerApi']>,
required: true,
},
params: {
type: Object as PropType<IDockviewPanelProps['params']>,
required: true,
},
},
data() {
return {
title: '',
width: 100,
height: 100,
};
},
methods: {
onResizeGroupWidth() {
this.api.group.api.setSize({ width: this.width });
},
onResizePanelWidth() {
this.api.setSize({ width: this.width });
},
onResizeGroupHeight() {
this.api.group.api.setSize({ height: this.height });
},
onResizePanelHeight() {
this.api.setSize({ height: this.height });
},
},
mounted() {
const disposable = this.api.onDidTitleChange(() => {
this.title = this.api.title;
});
this.title = this.api.title;
return () => {
disposable.dispose();
};
},
template: `
<div class="resize-panel">
<div style="height:25px;">{{title}}</div>
<div class="resize-control">
<span>Width:</span>
<input v-model="width" type="number" min="50" step="1"></input>
<button @click="onResizeGroupWidth">Resize Group</button>
<button @click="onResizePanelWidth">Resize Panel</button>
</div>
<div class="resize-control">
<span>Height:</span>
<input v-model="height" type="number" min="50" step="1"></input>
<button @click="onResizeGroupHeight">Resize Group</button>
<button @click="onResizePanelHeight">Resize Panel</button>
</div>
</div>`,
});
const App = defineComponent({
name: 'App',
components: {
'dockview-vue': DockviewVue,
Panel,
},
data() {
return {
components: {
default: Panel,
},
};
},
methods: {
onReady(event: DockviewReadyEvent) {
event.api.addPanel({
id: 'panel_1',
component: 'default',
});
event.api.addPanel({
id: 'panel_2',
component: 'default',
position: {
direction: 'right',
referencePanel: 'panel_1',
},
});
event.api.addPanel({
id: 'panel_3',
component: 'default',
position: {
direction: 'below',
referencePanel: 'panel_1',
},
});
event.api.addPanel({
id: 'panel_4',
component: 'default',
});
event.api.addPanel({
id: 'panel_5',
component: 'default',
});
},
},
computed: {
styleObject() {
return {
height: `${this.value}%`,
width: `${this.value}%`,
};
},
},
template: `
<dockview-vue
style="width:100%;height:100%"
class="dockview-theme-abyss"
@ready="onReady"
:components="components"
</dockview-vue>`,
});
const app = createApp(App);
app.config.errorHandler = (err) => {
console.log(err);
};
app.mount(document.getElementById('app')!);

View File

@ -0,0 +1,23 @@
.resize-panel {
padding: 10px;
color: white;
}
.resize-panel .resize-control {
display: flex;
height: 18px;
line-height: 18px;
font-size: 13px;
span {
width: 60px;
}
input {
width: 75px;
}
button {
width: 50px;
}
}

View File

@ -1,15 +0,0 @@
.group-control .action {
padding: 4px;
display: flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
font-size: 18px;
cursor: pointer;
}
.group-control .action:hover {
border-radius: 2px;
background-color: var(--dv-icon-hover-background-color);
}

View File

@ -4,7 +4,6 @@ import {
DockviewReadyEvent, DockviewReadyEvent,
IDockviewPanelProps, IDockviewPanelProps,
} from 'dockview'; } from 'dockview';
import './app.css';
const TEXT = const TEXT =
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'; 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.';

View File

@ -9,9 +9,5 @@ const rootElement = document.getElementById('app');
if (rootElement) { if (rootElement) {
const root = ReactDOMClient.createRoot(rootElement); const root = ReactDOMClient.createRoot(rootElement);
root.render( root.render(<App />);
<div className="app">
<App />
</div>
);
} }

View File

@ -0,0 +1,101 @@
import 'dockview-core/dist/styles/dockview.css';
import { createApp, defineComponent } from 'vue';
import { DockviewVue } from 'dockview-vue';
import { DockviewReadyEvent } from 'dockview-core';
const TEXT =
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.';
const FixedHeightContainer = defineComponent({
name: 'FixedHeightContainer',
data() {
return {
text: [TEXT, '\n\n'].join('').repeat(20),
};
},
template: `
<div style="height:100%;color:white;">
{{text}}
</div>`,
});
const OverflowContainer = defineComponent({
name: 'OverflowContainer',
data() {
return {
text: [TEXT, '\n\n'].join('').repeat(20),
};
},
template: `
<div style="height:200px;overflow:auto;color:white;">
{{text}}
</div>`,
});
const UserDefinedOverflowContainer = defineComponent({
name: 'UserDefinedOverflowContainer',
data() {
return {
text: [TEXT, '\n\n'].join('').repeat(20),
};
},
template: `
<div style="height:100%;color:white;">
<div style="height:100%;overflow:auto;">
{{text}}
</div>
</div>`,
});
const App = defineComponent({
name: 'App',
components: {
'dockview-vue': DockviewVue,
},
data() {
return {
components: {
fixedHeightContainer: FixedHeightContainer,
overflowContainer: OverflowContainer,
userDefinedOverflowContainer: UserDefinedOverflowContainer,
},
};
},
methods: {
onReady(event: DockviewReadyEvent) {
event.api.addPanel({
id: 'panel_1',
component: 'fixedHeightContainer',
title: 'Panel 1',
});
event.api.addPanel({
id: 'panel_2',
component: 'overflowContainer',
title: 'Panel 2',
position: { direction: 'right' },
});
event.api.addPanel({
id: 'panel_3',
component: 'userDefinedOverflowContainer',
title: 'Panel 3',
position: { direction: 'right' },
});
},
},
template: `
<dockview-vue
style="width:100%;height:100%"
class="dockview-theme-abyss"
@ready="onReady"
:components="components"
:disableFloatingGroups=true
</dockview-vue>`,
});
const app = createApp(App);
app.config.errorHandler = (err) => {
console.log(err);
};
app.mount(document.getElementById('app')!);

View File

@ -9,9 +9,5 @@ const rootElement = document.getElementById('app');
if (rootElement) { if (rootElement) {
const root = ReactDOMClient.createRoot(rootElement); const root = ReactDOMClient.createRoot(rootElement);
root.render( root.render(<App />);
<div className="app">
<App />
</div>
);
} }

View File

@ -84,12 +84,10 @@ const App = defineComponent({
id: 'panel_1', id: 'panel_1',
component: 'default', component: 'default',
}); });
event.api.addPanel({ event.api.addPanel({
id: 'panel_2', id: 'panel_2',
component: 'default', component: 'default',
}); });
event.api.addPanel({ event.api.addPanel({
id: 'panel_3', id: 'panel_3',
component: 'default', component: 'default',
@ -102,8 +100,6 @@ const App = defineComponent({
id: 'panel_5', id: 'panel_5',
component: 'default', component: 'default',
}); });
this.api = event.api;
}, },
}, },
template: ` template: `

View File

@ -29,7 +29,7 @@ const components = {
}, [running]); }, [running]);
return ( return (
<div style={{ height: '100%', padding: '20px', color: 'white' }}> <div style={{ padding: '20px', color: 'white' }}>
<div>{props.api.title}</div> <div>{props.api.title}</div>
<button onClick={() => setRunning(!running)}> <button onClick={() => setRunning(!running)}>
{running ? 'Stop' : 'Start'} {running ? 'Stop' : 'Start'}

View File

@ -9,9 +9,5 @@ const rootElement = document.getElementById('app');
if (rootElement) { if (rootElement) {
const root = ReactDOMClient.createRoot(rootElement); const root = ReactDOMClient.createRoot(rootElement);
root.render( root.render(<App />);
<div className="app">
<App />
</div>
);
} }

View File

@ -25,31 +25,13 @@ const Panel = defineComponent({
}, },
data() { data() {
return { return {
running: false, isRunning: false,
title: '', title: null,
}; };
}, },
methods: { methods: {
onClick() { toggle() {
this.running = !this.running; this.isRunning = !this.isRunning;
},
},
watch: {
running(newValue, oldValue) {
if (!newValue) {
return;
}
console.log('interval');
const interval = setInterval(() => {
this.api.updateParameters({ myValue: Date.now() });
}, 1000);
this.api.updateParameters({ myValue: Date.now() });
return () => {
clearInterval(interval);
};
}, },
}, },
mounted() { mounted() {
@ -62,57 +44,8 @@ const Panel = defineComponent({
disposable.dispose(); disposable.dispose();
}; };
}, },
template: `
<div style="height:100%;padding:20px;color:white;">
<div>{{title}}</div>
<button v-if="running" @click="onClick">Stop</button>
<button v-if="!running" @click="onClick">Start</button>
<span>{{title}}</span>
</div>`,
});
interface CustomParams {
myValue: number;
}
const Tab = defineComponent({
name: 'Tab',
props: {
api: {
type: Object as PropType<
IDockviewPanelHeaderProps<CustomParams>['api']
>,
required: true,
},
containerApi: {
type: Object as PropType<
IDockviewPanelHeaderProps<CustomParams>['containerApi']
>,
required: true,
},
params: {
type: Object as PropType<
IDockviewPanelHeaderProps<CustomParams>['params']
>,
required: true,
},
},
data() {
return {
myValue: this.params.myValue,
title: '',
};
},
methods: {
onClick() {
this.running = !this.running;
},
},
watch: { watch: {
params(newValue, oldValue) { isRunning(newValue, oldValue) {
this.myValue = newValue.myValue;
},
running(newValue, oldValue) {
if (!newValue) { if (!newValue) {
return; return;
} }
@ -127,11 +60,57 @@ const Tab = defineComponent({
}; };
}, },
}, },
template: `
<div style="height:100%;color:white;">
<div>{{title}}</div>
<button v-if="!isRunning" @click="toggle">Start</button>
<button v-if="isRunning" @click="toggle">Stop</button>
</div>`,
});
const Tab = defineComponent({
name: 'Tab',
props: {
api: {
type: Object as PropType<IDockviewPanelHeaderProps['api']>,
required: true,
},
containerApi: {
type: Object as PropType<IDockviewPanelHeaderProps['containerApi']>,
required: true,
},
params: {
type: Object as PropType<IDockviewPanelHeaderProps['params']>,
required: true,
},
},
data() {
return {
title: '',
value: null,
};
},
mounted() {
const disposable = this.api.onDidTitleChange(() => {
this.title = this.api.title;
});
const disposable2 = this.api.onDidParametersChange(() => {
this.value = this.params.myValue;
});
this.title = this.api.title;
this.value = this.params.myValue;
return () => {
disposable.dispose();
disposable2.dispose();
};
},
template: ` template: `
<div> <div>
<div>custom tab: {{title}}</div> <div>custom tab: {{title}}</div>
<span>value: {{myValue}}</span> <div>value: {{value}}</div>
</div>`, </div>`,
}); });
@ -140,9 +119,8 @@ const App = defineComponent({
components: { components: {
'dockview-vue': DockviewVue, 'dockview-vue': DockviewVue,
Panel, Panel,
Tab,
}, },
setup() { data() {
return { return {
components: { components: {
default: Panel, default: Panel,

View File

@ -9,9 +9,5 @@ const rootElement = document.getElementById('app');
if (rootElement) { if (rootElement) {
const root = ReactDOMClient.createRoot(rootElement); const root = ReactDOMClient.createRoot(rootElement);
root.render( root.render(<App />);
<div className="app">
<App />
</div>
);
} }

View File

@ -1,7 +1,10 @@
import 'dockview-core/dist/styles/dockview.css'; import 'dockview-core/dist/styles/dockview.css';
import { PropType, createApp, defineComponent } from 'vue'; import { PropType, createApp, defineComponent } from 'vue';
import { DockviewVue } from 'dockview-vue'; import { DockviewVue } from 'dockview-vue';
import { DockviewReadyEvent, IDockviewPanelProps } from 'dockview-core'; import {
DockviewReadyEvent,
IDockviewPanelProps,
} from 'dockview-core';
const Panel = defineComponent({ const Panel = defineComponent({
name: 'Panel', name: 'Panel',
@ -61,7 +64,7 @@ const App = defineComponent({
'dockview-vue': DockviewVue, 'dockview-vue': DockviewVue,
Panel, Panel,
}, },
setup() { data() {
return { return {
components: { components: {
default: Panel, default: Panel,

View File

@ -9,9 +9,5 @@ const rootElement = document.getElementById('app');
if (rootElement) { if (rootElement) {
const root = ReactDOMClient.createRoot(rootElement); const root = ReactDOMClient.createRoot(rootElement);
root.render( root.render(<App />);
<div className="app">
<App />
</div>
);
} }

View File

@ -83,9 +83,6 @@ const App = defineComponent({
Panel, Panel,
}, },
data() { data() {
return { api: null as DockviewApi | null };
},
setup() {
return { return {
components: { components: {
default: Panel, default: Panel,
@ -102,8 +99,6 @@ const App = defineComponent({
this.api.addGroup(); this.api.addGroup();
}, },
onReady(event: DockviewReadyEvent) { onReady(event: DockviewReadyEvent) {
console.log('ready');
event.api.fromJSON({ event.api.fromJSON({
grid: { grid: {
orientation: Orientation.HORIZONTAL, orientation: Orientation.HORIZONTAL,
@ -113,8 +108,6 @@ const App = defineComponent({
}, },
panels: {}, panels: {},
}); });
this.api = event.api;
}, },
}, },
template: ` template: `

105
yarn.lock
View File

@ -1961,6 +1961,13 @@
dependencies: dependencies:
regenerator-runtime "^0.14.0" regenerator-runtime "^0.14.0"
"@babel/runtime@^7.21.0":
version "7.24.4"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.4.tgz#de795accd698007a66ba44add6cc86542aff1edd"
integrity sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==
dependencies:
regenerator-runtime "^0.14.0"
"@babel/runtime@^7.22.6": "@babel/runtime@^7.22.6":
version "7.23.7" version "7.23.7"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.7.tgz#dd7c88deeb218a0f8bd34d5db1aa242e0f203193" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.7.tgz#dd7c88deeb218a0f8bd34d5db1aa242e0f203193"
@ -2338,7 +2345,7 @@
"@docusaurus/theme-search-algolia" "3.1.1" "@docusaurus/theme-search-algolia" "3.1.1"
"@docusaurus/types" "3.1.1" "@docusaurus/types" "3.1.1"
"@docusaurus/react-loadable@5.5.2", "react-loadable@npm:@docusaurus/react-loadable@5.5.2": "@docusaurus/react-loadable@5.5.2":
version "5.5.2" version "5.5.2"
resolved "https://registry.yarnpkg.com/@docusaurus/react-loadable/-/react-loadable-5.5.2.tgz#81aae0db81ecafbdaee3651f12804580868fa6ce" resolved "https://registry.yarnpkg.com/@docusaurus/react-loadable/-/react-loadable-5.5.2.tgz#81aae0db81ecafbdaee3651f12804580868fa6ce"
integrity sha512-A3dYjdBGuy0IGT+wyLIGIKLRE+sAk1iNk0f1HjNDysO7u8lhL4N3VEm+FAubmJbAztn94F7MxBTPmnixbiyFdQ== integrity sha512-A3dYjdBGuy0IGT+wyLIGIKLRE+sAk1iNk0f1HjNDysO7u8lhL4N3VEm+FAubmJbAztn94F7MxBTPmnixbiyFdQ==
@ -6593,6 +6600,21 @@ concat-with-sourcemaps@^1.0.0, concat-with-sourcemaps@^1.1.0:
dependencies: dependencies:
source-map "^0.6.1" source-map "^0.6.1"
concurrently@^8.2.2:
version "8.2.2"
resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-8.2.2.tgz#353141985c198cfa5e4a3ef90082c336b5851784"
integrity sha512-1dP4gpXFhei8IOtlXRE/T/4H88ElHgTiUzh71YUmtjTEHMSRS2Z/fgOxHSxxusGHogsRfxNq1vyAwxSC+EVyDg==
dependencies:
chalk "^4.1.2"
date-fns "^2.30.0"
lodash "^4.17.21"
rxjs "^7.8.1"
shell-quote "^1.8.1"
spawn-command "0.0.2"
supports-color "^8.1.1"
tree-kill "^1.2.2"
yargs "^17.7.2"
config-chain@^1.1.11: config-chain@^1.1.11:
version "1.1.13" version "1.1.13"
resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.13.tgz#fad0795aa6a6cdaff9ed1b68e9dff94372c232f4" resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.13.tgz#fad0795aa6a6cdaff9ed1b68e9dff94372c232f4"
@ -7077,6 +7099,13 @@ data-urls@^5.0.0:
whatwg-mimetype "^4.0.0" whatwg-mimetype "^4.0.0"
whatwg-url "^14.0.0" whatwg-url "^14.0.0"
date-fns@^2.30.0:
version "2.30.0"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.30.0.tgz#f367e644839ff57894ec6ac480de40cae4b0f4d0"
integrity sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==
dependencies:
"@babel/runtime" "^7.21.0"
dateformat@^3.0.3: dateformat@^3.0.3:
version "3.0.3" version "3.0.3"
resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae"
@ -9200,11 +9229,6 @@ has-yarn@^3.0.0:
resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-3.0.0.tgz#c3c21e559730d1d3b57e28af1f30d06fac38147d" resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-3.0.0.tgz#c3c21e559730d1d3b57e28af1f30d06fac38147d"
integrity sha512-IrsVwUHhEULx3R8f/aA8AHuEzAorplsab/v8HBzEiIukwq5i/EC+xmOW+HfP1OaDP+2JkgT1yILHN2O3UFIbcA== integrity sha512-IrsVwUHhEULx3R8f/aA8AHuEzAorplsab/v8HBzEiIukwq5i/EC+xmOW+HfP1OaDP+2JkgT1yILHN2O3UFIbcA==
hash-sum@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/hash-sum/-/hash-sum-2.0.0.tgz#81d01bb5de8ea4a214ad5d6ead1b523460b0b45a"
integrity sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==
hasown@^2.0.0: hasown@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c" resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c"
@ -14311,6 +14335,14 @@ react-loadable-ssr-addon-v5-slorber@^1.0.1:
dependencies: dependencies:
"@babel/runtime" "^7.10.3" "@babel/runtime" "^7.10.3"
"react-loadable@npm:@docusaurus/react-loadable@5.5.2":
version "5.5.2"
resolved "https://registry.yarnpkg.com/@docusaurus/react-loadable/-/react-loadable-5.5.2.tgz#81aae0db81ecafbdaee3651f12804580868fa6ce"
integrity sha512-A3dYjdBGuy0IGT+wyLIGIKLRE+sAk1iNk0f1HjNDysO7u8lhL4N3VEm+FAubmJbAztn94F7MxBTPmnixbiyFdQ==
dependencies:
"@types/react" "*"
prop-types "^15.6.2"
react-remove-scroll-bar@^2.3.3: react-remove-scroll-bar@^2.3.3:
version "2.3.4" version "2.3.4"
resolved "https://registry.yarnpkg.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.4.tgz#53e272d7a5cb8242990c7f144c44d8bd8ab5afd9" resolved "https://registry.yarnpkg.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.4.tgz#53e272d7a5cb8242990c7f144c44d8bd8ab5afd9"
@ -14947,15 +14979,6 @@ rollup-plugin-postcss@^4.0.2:
safe-identifier "^0.4.2" safe-identifier "^0.4.2"
style-inject "^0.3.0" style-inject "^0.3.0"
rollup-plugin-vue@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/rollup-plugin-vue/-/rollup-plugin-vue-6.0.0.tgz#e379e93e5ae9a8648522f698be2e452e8672aaf2"
integrity sha512-oVvUd84d5u73M2HYM3XsMDLtZRIA/tw2U0dmHlXU2UWP5JARYHzh/U9vcxaN/x/9MrepY7VH3pHFeOhrWpxs/Q==
dependencies:
debug "^4.1.1"
hash-sum "^2.0.0"
rollup-pluginutils "^2.8.2"
rollup-pluginutils@^2.8.2: rollup-pluginutils@^2.8.2:
version "2.8.2" version "2.8.2"
resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz#72f2af0748b592364dbd3389e600e5a9444a351e" resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz#72f2af0748b592364dbd3389e600e5a9444a351e"
@ -15037,7 +15060,7 @@ run-parallel@^1.1.9:
dependencies: dependencies:
queue-microtask "^1.2.2" queue-microtask "^1.2.2"
rxjs@^7.5.5: rxjs@^7.5.5, rxjs@^7.8.1:
version "7.8.1" version "7.8.1"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543"
integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg== integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==
@ -15589,6 +15612,11 @@ sparkles@^1.0.0:
resolved "https://registry.yarnpkg.com/sparkles/-/sparkles-1.0.1.tgz#008db65edce6c50eec0c5e228e1945061dd0437c" resolved "https://registry.yarnpkg.com/sparkles/-/sparkles-1.0.1.tgz#008db65edce6c50eec0c5e228e1945061dd0437c"
integrity sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw== integrity sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==
spawn-command@0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/spawn-command/-/spawn-command-0.0.2.tgz#9544e1a43ca045f8531aac1a48cb29bdae62338e"
integrity sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==
spdx-correct@^3.0.0: spdx-correct@^3.0.0:
version "3.2.0" version "3.2.0"
resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.2.0.tgz#4f5ab0668f0059e34f9c00dce331784a12de4e9c" resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.2.0.tgz#4f5ab0668f0059e34f9c00dce331784a12de4e9c"
@ -15753,7 +15781,7 @@ string-length@^4.0.1:
char-regex "^1.0.2" char-regex "^1.0.2"
strip-ansi "^6.0.0" strip-ansi "^6.0.0"
"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: "string-width-cjs@npm:string-width@^4.2.0":
version "4.2.3" version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@ -15771,6 +15799,15 @@ string-width@^1.0.1, string-width@^1.0.2:
is-fullwidth-code-point "^1.0.0" is-fullwidth-code-point "^1.0.0"
strip-ansi "^3.0.0" strip-ansi "^3.0.0"
"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
dependencies:
emoji-regex "^8.0.0"
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1"
string-width@^5.0.1, string-width@^5.1.2: string-width@^5.0.1, string-width@^5.1.2:
version "5.1.2" version "5.1.2"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794"
@ -15811,7 +15848,7 @@ stringify-object@^3.3.0:
is-obj "^1.0.1" is-obj "^1.0.1"
is-regexp "^1.0.0" is-regexp "^1.0.0"
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: "strip-ansi-cjs@npm:strip-ansi@^6.0.1":
version "6.0.1" version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
@ -15832,6 +15869,13 @@ strip-ansi@^4.0.0:
dependencies: dependencies:
ansi-regex "^3.0.0" ansi-regex "^3.0.0"
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
dependencies:
ansi-regex "^5.0.1"
strip-ansi@^7.0.1: strip-ansi@^7.0.1:
version "7.1.0" version "7.1.0"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45"
@ -15941,7 +15985,7 @@ supports-color@^7.1.0:
dependencies: dependencies:
has-flag "^4.0.0" has-flag "^4.0.0"
supports-color@^8.0.0: supports-color@^8.0.0, supports-color@^8.1.1:
version "8.1.1" version "8.1.1"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c"
integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==
@ -16246,6 +16290,11 @@ tr46@~0.0.3:
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
tree-kill@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc"
integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==
trim-lines@^3.0.0: trim-lines@^3.0.0:
version "3.0.1" version "3.0.1"
resolved "https://registry.yarnpkg.com/trim-lines/-/trim-lines-3.0.1.tgz#d802e332a07df861c48802c04321017b1bd87338" resolved "https://registry.yarnpkg.com/trim-lines/-/trim-lines-3.0.1.tgz#d802e332a07df861c48802c04321017b1bd87338"
@ -16917,6 +16966,11 @@ vscode-textmate@^8.0.0:
resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-8.0.0.tgz#2c7a3b1163ef0441097e0b5d6389cd5504b59e5d" resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-8.0.0.tgz#2c7a3b1163ef0441097e0b5d6389cd5504b59e5d"
integrity sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg== integrity sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==
vue-sfc-loader@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/vue-sfc-loader/-/vue-sfc-loader-0.1.0.tgz#630b8a47ec79e3a80bd9ba781967f6ad23bb149d"
integrity sha512-jWKKX0uGcW2nyiSv3REn4n86V4eYzPbsVWQRnxRO/bxKGrJrAMFl2aYD+38MjPsL6MblzFS/SG0jRcSkzGrElA==
vue-template-compiler@^2.7.14: vue-template-compiler@^2.7.14:
version "2.7.16" version "2.7.16"
resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.7.16.tgz#c81b2d47753264c77ac03b9966a46637482bb03b" resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.7.16.tgz#c81b2d47753264c77ac03b9966a46637482bb03b"
@ -17267,7 +17321,7 @@ wordwrap@^1.0.0:
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: "wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
version "7.0.0" version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
@ -17293,6 +17347,15 @@ wrap-ansi@^6.0.1:
string-width "^4.1.0" string-width "^4.1.0"
strip-ansi "^6.0.0" strip-ansi "^6.0.0"
wrap-ansi@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
dependencies:
ansi-styles "^4.0.0"
string-width "^4.1.0"
strip-ansi "^6.0.0"
wrap-ansi@^8.0.1, wrap-ansi@^8.1.0: wrap-ansi@^8.0.1, wrap-ansi@^8.1.0:
version "8.1.0" version "8.1.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"
@ -17458,7 +17521,7 @@ yargs-parser@^5.0.1:
camelcase "^3.0.0" camelcase "^3.0.0"
object.assign "^4.1.0" object.assign "^4.1.0"
yargs@17.7.2, yargs@^17.3.1, yargs@^17.6.2: yargs@17.7.2, yargs@^17.3.1, yargs@^17.6.2, yargs@^17.7.2:
version "17.7.2" version "17.7.2"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269"
integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==