mirror of
https://github.com/mathuo/dockview
synced 2025-08-15 13:46:00 +00:00
feat: floating group viewport rules
This commit is contained in:
parent
a1b2b9b1da
commit
715281b804
@ -11,6 +11,7 @@
|
||||
"/packages/docs/sandboxes/dockview-app",
|
||||
"/packages/docs/sandboxes/events-dockview",
|
||||
"/packages/docs/sandboxes/externaldnd-dockview",
|
||||
"/packages/docs/sandboxes/floatinggroup-dockview",
|
||||
"/packages/docs/sandboxes/fullwidthtab-dockview",
|
||||
"/packages/docs/sandboxes/groupcontol-dockview",
|
||||
"/packages/docs/sandboxes/iframe-dockview",
|
||||
@ -31,4 +32,4 @@
|
||||
"/packages/docs/sandboxes/javascript/vanilla-dockview"
|
||||
],
|
||||
"node": "16"
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { toHaveDescription } from '@testing-library/jest-dom/matchers';
|
||||
import {
|
||||
getElementsByTagName,
|
||||
quasiDefaultPrevented,
|
||||
@ -47,8 +48,8 @@ export class Overlay extends CompositeDisposable {
|
||||
top: number;
|
||||
container: HTMLElement;
|
||||
content: HTMLElement;
|
||||
minimumInViewportWidth: number;
|
||||
minimumInViewportHeight: number;
|
||||
minimumInViewportWidth?: number;
|
||||
minimumInViewportHeight?: number;
|
||||
}
|
||||
) {
|
||||
super();
|
||||
@ -105,16 +106,10 @@ export class Overlay extends CompositeDisposable {
|
||||
// region: ensure bounds within allowable limits
|
||||
|
||||
// a minimum width of minimumViewportWidth must be inside the viewport
|
||||
const xOffset = Math.max(
|
||||
0,
|
||||
overlayRect.width - this.options.minimumInViewportWidth
|
||||
);
|
||||
const xOffset = Math.max(0, this.getMinimumWidth(overlayRect.width));
|
||||
|
||||
// a minimum height of minimumViewportHeight must be inside the viewport
|
||||
const yOffset = Math.max(
|
||||
0,
|
||||
overlayRect.height - this.options.minimumInViewportHeight
|
||||
);
|
||||
const yOffset = Math.max(0, this.getMinimumHeight(overlayRect.height));
|
||||
|
||||
const left = clamp(
|
||||
overlayRect.left - containerRect.left,
|
||||
@ -194,12 +189,13 @@ export class Overlay extends CompositeDisposable {
|
||||
|
||||
const xOffset = Math.max(
|
||||
0,
|
||||
overlayRect.width - this.options.minimumInViewportWidth
|
||||
this.getMinimumWidth(overlayRect.width)
|
||||
);
|
||||
const yOffset = Math.max(
|
||||
0,
|
||||
overlayRect.height -
|
||||
this.options.minimumInViewportHeight
|
||||
this.options.minimumInViewportHeight
|
||||
? this.getMinimumHeight(overlayRect.height)
|
||||
: 0
|
||||
);
|
||||
|
||||
const left = clamp(
|
||||
@ -350,20 +346,16 @@ export class Overlay extends CompositeDisposable {
|
||||
let left: number | undefined = undefined;
|
||||
let width: number | undefined = undefined;
|
||||
|
||||
const minimumInViewportHeight =
|
||||
this.options.minimumInViewportHeight;
|
||||
const minimumInViewportWidth =
|
||||
this.options.minimumInViewportWidth;
|
||||
|
||||
function moveTop(): void {
|
||||
const moveTop = () => {
|
||||
top = clamp(
|
||||
y,
|
||||
-Number.MAX_VALUE,
|
||||
startPosition!.originalY +
|
||||
startPosition!.originalHeight >
|
||||
containerRect.height
|
||||
? containerRect.height -
|
||||
minimumInViewportHeight
|
||||
? this.getMinimumHeight(
|
||||
containerRect.height
|
||||
)
|
||||
: Math.max(
|
||||
0,
|
||||
startPosition!.originalY +
|
||||
@ -375,31 +367,31 @@ export class Overlay extends CompositeDisposable {
|
||||
startPosition!.originalY +
|
||||
startPosition!.originalHeight -
|
||||
top;
|
||||
}
|
||||
};
|
||||
|
||||
function moveBottom(): void {
|
||||
const moveBottom = () => {
|
||||
top =
|
||||
startPosition!.originalY -
|
||||
startPosition!.originalHeight;
|
||||
|
||||
height = clamp(
|
||||
y - top,
|
||||
top < 0
|
||||
? -top + minimumInViewportHeight
|
||||
top < 0 && this.options.minimumInViewportHeight
|
||||
? -top +
|
||||
this.options.minimumInViewportHeight
|
||||
: Overlay.MINIMUM_HEIGHT,
|
||||
Number.MAX_VALUE
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
function moveLeft(): void {
|
||||
const moveLeft = () => {
|
||||
left = clamp(
|
||||
x,
|
||||
-Number.MAX_VALUE,
|
||||
startPosition!.originalX +
|
||||
startPosition!.originalWidth >
|
||||
containerRect.width
|
||||
? containerRect.width -
|
||||
minimumInViewportWidth
|
||||
? this.getMinimumWidth(containerRect.width)
|
||||
: Math.max(
|
||||
0,
|
||||
startPosition!.originalX +
|
||||
@ -412,21 +404,22 @@ export class Overlay extends CompositeDisposable {
|
||||
startPosition!.originalX +
|
||||
startPosition!.originalWidth -
|
||||
left;
|
||||
}
|
||||
};
|
||||
|
||||
function moveRight(): void {
|
||||
const moveRight = () => {
|
||||
left =
|
||||
startPosition!.originalX -
|
||||
startPosition!.originalWidth;
|
||||
|
||||
width = clamp(
|
||||
x - left,
|
||||
left < 0
|
||||
? -left + minimumInViewportWidth
|
||||
left < 0 && this.options.minimumInViewportWidth
|
||||
? -left +
|
||||
this.options.minimumInViewportWidth
|
||||
: Overlay.MINIMUM_WIDTH,
|
||||
Number.MAX_VALUE
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
switch (direction) {
|
||||
case 'top':
|
||||
@ -477,6 +470,20 @@ export class Overlay extends CompositeDisposable {
|
||||
);
|
||||
}
|
||||
|
||||
private getMinimumWidth(width: number) {
|
||||
if (typeof this.options.minimumInViewportWidth === 'number') {
|
||||
return width - this.options.minimumInViewportWidth;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private getMinimumHeight(height: number) {
|
||||
if (typeof this.options.minimumInViewportHeight === 'number') {
|
||||
return height - this.options.minimumInViewportHeight;
|
||||
}
|
||||
return height;
|
||||
}
|
||||
|
||||
override dispose(): void {
|
||||
this._element.remove();
|
||||
super.dispose();
|
||||
|
@ -87,6 +87,7 @@ export type DockviewComponentUpdateOptions = Pick<
|
||||
| 'createLeftHeaderActionsElement'
|
||||
| 'createRightHeaderActionsElement'
|
||||
| 'disableFloatingGroups'
|
||||
| 'floatingGroupsPosition'
|
||||
>;
|
||||
|
||||
export interface DockviewDropEvent extends GroupviewDropEvent {
|
||||
@ -359,8 +360,16 @@ export class DockviewComponent
|
||||
width: coord?.width ?? 300,
|
||||
left: overlayLeft,
|
||||
top: overlayTop,
|
||||
minimumInViewportWidth: 100,
|
||||
minimumInViewportHeight: 100,
|
||||
minimumInViewportWidth:
|
||||
this.options.floatingGroupsPosition === 'boundedWithinViewport'
|
||||
? undefined
|
||||
: this.options.floatingGroupsPosition
|
||||
?.minimumWidthWithinViewport ?? 100,
|
||||
minimumInViewportHeight:
|
||||
this.options.floatingGroupsPosition === 'boundedWithinViewport'
|
||||
? undefined
|
||||
: this.options.floatingGroupsPosition
|
||||
?.minimumHeightWithinViewport ?? 100,
|
||||
});
|
||||
|
||||
const el = group.element.querySelector('.void-container');
|
||||
|
@ -87,6 +87,12 @@ export interface DockviewComponentOptions extends DockviewRenderFunctions {
|
||||
singleTabMode?: 'fullwidth' | 'default';
|
||||
parentElement?: HTMLElement;
|
||||
disableFloatingGroups?: boolean;
|
||||
floatingGroupsPosition?:
|
||||
| 'boundedWithinViewport'
|
||||
| {
|
||||
minimumHeightWithinViewport?: number;
|
||||
minimumWidthWithinViewport?: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface PanelOptions<P extends object = Parameters> {
|
||||
|
@ -69,6 +69,12 @@ export interface IDockviewReactProps {
|
||||
leftHeaderActionsComponent?: React.FunctionComponent<IDockviewHeaderActionsProps>;
|
||||
singleTabMode?: 'fullwidth' | 'default';
|
||||
disableFloatingGroups?: boolean;
|
||||
floatingGroupsPosition?:
|
||||
| 'boundedWithinViewport'
|
||||
| {
|
||||
minimumHeightWithinViewport?: number;
|
||||
minimumWidthWithinViewport?: number;
|
||||
};
|
||||
}
|
||||
|
||||
const DEFAULT_REACT_TAB = 'props.defaultTabComponent';
|
||||
@ -162,6 +168,7 @@ export const DockviewReact = React.forwardRef(
|
||||
),
|
||||
singleTabMode: props.singleTabMode,
|
||||
disableFloatingGroups: props.disableFloatingGroups,
|
||||
floatingGroupsPosition: props.floatingGroupsPosition,
|
||||
});
|
||||
|
||||
const { clientWidth, clientHeight } = domRef.current;
|
||||
@ -205,6 +212,15 @@ export const DockviewReact = React.forwardRef(
|
||||
});
|
||||
}, [props.components]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!dockviewRef.current) {
|
||||
return;
|
||||
}
|
||||
dockviewRef.current.updateOptions({
|
||||
floatingGroupsPosition: props.floatingGroupsPosition,
|
||||
});
|
||||
}, [props.floatingGroupsPosition]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!dockviewRef.current) {
|
||||
return;
|
||||
|
Loading…
x
Reference in New Issue
Block a user