mirror of
https://github.com/mathuo/dockview
synced 2025-03-09 23:42:05 +00:00
feat: gready rendering
This commit is contained in:
parent
6a620d4088
commit
9b1c366ce5
@ -0,0 +1,8 @@
|
||||
import { OverlayRenderContainer } from '../overlayRenderContainer';
|
||||
|
||||
describe('overlayRenderContainer', () => {
|
||||
test('abc', () => {
|
||||
const el = document.createElement('div');
|
||||
const cut = new OverlayRenderContainer(el);
|
||||
});
|
||||
});
|
@ -5,7 +5,7 @@ import { MutableDisposable } from '../lifecycle';
|
||||
import { DockviewPanel, IDockviewPanel } from '../dockview/dockviewPanel';
|
||||
import { DockviewComponent } from '../dockview/dockviewComponent';
|
||||
import { Position } from '../dnd/droptarget';
|
||||
import { DockviewPanelRenderer } from '../dockview/components/greadyRenderContainer';
|
||||
import { DockviewPanelRenderer } from '../overlayRenderContainer';
|
||||
|
||||
export interface TitleEvent {
|
||||
readonly title: string;
|
||||
|
@ -58,12 +58,6 @@ export class ContentContainer
|
||||
|
||||
this.addDisposables(this._onDidFocus, this._onDidBlur);
|
||||
|
||||
// for hosted containers
|
||||
// 1) register a drop target on the host
|
||||
// 2) register window dragStart events to disable pointer events
|
||||
// 3) register dragEnd events
|
||||
// 4) register mouseMove events (if no buttons are present we take this as a dragEnd event)
|
||||
|
||||
this.dropTarget = new Droptarget(this.element, {
|
||||
acceptedTargetZones: ['top', 'bottom', 'left', 'right', 'center'],
|
||||
canDisplayOverlay: (event, position) => {
|
||||
@ -125,7 +119,7 @@ export class ContentContainer
|
||||
|
||||
switch (panel.api.renderer) {
|
||||
case 'onlyWhenVisibile':
|
||||
this.accessor.greadyRenderContainer.remove(panel);
|
||||
this.accessor.overlayRenderContainer.remove(panel);
|
||||
if (isActive) {
|
||||
if (this.panel) {
|
||||
this._element.appendChild(
|
||||
@ -142,7 +136,7 @@ export class ContentContainer
|
||||
this._element.removeChild(panel.view.content.element);
|
||||
}
|
||||
container =
|
||||
this.accessor.greadyRenderContainer.setReferenceContentContainer(
|
||||
this.accessor.overlayRenderContainer.setReferenceContentContainer(
|
||||
panel,
|
||||
this
|
||||
);
|
||||
@ -201,7 +195,7 @@ export class ContentContainer
|
||||
switch (renderer) {
|
||||
case 'always':
|
||||
container =
|
||||
this.accessor.greadyRenderContainer.setReferenceContentContainer(
|
||||
this.accessor.overlayRenderContainer.setReferenceContentContainer(
|
||||
panel,
|
||||
this
|
||||
);
|
||||
|
@ -11,7 +11,7 @@
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.dv-gready-render-container {
|
||||
.dv-overlay-render-container {
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
@ -56,9 +56,18 @@ import {
|
||||
TabDragEvent,
|
||||
} from './components/titlebar/tabsContainer';
|
||||
import {
|
||||
GreadyRenderContainer,
|
||||
OverlayRenderContainer,
|
||||
DockviewPanelRenderer,
|
||||
<<<<<<< Updated upstream
|
||||
} from './components/greadyRenderContainer';
|
||||
=======
|
||||
} from '../overlayRenderContainer';
|
||||
import { DockviewPopoutGroupPanel } from './dockviewPopoutGroupPanel';
|
||||
import {
|
||||
DEFAULT_FLOATING_GROUP_OVERFLOW_SIZE,
|
||||
DEFAULT_FLOATING_GROUP_POSITION,
|
||||
} from '../constants';
|
||||
>>>>>>> Stashed changes
|
||||
|
||||
const DEFAULT_FLOATING_GROUP_OVERFLOW_SIZE = 100;
|
||||
|
||||
@ -249,7 +258,7 @@ export class DockviewComponent
|
||||
private _options: Exclude<DockviewComponentOptions, 'orientation'>;
|
||||
private watermark: IWatermarkRenderer | null = null;
|
||||
|
||||
readonly greadyRenderContainer: GreadyRenderContainer;
|
||||
readonly overlayRenderContainer: OverlayRenderContainer;
|
||||
|
||||
private readonly _onWillDragPanel = new Emitter<TabDragEvent>();
|
||||
readonly onWillDragPanel: Event<TabDragEvent> = this._onWillDragPanel.event;
|
||||
@ -319,16 +328,16 @@ export class DockviewComponent
|
||||
});
|
||||
|
||||
const gready = document.createElement('div');
|
||||
gready.className = 'dv-gready-render-container';
|
||||
gready.className = 'dv-overlay-render-container';
|
||||
this.gridview.element.appendChild(gready);
|
||||
|
||||
this.greadyRenderContainer = new GreadyRenderContainer(gready);
|
||||
this.overlayRenderContainer = new OverlayRenderContainer(gready);
|
||||
|
||||
toggleClass(this.gridview.element, 'dv-dockview', true);
|
||||
toggleClass(this.element, 'dv-debug', !!options.debug);
|
||||
|
||||
this.addDisposables(
|
||||
this.greadyRenderContainer,
|
||||
this.overlayRenderContainer,
|
||||
this._onWillDragPanel,
|
||||
this._onWillDragGroup,
|
||||
this._onDidActivePanelChange,
|
||||
@ -1059,7 +1068,7 @@ export class DockviewComponent
|
||||
group.model.removePanel(panel);
|
||||
|
||||
if (!options.skipDispose) {
|
||||
this.greadyRenderContainer.remove(panel);
|
||||
this.overlayRenderContainer.remove(panel);
|
||||
panel.dispose();
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@ import { CompositeDisposable, IDisposable } from '../lifecycle';
|
||||
import { IPanel, PanelUpdateEvent, Parameters } from '../panel/types';
|
||||
import { IDockviewPanelModel } from './dockviewPanelModel';
|
||||
import { DockviewComponent } from './dockviewComponent';
|
||||
import { DockviewPanelRenderer } from './components/greadyRenderContainer';
|
||||
import { DockviewPanelRenderer } from '../overlayRenderContainer';
|
||||
|
||||
export interface IDockviewPanel extends IDisposable, IPanel {
|
||||
readonly view: IDockviewPanelModel;
|
||||
|
@ -20,7 +20,7 @@ import {
|
||||
FrameworkFactory,
|
||||
} from '../panel/componentFactory';
|
||||
import { DockviewGroupPanelApi } from '../api/dockviewGroupPanelApi';
|
||||
import { DockviewPanelRenderer } from './components/greadyRenderContainer';
|
||||
import { DockviewPanelRenderer } from '../overlayRenderContainer';
|
||||
|
||||
export interface IHeaderActionsRenderer extends IDisposable {
|
||||
readonly element: HTMLElement;
|
||||
|
@ -5,7 +5,7 @@ import { DockviewApi } from '../api/component.api';
|
||||
import { Event } from '../events';
|
||||
import { Optional } from '../types';
|
||||
import { DockviewGroupPanel, IDockviewGroupPanel } from './dockviewGroupPanel';
|
||||
import { DockviewPanelRenderer } from './components/greadyRenderContainer';
|
||||
import { DockviewPanelRenderer } from '../overlayRenderContainer';
|
||||
|
||||
export enum DockviewDropTargets {
|
||||
Tab,
|
||||
|
@ -49,7 +49,7 @@ export * from './splitview/splitviewPanel';
|
||||
export * from './paneview/paneviewPanel';
|
||||
export * from './dockview/types';
|
||||
|
||||
export { DockviewPanelRenderer } from './dockview/components/greadyRenderContainer';
|
||||
export { DockviewPanelRenderer } from './overlayRenderContainer';
|
||||
|
||||
export {
|
||||
Position,
|
||||
|
150
packages/dockview-core/src/overlayRenderContainer.ts
Normal file
150
packages/dockview-core/src/overlayRenderContainer.ts
Normal file
@ -0,0 +1,150 @@
|
||||
import { DragAndDropObserver } from './dnd/dnd';
|
||||
import { Droptarget } from './dnd/droptarget';
|
||||
import { getDomNodePagePosition, toggleClass } from './dom';
|
||||
import { CompositeDisposable, Disposable, IDisposable } from './lifecycle';
|
||||
import { IDockviewPanel } from './dockview/dockviewPanel';
|
||||
|
||||
export type DockviewPanelRenderer = 'onlyWhenVisibile' | 'always';
|
||||
|
||||
export interface IRenderable {
|
||||
readonly element: HTMLElement;
|
||||
readonly dropTarget: Droptarget;
|
||||
}
|
||||
|
||||
function createFocusableElement(): HTMLDivElement {
|
||||
const element = document.createElement('div');
|
||||
element.tabIndex = -1;
|
||||
return element;
|
||||
}
|
||||
|
||||
export class OverlayRenderContainer extends CompositeDisposable {
|
||||
private readonly map: Record<
|
||||
string,
|
||||
{ disposable: IDisposable; element: HTMLElement }
|
||||
> = {};
|
||||
|
||||
get allIds(): string[] {
|
||||
return Object.keys(this.map);
|
||||
}
|
||||
|
||||
constructor(private readonly element: HTMLElement) {
|
||||
super();
|
||||
|
||||
this.addDisposables({
|
||||
dispose: () => {
|
||||
for (const value of Object.values(this.map)) {
|
||||
value.disposable.dispose();
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
remove(panel: IDockviewPanel): boolean {
|
||||
if (this.map[panel.api.id]) {
|
||||
this.map[panel.api.id].disposable.dispose();
|
||||
delete this.map[panel.api.id];
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
setReferenceContentContainer(
|
||||
panel: IDockviewPanel,
|
||||
referenceContainer: IRenderable
|
||||
): HTMLElement {
|
||||
if (!this.map[panel.api.id]) {
|
||||
const element = createFocusableElement();
|
||||
element.className = 'dv-render-overlay';
|
||||
|
||||
this.map[panel.api.id] = {
|
||||
disposable: Disposable.NONE,
|
||||
element,
|
||||
};
|
||||
}
|
||||
|
||||
this.map[panel.api.id]?.disposable.dispose();
|
||||
const focusContainer = this.map[panel.api.id].element;
|
||||
|
||||
if (panel.view.content.element.parentElement !== focusContainer) {
|
||||
focusContainer.appendChild(panel.view.content.element);
|
||||
}
|
||||
|
||||
if (focusContainer.parentElement !== this.element) {
|
||||
this.element.appendChild(focusContainer);
|
||||
}
|
||||
|
||||
const resize = () => {
|
||||
// TODO propagate position to avoid getDomNodePagePosition calls, possible performance bottleneck?
|
||||
const box = getDomNodePagePosition(referenceContainer.element);
|
||||
const box2 = getDomNodePagePosition(this.element);
|
||||
focusContainer.style.left = `${box.left - box2.left}px`;
|
||||
focusContainer.style.top = `${box.top - box2.top}px`;
|
||||
focusContainer.style.width = `${box.width}px`;
|
||||
focusContainer.style.height = `${box.height}px`;
|
||||
|
||||
toggleClass(
|
||||
focusContainer,
|
||||
'dv-render-overlay-float',
|
||||
panel.group.api.location === 'floating'
|
||||
);
|
||||
};
|
||||
|
||||
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, {
|
||||
onDragEnd: (e) => {
|
||||
referenceContainer.dropTarget.dnd.onDragEnd(e);
|
||||
},
|
||||
onDragEnter: (e) => {
|
||||
referenceContainer.dropTarget.dnd.onDragEnter(e);
|
||||
},
|
||||
onDragLeave: (e) => {
|
||||
referenceContainer.dropTarget.dnd.onDragLeave(e);
|
||||
},
|
||||
onDrop: (e) => {
|
||||
referenceContainer.dropTarget.dnd.onDrop(e);
|
||||
},
|
||||
onDragOver: (e) => {
|
||||
referenceContainer.dropTarget.dnd.onDragOver(e);
|
||||
},
|
||||
}),
|
||||
panel.api.onDidVisibilityChange((event) => {
|
||||
/**
|
||||
* Control the visibility of the content, however even when not visible (display: none)
|
||||
* the content is still maintained within the DOM hence DOM specific attributes
|
||||
* such as scroll position are maintained when next made visible.
|
||||
*/
|
||||
focusContainer.style.display = event.isVisible ? '' : 'none';
|
||||
}),
|
||||
panel.api.onDidDimensionsChange(() => {
|
||||
resize();
|
||||
}),
|
||||
{
|
||||
dispose: () => {
|
||||
focusContainer.removeChild(panel.view.content.element);
|
||||
this.element.removeChild(focusContainer);
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
queueMicrotask(() => {
|
||||
if (this.isDisposed) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* wait until everything has finished in the current stack-frame call before
|
||||
* calling the first resize as other size-altering events may still occur before
|
||||
* the end of the stack-frame.
|
||||
*/
|
||||
resize();
|
||||
});
|
||||
|
||||
this.map[panel.api.id].disposable = disposable;
|
||||
|
||||
return focusContainer;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user