Date: Mon, 23 Aug 2021 20:53:39 +0100
Subject: [PATCH 2/4] feat: expose dnd functions
---
packages/dockview-demo/public/index.html | 2 +-
.../src/layout-grid/activitybar.tsx | 33 +-
.../src/layout-grid/application.tsx | 4 +-
.../src/layout-grid/sidebar.layout.json | 8 +-
.../dockview-demo/src/layout-grid/sidebar.tsx | 110 ------
packages/dockview-demo/src/services/view.ts | 64 ++++
.../src/services/viewContainer.ts | 127 +++++++
.../src/services/viewRegistry.ts | 49 +++
.../dockview-demo/src/services/viewService.ts | 200 ++++++++++
.../dockview-demo/src/services/widgets.tsx | 357 ++++++++++++++++++
packages/dockview/src/index.ts | 1 +
packages/dockview/src/paneview/paneview.ts | 6 +
.../src/paneview/paneviewComponent.ts | 36 +-
.../dockview/src/react/paneview/paneview.tsx | 39 +-
14 files changed, 888 insertions(+), 148 deletions(-)
create mode 100644 packages/dockview-demo/src/services/view.ts
create mode 100644 packages/dockview-demo/src/services/viewContainer.ts
create mode 100644 packages/dockview-demo/src/services/viewRegistry.ts
create mode 100644 packages/dockview-demo/src/services/viewService.ts
create mode 100644 packages/dockview-demo/src/services/widgets.tsx
diff --git a/packages/dockview-demo/public/index.html b/packages/dockview-demo/public/index.html
index 9b54428e6..3e434a577 100644
--- a/packages/dockview-demo/public/index.html
+++ b/packages/dockview-demo/public/index.html
@@ -1,7 +1,7 @@
-
+
diff --git a/packages/dockview-demo/src/layout-grid/activitybar.tsx b/packages/dockview-demo/src/layout-grid/activitybar.tsx
index d3bd310f6..37242391d 100644
--- a/packages/dockview-demo/src/layout-grid/activitybar.tsx
+++ b/packages/dockview-demo/src/layout-grid/activitybar.tsx
@@ -49,18 +49,27 @@ export const Activitybar = (props: IGridviewPanelProps) => {
return (
);
};
diff --git a/packages/dockview-demo/src/layout-grid/application.tsx b/packages/dockview-demo/src/layout-grid/application.tsx
index fd265a651..748396699 100644
--- a/packages/dockview-demo/src/layout-grid/application.tsx
+++ b/packages/dockview-demo/src/layout-grid/application.tsx
@@ -8,12 +8,12 @@ import {
SerializedGridview,
GridviewApi,
} from 'dockview';
-import { Activitybar } from './activitybar';
+import { Activitybar } from '../services/widgets';
import { Footer } from './footer';
import { Panel } from './panel';
import { TestGrid } from './layoutGrid';
import { useLayoutRegistry } from './registry';
-import { Sidebar } from './sidebar';
+import { Sidebar } from '../services/widgets';
const rootcomponents: {
[index: string]: React.FunctionComponent
;
diff --git a/packages/dockview-demo/src/layout-grid/sidebar.layout.json b/packages/dockview-demo/src/layout-grid/sidebar.layout.json
index 0625e7e4c..5dd7eb9ba 100644
--- a/packages/dockview-demo/src/layout-grid/sidebar.layout.json
+++ b/packages/dockview-demo/src/layout-grid/sidebar.layout.json
@@ -5,7 +5,7 @@
"data": {
"id": "1",
"component": "controlCenter",
- "headerComponent": "default",
+
"props": {},
"title": "Control Center",
"state": {}
@@ -17,7 +17,7 @@
"data": {
"id": "2",
"component": "default",
- "headerComponent": "default",
+
"props": {},
"title": "Panel 1",
"state": {}
@@ -30,7 +30,7 @@
"data": {
"id": "3",
"component": "default",
- "headerComponent": "default",
+
"props": {},
"title": "Panel 2",
"state": {}
@@ -43,7 +43,7 @@
"data": {
"id": "4",
"component": "default",
- "headerComponent": "default",
+
"props": {},
"title": "Panel 3",
"state": {}
diff --git a/packages/dockview-demo/src/layout-grid/sidebar.tsx b/packages/dockview-demo/src/layout-grid/sidebar.tsx
index 6b3b33754..e849abeed 100644
--- a/packages/dockview-demo/src/layout-grid/sidebar.tsx
+++ b/packages/dockview-demo/src/layout-grid/sidebar.tsx
@@ -12,107 +12,6 @@ import { ControlCenter } from './controlCenter';
import { toggleClass } from '../dom';
import './sidebar.scss';
-const DefaultHeader = (props: IPaneviewPanelProps) => {
- const ref = React.useRef();
- const mouseover = React.useRef();
-
- const [url, setUrl] = React.useState(
- props.api.isExpanded
- ? 'https://fonts.gstatic.com/s/i/materialicons/expand_more/v6/24px.svg'
- : 'https://fonts.gstatic.com/s/i/materialicons/chevron_right/v7/24px.svg'
- );
-
- const toggle = () => {
- toggleClass(
- ref.current,
- 'within',
- props.api.isExpanded && mouseover.current
- );
- };
-
- React.useEffect(() => {
- const disposable = new CompositeDisposable(
- props.api.onDidExpansionChange((event) => {
- setUrl(
- event.isExpanded
- ? 'https://fonts.gstatic.com/s/i/materialicons/expand_more/v6/24px.svg'
- : 'https://fonts.gstatic.com/s/i/materialicons/chevron_right/v7/24px.svg'
- );
- toggle();
- }),
- props.api.onMouseEnter((ev) => {
- mouseover.current = true;
- toggle();
- }),
- props.api.onMouseLeave((ev) => {
- mouseover.current = false;
- toggle();
- })
- );
-
- return () => {
- disposable.dispose();
- };
- });
-
- const onClick = (event: React.MouseEvent) => {
- if (event.defaultPrevented) {
- return;
- }
- props.api.setExpanded(!props.api.isExpanded);
- };
-
- const onClickAction = (event: React.MouseEvent) => {
- event.preventDefault();
- };
-
- return (
-
- );
-};
-
const components = {
default: (props: IPaneviewPanelProps) => {
return This is an example panel
;
@@ -120,10 +19,6 @@ const components = {
controlCenter: ControlCenter,
};
-const headerComponents = {
- default: DefaultHeader,
-};
-
export const Sidebar = (props: IGridviewPanelProps) => {
const api = React.useRef();
@@ -139,25 +34,21 @@ export const Sidebar = (props: IGridviewPanelProps) => {
event.api.addPanel({
id: '1',
component: 'default',
- headerComponent: 'default',
title: 'Control Center',
});
event.api.addPanel({
id: '2',
component: 'default',
- headerComponent: 'default',
title: 'Panel 1',
});
event.api.addPanel({
id: '3',
component: 'default',
- headerComponent: 'default',
title: 'Panel 2',
});
event.api.addPanel({
id: '4',
component: 'default',
- headerComponent: 'default',
title: 'Panel 3',
});
@@ -196,7 +87,6 @@ export const Sidebar = (props: IGridviewPanelProps) => {
}}
>
{
+ readonly id: string;
+ readonly views: View[];
+ readonly schema: T | any;
+ readonly icon: string;
+ readonly onDidAddView: Event;
+ readonly onDidRemoveView: Event;
+ addView(view: View, location?: number): void;
+ layout(schema: T): void;
+ removeView(view: View): void;
+ clear(): void;
+ toJSON(): SerializedViewContainer;
+}
+
+export class PaneviewContainer implements ViewContainer {
+ private readonly _id: string;
+ private readonly _views: View[] = [];
+
+ private readonly _onDidAddView = new Emitter();
+ readonly onDidAddView = this._onDidAddView.event;
+ private readonly _onDidRemoveView = new Emitter();
+ readonly onDidRemoveView = this._onDidRemoveView.event;
+
+ private _schema: SerializedPaneview | undefined;
+
+ get id() {
+ return this._id;
+ }
+
+ get views() {
+ return this._views;
+ }
+
+ get schema(): SerializedPaneview | undefined {
+ if (!this._schema) {
+ this._schema = JSON.parse(
+ localStorage.getItem(`viewcontainer_${this.id}`)
+ );
+ }
+ return this._schema;
+ }
+
+ get icon(): string {
+ const defaultIcon = 'search';
+ if (this.views.length > 0) {
+ return this.views.find((v) => !!v.icon)?.icon || defaultIcon;
+ }
+ return defaultIcon;
+ }
+
+ constructor(
+ id: string,
+ viewRegistry: IViewRegistry,
+ views?: SerializedView[]
+ ) {
+ this._id = id;
+
+ if (views) {
+ for (const view of views) {
+ const registeredView = viewRegistry.getRegisteredView(view.id);
+ this.addView(
+ new DefaultView({
+ id: view.id,
+ title: registeredView.title,
+ isExpanded: view.isExpanded,
+ isLocationEditable: registeredView.isLocationEditable,
+ icon: registeredView.icon,
+ })
+ );
+ }
+ }
+ // this.addDisposables(this._onDidAddView, this._onDidRemoveView);
+ }
+
+ layout(schema: SerializedPaneview): void {
+ this._schema = schema;
+ localStorage.setItem(
+ `viewcontainer_${this.id}`,
+ JSON.stringify(schema)
+ );
+ }
+
+ addView(view: View, location = 0): void {
+ this._views.splice(location, 0, view);
+ this._onDidAddView.fire(view);
+ }
+
+ removeView(view: View): void {
+ const index = this._views.indexOf(view);
+ if (index < 0) {
+ throw new Error('invalid');
+ }
+ this._views.splice(index, 1);
+
+ if (this._schema) {
+ this._schema = { ...this._schema };
+ this._schema.views = this._schema.views.filter(
+ (v) => v.data.id !== view.id
+ );
+ this.layout(this._schema);
+ }
+
+ this._onDidRemoveView.fire(view);
+ }
+
+ clear() {
+ localStorage.removeItem(`viewcontainer_${this.id}`);
+ }
+
+ toJSON(): SerializedViewContainer {
+ return { id: this.id, views: this.views.map((v) => v.toJSON()) };
+ }
+}
diff --git a/packages/dockview-demo/src/services/viewRegistry.ts b/packages/dockview-demo/src/services/viewRegistry.ts
new file mode 100644
index 000000000..2a77a4ad1
--- /dev/null
+++ b/packages/dockview-demo/src/services/viewRegistry.ts
@@ -0,0 +1,49 @@
+export interface RegisteredView {
+ id: string;
+ icon: string;
+ title: string;
+ isLocationEditable: boolean;
+}
+
+export interface IViewRegistry {
+ getRegisteredView(id: string): RegisteredView | undefined;
+}
+
+export class ViewRegistry {
+ private readonly _registry = new Map();
+
+ register(registeredView: RegisteredView): void {
+ this._registry.set(registeredView.id, registeredView);
+ }
+
+ getRegisteredView(id: string): RegisteredView | undefined {
+ return this._registry.get(id);
+ }
+}
+
+export const VIEW_REGISTRY = new ViewRegistry();
+
+VIEW_REGISTRY.register({
+ id: 'search_widget',
+ title: 'search',
+ icon: 'search',
+ isLocationEditable: false,
+});
+VIEW_REGISTRY.register({
+ id: 'home_widget',
+ title: 'Home',
+ icon: 'home',
+ isLocationEditable: true,
+});
+VIEW_REGISTRY.register({
+ id: 'account_widget',
+ title: 'Account',
+ icon: 'account_circle',
+ isLocationEditable: true,
+});
+VIEW_REGISTRY.register({
+ id: 'settings_widget',
+ title: 'Settings',
+ icon: 'settings',
+ isLocationEditable: true,
+});
diff --git a/packages/dockview-demo/src/services/viewService.ts b/packages/dockview-demo/src/services/viewService.ts
new file mode 100644
index 000000000..1c9dc4d77
--- /dev/null
+++ b/packages/dockview-demo/src/services/viewService.ts
@@ -0,0 +1,200 @@
+import {
+ CompositeDisposable,
+ Emitter,
+ Event,
+ IDisposable,
+ IView,
+} from 'dockview';
+import { DefaultView, View } from './view';
+import {
+ PaneviewContainer,
+ ViewContainer,
+ SerializedViewContainer,
+} from './viewContainer';
+import { IViewRegistry } from './viewRegistry';
+
+export interface SerializedViewService {
+ containers: SerializedViewContainer[];
+ activeContainer?: string;
+}
+
+export interface IViewService extends IDisposable {
+ readonly containers: ViewContainer[];
+ readonly onDidActiveContainerChange: Event;
+ readonly onDidRemoveContainer: Event;
+ readonly onDidAddContainer: Event;
+ readonly onDidContainersChange: Event;
+ readonly activeContainer: ViewContainer | undefined;
+ addContainer(container: ViewContainer): void;
+ setActiveViewContainer(id: string): void;
+ getView(id: string): View | undefined;
+ moveViewToLocation(
+ view: View,
+ targetViewContainer: ViewContainer,
+ targetLocation: number
+ ): void;
+ insertContainerAfter(source: ViewContainer, target: ViewContainer): void;
+ addViews(view: View, viewContainer: ViewContainer, location?: number): void;
+ removeViews(removeViews: View[], viewContainer: ViewContainer): void;
+ getViewContainer(id: string): ViewContainer | undefined;
+ getViewContainer2(view: View): ViewContainer | undefined;
+ toJSON(): SerializedViewService;
+ load(layout: SerializedViewService): void;
+}
+
+export class ViewService implements IViewService {
+ private _viewContainers: ViewContainer[] = [];
+ private readonly _onDidActiveContainerChange = new Emitter();
+ readonly onDidActiveContainerChange = this._onDidActiveContainerChange
+ .event;
+ private readonly _onDidRemoveContainer = new Emitter();
+ readonly onDidRemoveContainer = this._onDidRemoveContainer.event;
+ private readonly _onDidAddContainer = new Emitter();
+ readonly onDidAddContainer = this._onDidAddContainer.event;
+ private readonly _onDidContainersChange = new Emitter();
+ readonly onDidContainersChange = this._onDidContainersChange.event;
+ private _activeViewContainerId: string;
+
+ get containers(): ViewContainer[] {
+ return this._viewContainers;
+ }
+
+ get activeContainer(): ViewContainer | undefined {
+ return this._viewContainers.find(
+ (c) => c.id === this._activeViewContainerId
+ );
+ }
+
+ constructor(private readonly viewRegistry: IViewRegistry) {
+ //
+ }
+
+ load(layout: SerializedViewService): void {
+ const { containers, activeContainer } = layout;
+
+ for (const container of containers) {
+ const { id, views } = container;
+ const viewContainer = new PaneviewContainer(
+ id,
+ this.viewRegistry,
+ views
+ );
+
+ this.addContainer(viewContainer);
+ }
+
+ this.setActiveViewContainer(activeContainer);
+ }
+
+ insertContainerAfter(source: ViewContainer, target: ViewContainer): void {
+ const sourceIndex = this._viewContainers.findIndex(
+ (c) => c.id === source.id
+ );
+
+ const view = this._viewContainers.splice(sourceIndex, 1)[0];
+
+ const targetIndex = this._viewContainers.findIndex(
+ (c) => c.id === target.id
+ );
+
+ this._viewContainers.splice(targetIndex + 1, 0, view);
+ this._viewContainers = [...this._viewContainers];
+
+ this._onDidContainersChange.fire();
+ }
+
+ addContainer(container: ViewContainer): void {
+ this._viewContainers = [...this._viewContainers, container];
+ this._activeViewContainerId = container.id;
+ this._onDidAddContainer.fire();
+ }
+
+ removeContainer(container: ViewContainer): void {
+ this._viewContainers = this._viewContainers.filter(
+ (c) => c.id !== container.id
+ );
+
+ if (this._activeViewContainerId === container.id) {
+ this._activeViewContainerId =
+ this._viewContainers.length > 0
+ ? this._viewContainers[0].id
+ : undefined;
+ }
+
+ this._onDidRemoveContainer.fire();
+ }
+
+ setActiveViewContainer(id: string): void {
+ if (!this._viewContainers.find((c) => c.id === id)) {
+ throw new Error(`invalid container ${id}`);
+ }
+ this._activeViewContainerId = id;
+ this._onDidActiveContainerChange.fire();
+ }
+
+ getView(id: string): View | undefined {
+ for (const container of Array.from(this._viewContainers.values())) {
+ const view = container.views.find((v) => v.id === id);
+ if (view) {
+ return view;
+ }
+ }
+ return undefined;
+ }
+
+ moveViewToLocation(
+ view: View,
+ targetViewContainer: ViewContainer,
+ targetLocation: number
+ ): void {
+ const sourceViewContainer = this.getViewContainer2(view);
+ this.removeViews([view], sourceViewContainer);
+ this.addViews(view, targetViewContainer, targetLocation);
+ }
+
+ addViews(
+ view: View,
+ viewContainer: ViewContainer,
+ location?: number
+ ): void {
+ viewContainer.addView(view, location);
+ }
+
+ removeViews(removeViews: View[], viewContainer: ViewContainer): void {
+ for (const view of removeViews) {
+ viewContainer.removeView(view);
+
+ if (viewContainer.views.length === 0) {
+ viewContainer.clear();
+ this.removeContainer(viewContainer);
+ }
+ }
+ }
+
+ getViewContainer(id: string): ViewContainer | undefined {
+ return this._viewContainers.find((c) => c.id === id);
+ }
+
+ getViewContainer2(view: View): ViewContainer | undefined {
+ for (const container of Array.from(this._viewContainers.values())) {
+ const v = container.views.find((v) => v.id === view.id);
+ if (v) {
+ return container;
+ }
+ }
+ return undefined;
+ }
+
+ toJSON(): SerializedViewService {
+ return {
+ containers: this.containers.map((c) => c.toJSON()),
+ activeContainer: this.activeContainer.id,
+ };
+ }
+
+ dispose(): void {
+ this._onDidActiveContainerChange.dispose();
+ this._onDidAddContainer.dispose();
+ this._onDidRemoveContainer.dispose();
+ }
+}
diff --git a/packages/dockview-demo/src/services/widgets.tsx b/packages/dockview-demo/src/services/widgets.tsx
new file mode 100644
index 000000000..fb2d17a70
--- /dev/null
+++ b/packages/dockview-demo/src/services/widgets.tsx
@@ -0,0 +1,357 @@
+import {
+ CompositeDisposable,
+ GridviewApi,
+ IGridviewPanelProps,
+ IPaneviewPanelProps,
+ PanelCollection,
+ PaneviewApi,
+ PaneviewDropEvent,
+ PaneviewReact,
+ PaneviewReadyEvent,
+ getPaneData,
+} from 'dockview';
+import * as React from 'react';
+import { useLayoutRegistry } from '../layout-grid/registry';
+import { PaneviewContainer, ViewContainer } from './viewContainer';
+import { IViewService, ViewService } from './viewService';
+import { DefaultView } from './view';
+import { RegisteredView, VIEW_REGISTRY } from './viewRegistry';
+
+class ViewServiceModel {
+ private readonly viewService: IViewService;
+
+ get model() {
+ return this.viewService;
+ }
+
+ constructor() {
+ this.viewService = new ViewService(VIEW_REGISTRY);
+ this.init();
+ }
+
+ init(): void {
+ const layout = localStorage.getItem('viewservice');
+ if (layout) {
+ this.viewService.load(JSON.parse(layout));
+ } else {
+ const container1 = new PaneviewContainer(
+ 'default_container_1',
+ VIEW_REGISTRY
+ );
+ if (!container1.schema) {
+ this.addView(
+ container1,
+ VIEW_REGISTRY.getRegisteredView('search_widget')
+ );
+ this.addView(
+ container1,
+ VIEW_REGISTRY.getRegisteredView('home_widget')
+ );
+ }
+ const container2 = new PaneviewContainer(
+ 'default_container_2',
+ VIEW_REGISTRY
+ );
+ if (!container2.schema) {
+ this.addView(
+ container2,
+ VIEW_REGISTRY.getRegisteredView('account_widget')
+ );
+ this.addView(
+ container2,
+ VIEW_REGISTRY.getRegisteredView('settings_widget')
+ );
+ }
+ this.viewService.addContainer(container1);
+ this.viewService.addContainer(container2);
+ }
+
+ const save = () => {
+ localStorage.setItem(
+ 'viewservice',
+ JSON.stringify(this.viewService.toJSON())
+ );
+ };
+
+ this.viewService.onDidActiveContainerChange(save);
+ this.viewService.onDidRemoveContainer(save);
+ this.viewService.onDidAddContainer(save);
+ }
+
+ private addView(
+ container: ViewContainer,
+ registedView: RegisteredView
+ ): void {
+ container.addView(
+ new DefaultView({
+ id: registedView.id,
+ title: registedView.title,
+ isExpanded: true,
+ isLocationEditable: registedView.isLocationEditable,
+ icon: registedView.icon,
+ })
+ );
+ }
+}
+
+const viewService = new ViewServiceModel();
+
+const components: PanelCollection> = {
+ default: (props: IPaneviewPanelProps<{ viewId: string }>) => {
+ return (
+
+ {props.params.viewId}
+
+ );
+ },
+};
+
+export const Activitybar = (props: IGridviewPanelProps) => {
+ const [activeContainerid, setActiveContainerId] = React.useState(
+ viewService.model.activeContainer.id
+ );
+ const [containers, setContainers] = React.useState(
+ viewService.model.containers
+ );
+
+ const registry = useLayoutRegistry();
+
+ React.useEffect(() => {
+ const disposable = new CompositeDisposable(
+ viewService.model.onDidActiveContainerChange(() => {
+ setActiveContainerId(viewService.model.activeContainer.id);
+ }),
+ viewService.model.onDidAddContainer(() => {
+ setContainers(viewService.model.containers);
+ }),
+ viewService.model.onDidRemoveContainer(() => {
+ setContainers(viewService.model.containers);
+ }),
+ viewService.model.onDidContainersChange(() => {
+ setContainers(viewService.model.containers);
+ })
+ );
+
+ return () => {
+ disposable.dispose();
+ };
+ }, []);
+
+ const onClick = (container: ViewContainer, alwaysOpen = false) => (
+ event: React.MouseEvent
+ ) => {
+ const api = registry.get('gridview');
+
+ const selectedActive = container.id === activeContainerid;
+
+ const sidebarPanel = api.getPanel('sidebar');
+ if (sidebarPanel.api.isVisible) {
+ if (!alwaysOpen && selectedActive) {
+ api.setVisible(sidebarPanel, false);
+ }
+ } else {
+ event.preventDefault(); // prevent focus
+ api.setVisible(sidebarPanel, true);
+ sidebarPanel.focus();
+ }
+
+ viewService.model.setActiveViewContainer(container.id);
+ };
+
+ const onDrop = (targetContainer: ViewContainer) => (
+ event: React.DragEvent
+ ) => {
+ const data = event.dataTransfer.getData('application/json');
+ if (data) {
+ const { container } = JSON.parse(data);
+ const sourceContainer = viewService.model.getViewContainer(
+ container
+ );
+ viewService.model.insertContainerAfter(
+ sourceContainer,
+ targetContainer
+ );
+ }
+ };
+
+ const onNewContainer = (event: React.DragEvent) => {
+ const data = getPaneData();
+ if (data) {
+ const { paneId } = data;
+ const view = viewService.model.getView(paneId);
+ const viewContainer = viewService.model.getViewContainer2(view);
+ viewService.model.removeViews([view], viewContainer);
+ // viewContainer.removeView(view);
+ const newContainer = new PaneviewContainer(
+ `t_${Date.now().toString().substr(5)}`,
+ VIEW_REGISTRY
+ );
+ newContainer.addView(view);
+ viewService.model.addContainer(newContainer);
+ }
+ };
+
+ return (
+
+ {containers.map((container, i) => {
+ const isActive = activeContainerid === container.id;
+ return (
+
{
+ e.preventDefault();
+ onClick(container, true)(e);
+ }}
+ onDragEnter={(e) => {
+ e.preventDefault();
+ }}
+ draggable={true}
+ onDragStart={(e) => {
+ e.dataTransfer.setData(
+ 'application/json',
+ JSON.stringify({ container: container.id })
+ );
+ }}
+ onDrop={onDrop(container)}
+ style={{
+ display: 'flex',
+ justifyContent: 'center',
+ alignItems: 'center',
+ height: '48px',
+ boxSizing: 'border-box',
+ borderLeft: isActive
+ ? '1px solid white'
+ : '1px solid transparent',
+ }}
+ key={i}
+ >
+ {/* {container.id} */}
+
+ {container.icon}
+
+
+ );
+ })}
+
{
+ e.preventDefault();
+ }}
+ onDragEnter={(e) => {
+ e.preventDefault();
+ }}
+ onDrop={onNewContainer}
+ style={{ height: '100%', backgroundColor: 'red' }}
+ >
+
+ );
+};
+
+export const Sidebar = () => {
+ const [sidebarId, setSidebarId] = React.useState(
+ viewService.model.activeContainer.id
+ );
+
+ React.useEffect(() => {
+ const disposable = viewService.model.onDidActiveContainerChange(() => {
+ setSidebarId(viewService.model.activeContainer.id);
+ });
+
+ return () => {
+ disposable.dispose();
+ };
+ }, []);
+
+ return ;
+};
+
+export const SidebarPart = (props: { id: string }) => {
+ const [api, setApi] = React.useState();
+
+ React.useEffect(() => {
+ if (!api) {
+ return () => {
+ //
+ };
+ }
+
+ const viewContainer = viewService.model.getViewContainer(props.id);
+
+ const disposables = new CompositeDisposable(
+ api.onDidLayoutChange(() => {
+ viewContainer.layout(api.toJSON());
+ }),
+ viewContainer.onDidAddView((view) => {
+ api.addPanel({
+ id: view.id,
+ isExpanded: view.isExpanded,
+ title: view.title,
+ component: 'default',
+ params: {
+ viewId: view.id,
+ },
+ });
+ }),
+ viewContainer.onDidRemoveView((view) => {
+ const panel = api.getPanel(view.id);
+ api.removePanel(panel);
+ })
+ );
+
+ const schema = viewContainer.schema;
+ if (schema) {
+ api.fromJSON(schema);
+ } else {
+ api.getPanels().forEach((p) => {
+ api.removePanel(p);
+ });
+ viewContainer.views.forEach((view) => {
+ api.addPanel({
+ id: view.id,
+ isExpanded: view.isExpanded,
+ title: view.title,
+ component: 'default',
+ params: {
+ viewId: view.id,
+ },
+ });
+ });
+ }
+
+ return () => {
+ disposables.dispose();
+ };
+ }, [api, props.id]);
+
+ const onReady = (event: PaneviewReadyEvent) => {
+ setApi(event.api);
+ };
+
+ const onDidDrop = (event: PaneviewDropEvent) => {
+ const data = getPaneData();
+
+ if (!data) {
+ return;
+ }
+
+ const viewId = data.paneId;
+ const viewContainer = viewService.model.getViewContainer(props.id);
+ const view = viewService.model.getView(viewId);
+
+ viewService.model.moveViewToLocation(view, viewContainer, 0);
+ };
+
+ if (!props.id) {
+ return null;
+ }
+
+ return (
+
+ );
+};
diff --git a/packages/dockview/src/index.ts b/packages/dockview/src/index.ts
index 8ad56d994..b121d7063 100644
--- a/packages/dockview/src/index.ts
+++ b/packages/dockview/src/index.ts
@@ -16,6 +16,7 @@ export * from './groupview/types';
export * from './dockview/dockviewComponent';
export * from './dockview/options';
export * from './gridview/gridviewComponent';
+export * from './dnd/dataTransfer';
export * from './react'; // TODO: should be conditional on whether user wants the React wrappers
diff --git a/packages/dockview/src/paneview/paneview.ts b/packages/dockview/src/paneview/paneview.ts
index 9c569c015..8e59de810 100644
--- a/packages/dockview/src/paneview/paneview.ts
+++ b/packages/dockview/src/paneview/paneview.ts
@@ -96,6 +96,12 @@ export class Paneview extends CompositeDisposable implements IDisposable {
this.addDisposables(
this.splitview.onDidSashEnd(() => {
this._onDidChange.fire(undefined);
+ }),
+ this.splitview.onDidAddView(() => {
+ this._onDidChange.fire();
+ }),
+ this.splitview.onDidRemoveView(() => {
+ this._onDidChange.fire();
})
);
}
diff --git a/packages/dockview/src/paneview/paneviewComponent.ts b/packages/dockview/src/paneview/paneviewComponent.ts
index 53503b30a..69e2a96b0 100644
--- a/packages/dockview/src/paneview/paneviewComponent.ts
+++ b/packages/dockview/src/paneview/paneviewComponent.ts
@@ -128,9 +128,10 @@ export interface IPaneviewComponent extends IDisposable {
readonly height: number;
readonly minimumSize: number;
readonly maximumSize: number;
+ readonly onDidDrop: Event;
+ readonly onDidLayoutChange: Event;
addPanel(options: AddPaneviewCompponentOptions): IDisposable;
layout(width: number, height: number): void;
- onDidLayoutChange: Event;
toJSON(): SerializedPaneview;
fromJSON(
serializedPaneview: SerializedPaneview,
@@ -142,6 +143,7 @@ export interface IPaneviewComponent extends IDisposable {
removePanel(panel: IPaneviewPanel): void;
getPanel(id: string): IPaneviewPanel | undefined;
movePanel(from: number, to: number): void;
+ updateOptions(options: Partial): void;
}
export class PaneviewComponent
@@ -199,12 +201,20 @@ export class PaneviewComponent
: this.paneview.orthogonalSize;
}
+ private _options: PaneviewComponentOptions;
+
+ get options() {
+ return this._options;
+ }
+
constructor(
private element: HTMLElement,
- private readonly options: PaneviewComponentOptions
+ options: PaneviewComponentOptions
) {
super();
+ this._options = options;
+
if (!options.components) {
options.components = {};
}
@@ -224,6 +234,10 @@ export class PaneviewComponent
//
}
+ updateOptions(options: Partial): void {
+ this._options = { ...this.options, ...options };
+ }
+
addPanel(options: AddPaneviewCompponentOptions): IDisposable {
const body = createComponent(
options.id,
@@ -269,17 +283,17 @@ export class PaneviewComponent
disableDnd: !!this.options.disableDnd,
});
- view.onDidDrop((event) => {
- this._onDidDrop.fire(event);
- });
+ const disposable = new CompositeDisposable(
+ view.onDidDrop((event) => {
+ this._onDidDrop.fire(event);
+ })
+ );
const size: Sizing | number =
typeof options.size === 'number' ? options.size : Sizing.Distribute;
const index =
typeof options.index === 'number' ? options.index : undefined;
- this.paneview.addPane(view, size, index);
-
view.init({
params: options.params || {},
minimumBodySize: options.minimumBodySize,
@@ -289,13 +303,11 @@ export class PaneviewComponent
containerApi: new PaneviewApi(this),
});
+ this.paneview.addPane(view, size, index);
+
view.orientation = this.paneview.orientation;
- return {
- dispose: () => {
- //
- },
- };
+ return disposable;
}
getPanels(): PaneviewPanel[] {
diff --git a/packages/dockview/src/react/paneview/paneview.tsx b/packages/dockview/src/react/paneview/paneview.tsx
index d499b5a27..4e6fb48c9 100644
--- a/packages/dockview/src/react/paneview/paneview.tsx
+++ b/packages/dockview/src/react/paneview/paneview.tsx
@@ -62,6 +62,18 @@ export const PaneviewReact = React.forwardRef(
};
}, [props.disableAutoResizing]);
+ React.useEffect(() => {
+ paneviewRef.current?.updateOptions({
+ frameworkComponents: props.components,
+ });
+ }, [props.components]);
+
+ React.useEffect(() => {
+ paneviewRef.current?.updateOptions({
+ headerframeworkComponents: props.headerComponents,
+ });
+ }, [props.headerComponents]);
+
React.useEffect(() => {
const createComponent = (
id: string,
@@ -90,12 +102,6 @@ export const PaneviewReact = React.forwardRef(
const api = new PaneviewApi(paneview);
- const disposable = paneview.onDidDrop((event) => {
- if (props.onDidDrop) {
- props.onDidDrop({ event, api });
- }
- });
-
const { clientWidth, clientHeight } = domRef.current!;
paneview.layout(clientWidth, clientHeight);
@@ -106,11 +112,30 @@ export const PaneviewReact = React.forwardRef(
paneviewRef.current = paneview;
return () => {
- disposable.dispose();
paneview.dispose();
};
}, []);
+ React.useEffect(() => {
+ if (!paneviewRef.current) {
+ return () => {
+ //
+ };
+ }
+
+ const paneview = paneviewRef.current;
+
+ const disposable = paneview.onDidDrop((event) => {
+ if (props.onDidDrop) {
+ props.onDidDrop({ event, api: new PaneviewApi(paneview) });
+ }
+ });
+
+ return () => {
+ disposable.dispose();
+ };
+ }, [props.onDidDrop]);
+
return (
Date: Sat, 2 Oct 2021 12:14:16 +0100
Subject: [PATCH 3/4] test: fix tests
---
packages/dockview/src/__tests__/__test_utils__/utils.ts | 2 +-
packages/dockview/src/react/paneview/paneview.tsx | 4 +++-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/packages/dockview/src/__tests__/__test_utils__/utils.ts b/packages/dockview/src/__tests__/__test_utils__/utils.ts
index 2a99e97f0..ab8dc0a9e 100644
--- a/packages/dockview/src/__tests__/__test_utils__/utils.ts
+++ b/packages/dockview/src/__tests__/__test_utils__/utils.ts
@@ -10,5 +10,5 @@ export function setMockRefElement(node: Partial
): void {
},
};
- jest.spyOn(React, 'useRef').mockReturnValue(mockRef);
+ jest.spyOn(React, 'useRef').mockReturnValueOnce(mockRef);
}
diff --git a/packages/dockview/src/react/paneview/paneview.tsx b/packages/dockview/src/react/paneview/paneview.tsx
index 2b7e633d3..99889bece 100644
--- a/packages/dockview/src/react/paneview/paneview.tsx
+++ b/packages/dockview/src/react/paneview/paneview.tsx
@@ -118,7 +118,9 @@ export const PaneviewReact = React.forwardRef(
React.useEffect(() => {
if (!paneviewRef.current) {
- return;
+ return () => {
+ // noop
+ };
}
const paneview = paneviewRef.current;
From 29771cace1b0cae265937d505925b6692dde8a0d Mon Sep 17 00:00:00 2001
From: mathuo <6710312+mathuo@users.noreply.github.com>
Date: Mon, 4 Oct 2021 20:21:05 +0100
Subject: [PATCH 4/4] feat: draggable panels work
---
.../src/services/viewContainer.ts | 13 ++-
.../{viewRegistry.ts => viewRegistry.tsx} | 15 +++
.../dockview-demo/src/services/widgets.scss | 5 +
.../dockview-demo/src/services/widgets.tsx | 91 ++++++++++++++-----
packages/dockview/src/index.ts | 1 +
.../src/paneview/draggablePaneviewPanel.ts | 39 ++++++--
packages/dockview/src/paneview/paneview.scss | 5 +
.../src/paneview/paneviewComponent.ts | 13 ++-
.../dockview/src/react/paneview/paneview.tsx | 34 ++++---
9 files changed, 161 insertions(+), 55 deletions(-)
rename packages/dockview-demo/src/services/{viewRegistry.ts => viewRegistry.tsx} (75%)
create mode 100644 packages/dockview-demo/src/services/widgets.scss
diff --git a/packages/dockview-demo/src/services/viewContainer.ts b/packages/dockview-demo/src/services/viewContainer.ts
index 72f5067c3..70245db75 100644
--- a/packages/dockview-demo/src/services/viewContainer.ts
+++ b/packages/dockview-demo/src/services/viewContainer.ts
@@ -17,7 +17,7 @@ export interface ViewContainer {
readonly views: View[];
readonly schema: T | any;
readonly icon: string;
- readonly onDidAddView: Event;
+ readonly onDidAddView: Event<{ view: View; index?: number }>;
readonly onDidRemoveView: Event;
addView(view: View, location?: number): void;
layout(schema: T): void;
@@ -30,7 +30,10 @@ export class PaneviewContainer implements ViewContainer {
private readonly _id: string;
private readonly _views: View[] = [];
- private readonly _onDidAddView = new Emitter();
+ private readonly _onDidAddView = new Emitter<{
+ view: View;
+ index?: number;
+ }>();
readonly onDidAddView = this._onDidAddView.event;
private readonly _onDidRemoveView = new Emitter();
readonly onDidRemoveView = this._onDidRemoveView.event;
@@ -94,9 +97,9 @@ export class PaneviewContainer implements ViewContainer {
);
}
- addView(view: View, location = 0): void {
- this._views.splice(location, 0, view);
- this._onDidAddView.fire(view);
+ addView(view: View, index?: number): void {
+ this._views.splice(index, 0, view);
+ this._onDidAddView.fire({ view, index });
}
removeView(view: View): void {
diff --git a/packages/dockview-demo/src/services/viewRegistry.ts b/packages/dockview-demo/src/services/viewRegistry.tsx
similarity index 75%
rename from packages/dockview-demo/src/services/viewRegistry.ts
rename to packages/dockview-demo/src/services/viewRegistry.tsx
index 2a77a4ad1..3304b6d3e 100644
--- a/packages/dockview-demo/src/services/viewRegistry.ts
+++ b/packages/dockview-demo/src/services/viewRegistry.tsx
@@ -1,8 +1,11 @@
+import React from 'react';
+
export interface RegisteredView {
id: string;
icon: string;
title: string;
isLocationEditable: boolean;
+ component: React.FunctionComponent;
}
export interface IViewRegistry {
@@ -28,22 +31,34 @@ VIEW_REGISTRY.register({
title: 'search',
icon: 'search',
isLocationEditable: false,
+ component: () => {
+ return This is a search bar component
;
+ },
});
VIEW_REGISTRY.register({
id: 'home_widget',
title: 'Home',
icon: 'home',
isLocationEditable: true,
+ component: () => {
+ return Home
;
+ },
});
VIEW_REGISTRY.register({
id: 'account_widget',
title: 'Account',
icon: 'account_circle',
isLocationEditable: true,
+ component: () => {
+ return account_circle
;
+ },
});
VIEW_REGISTRY.register({
id: 'settings_widget',
title: 'Settings',
icon: 'settings',
isLocationEditable: true,
+ component: () => {
+ return settings
;
+ },
});
diff --git a/packages/dockview-demo/src/services/widgets.scss b/packages/dockview-demo/src/services/widgets.scss
new file mode 100644
index 000000000..7859ccb12
--- /dev/null
+++ b/packages/dockview-demo/src/services/widgets.scss
@@ -0,0 +1,5 @@
+.activity-bar-space {
+ &.activity-bar-space-dragover {
+ background-color: green !important;
+ }
+}
diff --git a/packages/dockview-demo/src/services/widgets.tsx b/packages/dockview-demo/src/services/widgets.tsx
index fb2d17a70..4408f492d 100644
--- a/packages/dockview-demo/src/services/widgets.tsx
+++ b/packages/dockview-demo/src/services/widgets.tsx
@@ -1,5 +1,6 @@
import {
CompositeDisposable,
+ getPaneData,
GridviewApi,
IGridviewPanelProps,
IPaneviewPanelProps,
@@ -8,7 +9,7 @@ import {
PaneviewDropEvent,
PaneviewReact,
PaneviewReadyEvent,
- getPaneData,
+ Position,
} from 'dockview';
import * as React from 'react';
import { useLayoutRegistry } from '../layout-grid/registry';
@@ -16,6 +17,8 @@ import { PaneviewContainer, ViewContainer } from './viewContainer';
import { IViewService, ViewService } from './viewService';
import { DefaultView } from './view';
import { RegisteredView, VIEW_REGISTRY } from './viewRegistry';
+import { toggleClass } from '../dom';
+import './widgets.scss';
class ViewServiceModel {
private readonly viewService: IViewService;
@@ -96,13 +99,23 @@ class ViewServiceModel {
const viewService = new ViewServiceModel();
+const colors = {
+ home_widget: 'red',
+ account_widget: 'green',
+ settings_widget: 'yellow',
+ search_widget: 'orange',
+};
+
const components: PanelCollection> = {
default: (props: IPaneviewPanelProps<{ viewId: string }>) => {
- return (
-
- {props.params.viewId}
-
- );
+ const Component = React.useMemo(() => {
+ const registeredView = VIEW_REGISTRY.getRegisteredView(
+ props.params.viewId
+ );
+ return registeredView?.component;
+ }, [props.params.viewId]);
+
+ return Component ? : null;
},
};
@@ -158,7 +171,7 @@ export const Activitybar = (props: IGridviewPanelProps) => {
viewService.model.setActiveViewContainer(container.id);
};
- const onDrop = (targetContainer: ViewContainer) => (
+ const onContainerDrop = (targetContainer: ViewContainer) => (
event: React.DragEvent
) => {
const data = event.dataTransfer.getData('application/json');
@@ -192,7 +205,7 @@ export const Activitybar = (props: IGridviewPanelProps) => {
};
return (
-
+
{containers.map((container, i) => {
const isActive = activeContainerid === container.id;
return (
@@ -212,7 +225,7 @@ export const Activitybar = (props: IGridviewPanelProps) => {
JSON.stringify({ container: container.id })
);
}}
- onDrop={onDrop(container)}
+ onDrop={onContainerDrop(container)}
style={{
display: 'flex',
justifyContent: 'center',
@@ -235,20 +248,36 @@ export const Activitybar = (props: IGridviewPanelProps) => {
);
})}
-
{
- e.preventDefault();
- }}
- onDragEnter={(e) => {
- e.preventDefault();
- }}
- onDrop={onNewContainer}
- style={{ height: '100%', backgroundColor: 'red' }}
- >
+
);
};
+const ExtraSpace = (props: {
+ onNewContainer: (event: React.DragEvent) => void;
+}) => {
+ const ref = React.useRef(null);
+
+ return (
+ {
+ e.preventDefault();
+ }}
+ onDragEnter={(e) => {
+ toggleClass(ref.current, 'activity-bar-space-dragover', true);
+ e.preventDefault();
+ }}
+ onDragLeave={(e) => {
+ toggleClass(ref.current, 'activity-bar-space-dragover', false);
+ }}
+ onDrop={props.onNewContainer}
+ style={{ height: '100%', backgroundColor: 'red' }}
+ >
+ );
+};
+
export const Sidebar = () => {
const [sidebarId, setSidebarId] = React.useState(
viewService.model.activeContainer.id
@@ -283,7 +312,7 @@ export const SidebarPart = (props: { id: string }) => {
api.onDidLayoutChange(() => {
viewContainer.layout(api.toJSON());
}),
- viewContainer.onDidAddView((view) => {
+ viewContainer.onDidAddView(({ view, index }) => {
api.addPanel({
id: view.id,
isExpanded: view.isExpanded,
@@ -292,6 +321,7 @@ export const SidebarPart = (props: { id: string }) => {
params: {
viewId: view.id,
},
+ index,
});
}),
viewContainer.onDidRemoveView((view) => {
@@ -330,17 +360,34 @@ export const SidebarPart = (props: { id: string }) => {
};
const onDidDrop = (event: PaneviewDropEvent) => {
- const data = getPaneData();
+ const data = event.event.getData();
if (!data) {
return;
}
+ const targetPanel = event.event.panel;
+ const allPanels = event.api.getPanels();
+ let toIndex = allPanels.indexOf(targetPanel);
+
+ // if (
+ // event.event.position === Position.Left ||
+ // event.event.position === Position.Top
+ // ) {
+ // toIndex = Math.max(0, toIndex - 1);
+ // }
+ if (
+ event.event.position === Position.Right ||
+ event.event.position === Position.Bottom
+ ) {
+ toIndex = Math.min(allPanels.length, toIndex + 1);
+ }
+
const viewId = data.paneId;
const viewContainer = viewService.model.getViewContainer(props.id);
const view = viewService.model.getView(viewId);
- viewService.model.moveViewToLocation(view, viewContainer, 0);
+ viewService.model.moveViewToLocation(view, viewContainer, toIndex);
};
if (!props.id) {
diff --git a/packages/dockview/src/index.ts b/packages/dockview/src/index.ts
index b121d7063..9f2c6a2dc 100644
--- a/packages/dockview/src/index.ts
+++ b/packages/dockview/src/index.ts
@@ -17,6 +17,7 @@ export * from './dockview/dockviewComponent';
export * from './dockview/options';
export * from './gridview/gridviewComponent';
export * from './dnd/dataTransfer';
+export { Position } from './dnd/droptarget';
export * from './react'; // TODO: should be conditional on whether user wants the React wrappers
diff --git a/packages/dockview/src/paneview/draggablePaneviewPanel.ts b/packages/dockview/src/paneview/draggablePaneviewPanel.ts
index 4aea7d119..b26436fda 100644
--- a/packages/dockview/src/paneview/draggablePaneviewPanel.ts
+++ b/packages/dockview/src/paneview/draggablePaneviewPanel.ts
@@ -9,7 +9,11 @@ import {
import { Emitter, Event } from '../events';
import { IDisposable } from '../lifecycle';
import { Orientation } from '../splitview/core/splitview';
-import { PanePanelInitParameter, PaneviewPanel } from './paneviewPanel';
+import {
+ IPaneviewPanel,
+ PanePanelInitParameter,
+ PaneviewPanel,
+} from './paneviewPanel';
interface ViewContainer {
readonly title: string;
@@ -28,11 +32,16 @@ interface IViewContainerService {
getViewContainerModel(container: ViewContainer): ViewContainerModel;
}
+export interface PaneviewDropEvent2 extends DroptargetEvent {
+ panel: IPaneviewPanel;
+ getData: () => PaneTransfer | undefined;
+}
+
export abstract class DraggablePaneviewPanel extends PaneviewPanel {
private handler: DragHandler | undefined;
private target: Droptarget | undefined;
- private readonly _onDidDrop = new Emitter();
+ private readonly _onDidDrop = new Emitter();
readonly onDidDrop = this._onDidDrop.event;
constructor(
@@ -93,7 +102,11 @@ export abstract class DraggablePaneviewPanel extends PaneviewPanel {
const data = getPaneData();
if (!data) {
- this._onDidDrop.fire(event);
+ this._onDidDrop.fire({
+ ...event,
+ panel: this,
+ getData: () => getPaneData(),
+ });
return;
}
@@ -103,20 +116,30 @@ export abstract class DraggablePaneviewPanel extends PaneviewPanel {
const existingPanel = containerApi.getPanel(id);
if (!existingPanel) {
- this._onDidDrop.fire(event);
+ this._onDidDrop.fire({
+ ...event,
+ panel: this,
+ getData: () => getPaneData(),
+ });
return;
}
- const fromIndex = containerApi
- .getPanels()
- .indexOf(existingPanel);
+ const allPanels = containerApi.getPanels();
+
+ const fromIndex = allPanels.indexOf(existingPanel);
let toIndex = containerApi.getPanels().indexOf(this);
+ if (
+ event.position === Position.Left ||
+ event.position === Position.Top
+ ) {
+ toIndex = Math.max(0, toIndex - 1);
+ }
if (
event.position === Position.Right ||
event.position === Position.Bottom
) {
- toIndex = Math.max(0, toIndex + 1);
+ toIndex = Math.min(allPanels.length - 1, toIndex + 1);
}
containerApi.movePanel(fromIndex, toIndex);
diff --git a/packages/dockview/src/paneview/paneview.scss b/packages/dockview/src/paneview/paneview.scss
index 117835fae..5145a7d94 100644
--- a/packages/dockview/src/paneview/paneview.scss
+++ b/packages/dockview/src/paneview/paneview.scss
@@ -23,6 +23,11 @@
border-top: 1px solid var(--dv-paneview-header-border-color);
}
}
+
+ .default-header {
+ background-color: var(--dv-group-view-background-color);
+ color: var(--dv-activegroup-visiblepanel-tab-color);
+ }
}
&:first-of-type > .pane > .pane-header {
diff --git a/packages/dockview/src/paneview/paneviewComponent.ts b/packages/dockview/src/paneview/paneviewComponent.ts
index 69e2a96b0..d1816503c 100644
--- a/packages/dockview/src/paneview/paneviewComponent.ts
+++ b/packages/dockview/src/paneview/paneviewComponent.ts
@@ -22,8 +22,10 @@ import {
PanePanelInitParameter,
IPaneviewPanel,
} from './paneviewPanel';
-import { DraggablePaneviewPanel } from './draggablePaneviewPanel';
-import { DroptargetEvent } from '../dnd/droptarget';
+import {
+ DraggablePaneviewPanel,
+ PaneviewDropEvent2,
+} from './draggablePaneviewPanel';
export interface SerializedPaneviewPanel {
snap?: boolean;
@@ -58,6 +60,7 @@ class DefaultHeader extends CompositeDisposable implements IPaneHeaderPart {
constructor() {
super();
this._element = document.createElement('div');
+ this._element.className = 'default-header';
this.addDisposables(
addDisposableListener(this.element, 'click', () => {
@@ -128,7 +131,7 @@ export interface IPaneviewComponent extends IDisposable {
readonly height: number;
readonly minimumSize: number;
readonly maximumSize: number;
- readonly onDidDrop: Event;
+ readonly onDidDrop: Event;
readonly onDidLayoutChange: Event;
addPanel(options: AddPaneviewCompponentOptions): IDisposable;
layout(width: number, height: number): void;
@@ -156,8 +159,8 @@ export class PaneviewComponent
private readonly _onDidLayoutChange = new Emitter();
readonly onDidLayoutChange: Event = this._onDidLayoutChange.event;
- private readonly _onDidDrop = new Emitter();
- readonly onDidDrop: Event = this._onDidDrop.event;
+ private readonly _onDidDrop = new Emitter();
+ readonly onDidDrop: Event = this._onDidDrop.event;
get onDidAddView() {
return this._paneview.onDidAddView;
diff --git a/packages/dockview/src/react/paneview/paneview.tsx b/packages/dockview/src/react/paneview/paneview.tsx
index 4e6fb48c9..d8ca2d9c6 100644
--- a/packages/dockview/src/react/paneview/paneview.tsx
+++ b/packages/dockview/src/react/paneview/paneview.tsx
@@ -9,7 +9,7 @@ import { PaneviewApi } from '../../api/component.api';
import { PanePanelSection } from './view';
import { PanelCollection, PanelParameters } from '../types';
import { watchElementResize } from '../../dom';
-import { DroptargetEvent } from '../../dnd/droptarget';
+import { PaneviewDropEvent2 } from '../../paneview/draggablePaneviewPanel';
export interface PaneviewReadyEvent {
api: PaneviewApi;
@@ -24,7 +24,7 @@ export interface IPaneviewPanelProps>
export interface PaneviewDropEvent {
api: PaneviewApi;
- event: DroptargetEvent;
+ event: PaneviewDropEvent2;
}
export interface IPaneviewReactProps {
@@ -62,18 +62,6 @@ export const PaneviewReact = React.forwardRef(
};
}, [props.disableAutoResizing]);
- React.useEffect(() => {
- paneviewRef.current?.updateOptions({
- frameworkComponents: props.components,
- });
- }, [props.components]);
-
- React.useEffect(() => {
- paneviewRef.current?.updateOptions({
- headerframeworkComponents: props.headerComponents,
- });
- }, [props.headerComponents]);
-
React.useEffect(() => {
const createComponent = (
id: string,
@@ -116,6 +104,19 @@ export const PaneviewReact = React.forwardRef(
};
}, []);
+ React.useEffect(() => {
+ console.log(paneviewRef.current);
+ paneviewRef.current?.updateOptions({
+ frameworkComponents: props.components,
+ });
+ }, [props.components]);
+
+ React.useEffect(() => {
+ paneviewRef.current?.updateOptions({
+ headerframeworkComponents: props.headerComponents,
+ });
+ }, [props.headerComponents]);
+
React.useEffect(() => {
if (!paneviewRef.current) {
return () => {
@@ -127,7 +128,10 @@ export const PaneviewReact = React.forwardRef(
const disposable = paneview.onDidDrop((event) => {
if (props.onDidDrop) {
- props.onDidDrop({ event, api: new PaneviewApi(paneview) });
+ props.onDidDrop({
+ event,
+ api: new PaneviewApi(paneview),
+ });
}
});