mirror of
https://github.com/mathuo/dockview
synced 2025-01-23 01:45:58 +00:00
Merge pull request #431 from mathuo/430-support-droptarget-size-options
feat: expose dockview root droptarget overlay options (work-in-progress)
This commit is contained in:
commit
6c670c1fbb
@ -5,10 +5,6 @@ import { DragAndDropObserver } from './dnd';
|
||||
import { clamp } from '../math';
|
||||
import { Direction } from '../gridview/baseComponentGridview';
|
||||
|
||||
function numberOrFallback(maybeNumber: any, fallback: number): number {
|
||||
return typeof maybeNumber === 'number' ? maybeNumber : fallback;
|
||||
}
|
||||
|
||||
export function directionToPosition(direction: Direction): Position {
|
||||
switch (direction) {
|
||||
case 'above':
|
||||
@ -54,6 +50,26 @@ export type CanDisplayOverlay =
|
||||
| boolean
|
||||
| ((dragEvent: DragEvent, state: Position) => boolean);
|
||||
|
||||
export type MeasuredValue = { value: number; type: 'pixels' | 'percentage' };
|
||||
|
||||
export type DroptargetOverlayModel = {
|
||||
size?: MeasuredValue;
|
||||
activationSize?: MeasuredValue;
|
||||
};
|
||||
|
||||
const DEFAULT_ACTIVATION_SIZE: MeasuredValue = {
|
||||
value: 20,
|
||||
type: 'percentage',
|
||||
};
|
||||
|
||||
const DEFAULT_SIZE: MeasuredValue = {
|
||||
value: 50,
|
||||
type: 'percentage',
|
||||
};
|
||||
|
||||
const SMALL_WIDTH_BOUNDARY = 100;
|
||||
const SMALL_HEIGHT_BOUNDARY = 100;
|
||||
|
||||
export class Droptarget extends CompositeDisposable {
|
||||
private targetElement: HTMLElement | undefined;
|
||||
private overlayElement: HTMLElement | undefined;
|
||||
@ -76,13 +92,7 @@ export class Droptarget extends CompositeDisposable {
|
||||
private readonly options: {
|
||||
canDisplayOverlay: CanDisplayOverlay;
|
||||
acceptedTargetZones: Position[];
|
||||
overlayModel?: {
|
||||
size?: { value: number; type: 'pixels' | 'percentage' };
|
||||
activationSize?: {
|
||||
value: number;
|
||||
type: 'pixels' | 'percentage';
|
||||
};
|
||||
};
|
||||
overlayModel?: DroptargetOverlayModel;
|
||||
}
|
||||
) {
|
||||
super();
|
||||
@ -158,7 +168,7 @@ export class Droptarget extends CompositeDisposable {
|
||||
|
||||
this.toggleClasses(quadrant, width, height);
|
||||
|
||||
this.setState(quadrant);
|
||||
this._state = quadrant;
|
||||
},
|
||||
onDragLeave: () => {
|
||||
this.removeDropTarget();
|
||||
@ -189,6 +199,10 @@ export class Droptarget extends CompositeDisposable {
|
||||
this._acceptedTargetZonesSet = new Set(acceptedTargetZones);
|
||||
}
|
||||
|
||||
setOverlayModel(model: DroptargetOverlayModel): void {
|
||||
this.options.overlayModel = model;
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.removeDropTarget();
|
||||
super.dispose();
|
||||
@ -202,7 +216,7 @@ export class Droptarget extends CompositeDisposable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Check is the event has already been used by another instance od DropTarget
|
||||
* Check is the event has already been used by another instance of DropTarget
|
||||
*/
|
||||
private isAlreadyUsed(event: DragEvent): boolean {
|
||||
const value = (event as any)[Droptarget.USED_EVENT_ID];
|
||||
@ -218,8 +232,8 @@ export class Droptarget extends CompositeDisposable {
|
||||
return;
|
||||
}
|
||||
|
||||
const isSmallX = width < 100;
|
||||
const isSmallY = height < 100;
|
||||
const isSmallX = width < SMALL_WIDTH_BOUNDARY;
|
||||
const isSmallY = height < SMALL_HEIGHT_BOUNDARY;
|
||||
|
||||
const isLeft = quadrant === 'left';
|
||||
const isRight = quadrant === 'right';
|
||||
@ -231,22 +245,18 @@ export class Droptarget extends CompositeDisposable {
|
||||
const topClass = !isSmallY && isTop;
|
||||
const bottomClass = !isSmallY && isBottom;
|
||||
|
||||
let size = 0.5;
|
||||
let size = 1;
|
||||
|
||||
if (this.options.overlayModel?.size?.type === 'percentage') {
|
||||
size = clamp(this.options.overlayModel.size.value, 0, 100) / 100;
|
||||
}
|
||||
const sizeOptions = this.options.overlayModel?.size ?? DEFAULT_SIZE;
|
||||
|
||||
if (this.options.overlayModel?.size?.type === 'pixels') {
|
||||
if (sizeOptions.type === 'percentage') {
|
||||
size = clamp(sizeOptions.value, 0, 100) / 100;
|
||||
} else {
|
||||
if (rightClass || leftClass) {
|
||||
size =
|
||||
clamp(0, this.options.overlayModel.size.value, width) /
|
||||
width;
|
||||
size = clamp(0, sizeOptions.value, width) / width;
|
||||
}
|
||||
if (topClass || bottomClass) {
|
||||
size =
|
||||
clamp(0, this.options.overlayModel.size.value, height) /
|
||||
height;
|
||||
size = clamp(0, sizeOptions.value, height) / height;
|
||||
}
|
||||
}
|
||||
|
||||
@ -281,26 +291,6 @@ export class Droptarget extends CompositeDisposable {
|
||||
toggleClass(this.overlayElement, 'dv-overlay-bottom', isBottom);
|
||||
}
|
||||
|
||||
private setState(quadrant: Position): void {
|
||||
switch (quadrant) {
|
||||
case 'top':
|
||||
this._state = 'top';
|
||||
break;
|
||||
case 'left':
|
||||
this._state = 'left';
|
||||
break;
|
||||
case 'bottom':
|
||||
this._state = 'bottom';
|
||||
break;
|
||||
case 'right':
|
||||
this._state = 'right';
|
||||
break;
|
||||
case 'center':
|
||||
this._state = 'center';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private calculateQuadrant(
|
||||
overlayType: Set<Position>,
|
||||
x: number,
|
||||
@ -308,14 +298,11 @@ export class Droptarget extends CompositeDisposable {
|
||||
width: number,
|
||||
height: number
|
||||
): Position | null {
|
||||
const isPercentage =
|
||||
this.options.overlayModel?.activationSize === undefined ||
|
||||
this.options.overlayModel?.activationSize?.type === 'percentage';
|
||||
const activationSizeOptions =
|
||||
this.options.overlayModel?.activationSize ??
|
||||
DEFAULT_ACTIVATION_SIZE;
|
||||
|
||||
const value = numberOrFallback(
|
||||
this.options?.overlayModel?.activationSize?.value,
|
||||
20
|
||||
);
|
||||
const isPercentage = activationSizeOptions.type === 'percentage';
|
||||
|
||||
if (isPercentage) {
|
||||
return calculateQuadrantAsPercentage(
|
||||
@ -324,7 +311,7 @@ export class Droptarget extends CompositeDisposable {
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
value
|
||||
activationSizeOptions.value
|
||||
);
|
||||
}
|
||||
|
||||
@ -334,7 +321,7 @@ export class Droptarget extends CompositeDisposable {
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
value
|
||||
activationSizeOptions.value
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,12 @@ import {
|
||||
getGridLocation,
|
||||
ISerializedLeafNode,
|
||||
} from '../gridview/gridview';
|
||||
import { directionToPosition, Droptarget, Position } from '../dnd/droptarget';
|
||||
import {
|
||||
directionToPosition,
|
||||
Droptarget,
|
||||
DroptargetOverlayModel,
|
||||
Position,
|
||||
} from '../dnd/droptarget';
|
||||
import { tail, sequenceEquals, remove } from '../array';
|
||||
import { DockviewPanel, IDockviewPanel } from './dockviewPanel';
|
||||
import { CompositeDisposable, Disposable } from '../lifecycle';
|
||||
@ -63,6 +68,11 @@ import {
|
||||
OverlayRenderContainer,
|
||||
} from '../overlayRenderContainer';
|
||||
|
||||
const DEFAULT_ROOT_OVERLAY_MODEL: DroptargetOverlayModel = {
|
||||
activationSize: { type: 'pixels', value: 10 },
|
||||
size: { type: 'pixels', value: 20 },
|
||||
};
|
||||
|
||||
function getTheme(element: HTMLElement): string | undefined {
|
||||
function toClassList(element: HTMLElement) {
|
||||
const list: string[] = [];
|
||||
@ -219,6 +229,7 @@ export type DockviewComponentUpdateOptions = Pick<
|
||||
| 'createPrefixHeaderActionsElement'
|
||||
| 'disableFloatingGroups'
|
||||
| 'floatingGroupBounds'
|
||||
| 'rootOverlayModel'
|
||||
>;
|
||||
|
||||
export interface DockviewDropEvent extends GroupviewDropEvent {
|
||||
@ -319,6 +330,7 @@ export class DockviewComponent
|
||||
|
||||
private readonly _floatingGroups: DockviewFloatingGroupPanel[] = [];
|
||||
private readonly _popoutGroups: DockviewPopoutGroupPanel[] = [];
|
||||
private readonly _rootDropTarget: Droptarget;
|
||||
|
||||
get orientation(): Orientation {
|
||||
return this.gridview.orientation;
|
||||
@ -424,7 +436,7 @@ export class DockviewComponent
|
||||
this.options.watermarkComponent = Watermark;
|
||||
}
|
||||
|
||||
const dropTarget = new Droptarget(this.element, {
|
||||
this._rootDropTarget = new Droptarget(this.element, {
|
||||
canDisplayOverlay: (event, position) => {
|
||||
const data = getPanelData();
|
||||
|
||||
@ -463,14 +475,12 @@ export class DockviewComponent
|
||||
return false;
|
||||
},
|
||||
acceptedTargetZones: ['top', 'bottom', 'left', 'right', 'center'],
|
||||
overlayModel: {
|
||||
activationSize: { type: 'pixels', value: 10 },
|
||||
size: { type: 'pixels', value: 20 },
|
||||
},
|
||||
overlayModel:
|
||||
this.options.rootOverlayModel ?? DEFAULT_ROOT_OVERLAY_MODEL,
|
||||
});
|
||||
|
||||
this.addDisposables(
|
||||
dropTarget.onDrop((event) => {
|
||||
this._rootDropTarget.onDrop((event) => {
|
||||
const data = getPanelData();
|
||||
|
||||
if (data) {
|
||||
@ -489,7 +499,7 @@ export class DockviewComponent
|
||||
});
|
||||
}
|
||||
}),
|
||||
dropTarget
|
||||
this._rootDropTarget
|
||||
);
|
||||
|
||||
this._api = new DockviewApi(this);
|
||||
@ -720,20 +730,24 @@ export class DockviewComponent
|
||||
}
|
||||
|
||||
updateOptions(options: DockviewComponentUpdateOptions): void {
|
||||
const hasOrientationChanged =
|
||||
const changed_orientation =
|
||||
typeof options.orientation === 'string' &&
|
||||
this.gridview.orientation !== options.orientation;
|
||||
const hasFloatingGroupOptionsChanged =
|
||||
const changed_floatingGroupBounds =
|
||||
options.floatingGroupBounds !== undefined &&
|
||||
options.floatingGroupBounds !== this.options.floatingGroupBounds;
|
||||
|
||||
const changed_rootOverlayOptions =
|
||||
options.rootOverlayModel !== undefined &&
|
||||
options.rootOverlayModel !== this.options.rootOverlayModel;
|
||||
|
||||
this._options = { ...this.options, ...options };
|
||||
|
||||
if (hasOrientationChanged) {
|
||||
if (changed_orientation) {
|
||||
this.gridview.orientation = options.orientation!;
|
||||
}
|
||||
|
||||
if (hasFloatingGroupOptionsChanged) {
|
||||
if (changed_floatingGroupBounds) {
|
||||
for (const group of this._floatingGroups) {
|
||||
switch (this.options.floatingGroupBounds) {
|
||||
case 'boundedWithinViewport':
|
||||
@ -757,6 +771,10 @@ export class DockviewComponent
|
||||
}
|
||||
}
|
||||
|
||||
if (changed_rootOverlayOptions) {
|
||||
this._rootDropTarget.setOverlayModel(options.rootOverlayModel!);
|
||||
}
|
||||
|
||||
this.layout(this.gridview.width, this.gridview.height, true);
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,7 @@ import { DockviewGroupPanel } from './dockviewGroupPanel';
|
||||
import { ISplitviewStyles, Orientation } from '../splitview/splitview';
|
||||
import { PanelTransfer } from '../dnd/dataTransfer';
|
||||
import { IDisposable } from '../lifecycle';
|
||||
import { Position } from '../dnd/droptarget';
|
||||
import { DroptargetOverlayModel, Position } from '../dnd/droptarget';
|
||||
import { IDockviewPanel } from './dockviewPanel';
|
||||
import {
|
||||
ComponentConstructor,
|
||||
@ -100,6 +100,7 @@ export interface DockviewComponentOptions extends DockviewRenderFunctions {
|
||||
popoutUrl?: string;
|
||||
defaultRenderer?: DockviewPanelRenderer;
|
||||
debug?: boolean;
|
||||
rootOverlayModel?: DroptargetOverlayModel;
|
||||
}
|
||||
|
||||
export interface PanelOptions<P extends object = Parameters> {
|
||||
|
@ -55,6 +55,8 @@ export {
|
||||
Position,
|
||||
positionToDirection,
|
||||
directionToPosition,
|
||||
MeasuredValue,
|
||||
DroptargetOverlayModel,
|
||||
} from './dnd/droptarget';
|
||||
export {
|
||||
FocusEvent,
|
||||
|
@ -11,6 +11,7 @@ import {
|
||||
DockviewGroupPanel,
|
||||
IHeaderActionsRenderer,
|
||||
DockviewPanelRenderer,
|
||||
DroptargetOverlayModel,
|
||||
} from 'dockview-core';
|
||||
import { ReactPanelContentPart } from './reactContentPart';
|
||||
import { ReactPanelHeaderPart } from './reactHeaderPart';
|
||||
@ -79,6 +80,7 @@ export interface IDockviewReactProps {
|
||||
};
|
||||
debug?: boolean;
|
||||
defaultRenderer?: DockviewPanelRenderer;
|
||||
rootOverlayModel?: DroptargetOverlayModel;
|
||||
}
|
||||
|
||||
const DEFAULT_REACT_TAB = 'props.defaultTabComponent';
|
||||
@ -180,6 +182,7 @@ export const DockviewReact = React.forwardRef(
|
||||
floatingGroupBounds: props.floatingGroupBounds,
|
||||
defaultRenderer: props.defaultRenderer,
|
||||
debug: props.debug,
|
||||
rootOverlayModel: props.rootOverlayModel,
|
||||
});
|
||||
|
||||
const { clientWidth, clientHeight } = domRef.current;
|
||||
@ -312,6 +315,15 @@ export const DockviewReact = React.forwardRef(
|
||||
});
|
||||
}, [props.leftHeaderActionsComponent]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!dockviewRef.current) {
|
||||
return;
|
||||
}
|
||||
dockviewRef.current.updateOptions({
|
||||
rootOverlayModel: props.rootOverlayModel,
|
||||
});
|
||||
}, [props.rootOverlayModel]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!dockviewRef.current) {
|
||||
return;
|
||||
|
Loading…
Reference in New Issue
Block a user