feat: render mode

This commit is contained in:
mathuo 2024-01-10 22:23:35 +00:00
parent e686ecb9d5
commit d0d6508ae3
No known key found for this signature in database
GPG Key ID: C6EEDEFD6CA07281
3 changed files with 64 additions and 85 deletions

View File

@ -178,58 +178,7 @@ export class ContentContainer
return; return;
} }
const renderer = panel.api.renderer; this.renderPanel(panel);
if (
this.panel &&
this.panel.view.content.element.parentElement === this._element
) {
/**
* If the currently attached panel is mounted directly to the content then remove it
*/
this._element.removeChild(this.panel.view.content.element);
}
this.panel = panel;
let container: HTMLElement;
switch (renderer) {
case 'always':
container =
this.accessor.overlayRenderContainer.setReferenceContentContainer(
panel,
this
);
break;
case 'onlyWhenVisibile':
this._element.appendChild(this.panel.view.content.element);
container = this._element;
break;
}
const _onDidFocus = this.panel.view.content.onDidFocus;
const _onDidBlur = this.panel.view.content.onDidBlur;
const disposable = new CompositeDisposable();
const focusTracker = trackFocus(container);
disposable.addDisposables(
focusTracker,
focusTracker.onDidFocus(() => this._onDidFocus.fire()),
focusTracker.onDidBlur(() => this._onDidBlur.fire())
);
if (_onDidFocus) {
disposable.addDisposables(
_onDidFocus(() => this._onDidFocus.fire())
);
}
if (_onDidBlur) {
disposable.addDisposables(_onDidBlur(() => this._onDidBlur.fire()));
}
this.disposable.value = disposable;
} }
public layout(_width: number, _height: number): void { public layout(_width: number, _height: number): void {

View File

@ -1,7 +1,12 @@
import { DragAndDropObserver } from './dnd/dnd'; import { DragAndDropObserver } from './dnd/dnd';
import { Droptarget } from './dnd/droptarget'; import { Droptarget } from './dnd/droptarget';
import { getDomNodePagePosition, toggleClass } from './dom'; import { getDomNodePagePosition, toggleClass } from './dom';
import { CompositeDisposable, Disposable, IDisposable } from './lifecycle'; import {
CompositeDisposable,
Disposable,
IDisposable,
MutableDisposable,
} from './lifecycle';
import { IDockviewPanel } from './dockview/dockviewPanel'; import { IDockviewPanel } from './dockview/dockviewPanel';
export type DockviewPanelRenderer = 'onlyWhenVisibile' | 'always'; export type DockviewPanelRenderer = 'onlyWhenVisibile' | 'always';
@ -20,7 +25,12 @@ function createFocusableElement(): HTMLDivElement {
export class OverlayRenderContainer extends CompositeDisposable { export class OverlayRenderContainer extends CompositeDisposable {
private readonly map: Record< private readonly map: Record<
string, string,
{ disposable: IDisposable; element: HTMLElement } {
panel: IDockviewPanel;
disposable: IDisposable;
destroy: IDisposable;
element: HTMLElement;
}
> = {}; > = {};
get allIds(): string[] { get allIds(): string[] {
@ -30,13 +40,14 @@ export class OverlayRenderContainer extends CompositeDisposable {
constructor(private readonly element: HTMLElement) { constructor(private readonly element: HTMLElement) {
super(); super();
this.addDisposables({ this.addDisposables(
dispose: () => { Disposable.from(() => {
for (const value of Object.values(this.map)) { for (const value of Object.values(this.map)) {
value.disposable.dispose(); value.disposable.dispose();
value.destroy.dispose();
} }
}, })
}); );
} }
remove(panel: IDockviewPanel): boolean { remove(panel: IDockviewPanel): boolean {
@ -57,12 +68,14 @@ export class OverlayRenderContainer extends CompositeDisposable {
element.className = 'dv-render-overlay'; element.className = 'dv-render-overlay';
this.map[panel.api.id] = { this.map[panel.api.id] = {
panel,
disposable: Disposable.NONE, disposable: Disposable.NONE,
destroy: Disposable.NONE,
element, element,
}; };
} }
this.map[panel.api.id]?.disposable.dispose();
const focusContainer = this.map[panel.api.id].element; const focusContainer = this.map[panel.api.id].element;
if (panel.view.content.element.parentElement !== focusContainer) { if (panel.view.content.element.parentElement !== focusContainer) {
@ -97,11 +110,17 @@ export class OverlayRenderContainer extends CompositeDisposable {
focusContainer.style.display = panel.api.isVisible ? '' : 'none'; focusContainer.style.display = panel.api.isVisible ? '' : 'none';
}; };
const whenVisible = <T>(func: (event: T) => void) => {
return (event: T) => {
if (!panel.api.isVisible) {
return;
}
func(event);
};
};
const disposable = new CompositeDisposable( const disposable = new CompositeDisposable(
/**
* since container is positioned absoutely we must explicitly forward
* the dnd events for the expect behaviours to continue to occur in terms of dnd
*/
new DragAndDropObserver(focusContainer, { new DragAndDropObserver(focusContainer, {
onDragEnd: (e) => { onDragEnd: (e) => {
referenceContainer.dropTarget.dnd.onDragEnd(e); referenceContainer.dropTarget.dnd.onDragEnd(e);
@ -119,6 +138,10 @@ export class OverlayRenderContainer extends CompositeDisposable {
referenceContainer.dropTarget.dnd.onDragOver(e); referenceContainer.dropTarget.dnd.onDragOver(e);
}, },
}), }),
/**
* since container is positioned absoutely we must explicitly forward
* the dnd events for the expect behaviours to continue to occur in terms of dnd
*/
panel.api.onDidVisibilityChange((event) => { panel.api.onDidVisibilityChange((event) => {
/** /**
* Control the visibility of the content, however even when not visible (display: none) * Control the visibility of the content, however even when not visible (display: none)
@ -133,15 +156,14 @@ export class OverlayRenderContainer extends CompositeDisposable {
} }
resize(); resize();
}), })
{
dispose: () => {
focusContainer.removeChild(panel.view.content.element);
this.element.removeChild(focusContainer);
},
}
); );
this.map[panel.api.id].destroy = Disposable.from(() => {
focusContainer.removeChild(panel.view.content.element);
this.element.removeChild(focusContainer);
});
queueMicrotask(() => { queueMicrotask(() => {
if (this.isDisposed) { if (this.isDisposed) {
return; return;
@ -155,6 +177,7 @@ export class OverlayRenderContainer extends CompositeDisposable {
visibilityChanged(); visibilityChanged();
}); });
this.map[panel.api.id].disposable.dispose();
this.map[panel.api.id].disposable = disposable; this.map[panel.api.id].disposable = disposable;
return focusContainer; return focusContainer;

View File

@ -7,21 +7,26 @@ import * as React from 'react';
import { HoistedDockviewPanel } from './hoistedDockviewPanel'; import { HoistedDockviewPanel } from './hoistedDockviewPanel';
const components = { const components = {
iframeComponent: HoistedDockviewPanel( iframeComponent: (props: IDockviewPanelProps<{ color: string }>) => {
(props: IDockviewPanelProps<{ color: string }>) => { return (
return ( <div style={{ height: '100%', overflow: 'auto' }}>
<iframe <div style={{ height: '1000px', color: 'white' }}>
style={{ {props.api.title}
pointerEvents: 'none', </div>
border: 'none', </div>
width: '100%', );
height: '100%', return (
}} <iframe
src="https://dockview.dev" style={{
/> // pointerEvents: 'none',
); // border: 'none',
} width: '100%',
), height: '100%',
}}
src="https://dockview.dev"
/>
);
},
basicComponent: () => { basicComponent: () => {
return ( return (
<div style={{ padding: '20px', color: 'white' }}> <div style={{ padding: '20px', color: 'white' }}>
@ -36,11 +41,13 @@ export const App: React.FC = (props: { theme?: string }) => {
event.api.addPanel({ event.api.addPanel({
id: 'panel_1', id: 'panel_1',
component: 'iframeComponent', component: 'iframeComponent',
renderer: 'always',
}); });
event.api.addPanel({ event.api.addPanel({
id: 'panel_2', id: 'panel_2',
component: 'iframeComponent', component: 'iframeComponent',
renderer: 'always',
}); });
event.api.addPanel({ event.api.addPanel({