mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-18 14:56:59 +08:00
refactor(editor): adjust folder structure for slash menu extension (#10588)
Close [BS-2743](https://linear.app/affine-design/issue/BS-2743/slash-menu插件化:调整文件夹结构) This PR move slash menu from `affine-root-block` to `widget-affine-slash-menu`, and make it as a `WidgetViewExtension`
This commit is contained in:
@@ -14,6 +14,7 @@ export * from './insert';
|
||||
export * from './is-abort-error';
|
||||
export * from './math';
|
||||
export * from './model';
|
||||
export * from './popper-position';
|
||||
export * from './print-to-pdf';
|
||||
export * from './reference';
|
||||
export * from './reordering';
|
||||
|
||||
139
blocksuite/affine/shared/src/utils/popper-position.ts
Normal file
139
blocksuite/affine/shared/src/utils/popper-position.ts
Normal file
@@ -0,0 +1,139 @@
|
||||
import clamp from 'lodash-es/clamp';
|
||||
|
||||
type CollisionBox = {
|
||||
/**
|
||||
* The point that the objRect is positioned to.
|
||||
*/
|
||||
positioningPoint: { x: number; y: number };
|
||||
/**
|
||||
* The boundary rect of the obj that is being positioned.
|
||||
*/
|
||||
objRect?: { height: number; width: number };
|
||||
/**
|
||||
* The boundary rect of the container that the obj is in.
|
||||
*/
|
||||
boundaryRect?: DOMRect;
|
||||
offsetX?: number;
|
||||
offsetY?: number;
|
||||
edgeGap?: number;
|
||||
};
|
||||
|
||||
function calcSafeCoordinate({
|
||||
positioningPoint,
|
||||
objRect = { width: 0, height: 0 },
|
||||
boundaryRect = document.body.getBoundingClientRect(),
|
||||
offsetX = 0,
|
||||
offsetY = 0,
|
||||
edgeGap = 20,
|
||||
}: CollisionBox) {
|
||||
const safeX = clamp(
|
||||
positioningPoint.x + offsetX,
|
||||
edgeGap,
|
||||
boundaryRect.width - objRect.width - edgeGap
|
||||
);
|
||||
const y = positioningPoint.y + offsetY;
|
||||
// Not use clamp for y coordinate to avoid the quick bar always showing after scrolling
|
||||
// const safeY = clamp(
|
||||
// positioningPoint.y + offsetY,
|
||||
// edgeGap,
|
||||
// boundaryRect.height - objRect.height - edgeGap
|
||||
// );
|
||||
return {
|
||||
x: safeX,
|
||||
y,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to compare the space available
|
||||
* at the top and bottom of an element within a container.
|
||||
*
|
||||
* Please give preference to {@link getPopperPosition}
|
||||
*/
|
||||
function compareTopAndBottomSpace(
|
||||
obj: { getBoundingClientRect: () => DOMRect },
|
||||
container = document.body,
|
||||
gap = 20
|
||||
) {
|
||||
const objRect = obj.getBoundingClientRect();
|
||||
const spaceRect = container.getBoundingClientRect();
|
||||
const topSpace = objRect.top - spaceRect.top;
|
||||
const bottomSpace = spaceRect.bottom - objRect.bottom;
|
||||
const topOrBottom: 'top' | 'bottom' =
|
||||
topSpace > bottomSpace ? 'top' : 'bottom';
|
||||
return {
|
||||
placement: topOrBottom,
|
||||
// the height is the available space.
|
||||
height: (topOrBottom === 'top' ? topSpace : bottomSpace) - gap,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the position of the popper element with flip.
|
||||
* return null if the reference rect is all zero.
|
||||
*/
|
||||
export function getPopperPosition(
|
||||
popper: {
|
||||
getBoundingClientRect: () => DOMRect;
|
||||
},
|
||||
reference: {
|
||||
getBoundingClientRect: () => DOMRect;
|
||||
},
|
||||
{ gap = 12, offsetY = 5 }: { gap?: number; offsetY?: number } = {}
|
||||
) {
|
||||
if (!popper) {
|
||||
// foolproof, someone may use element with non-null assertion
|
||||
console.warn(
|
||||
'The popper element is not exist. Popper position maybe incorrect'
|
||||
);
|
||||
}
|
||||
const { placement, height } = compareTopAndBottomSpace(
|
||||
reference,
|
||||
document.body,
|
||||
gap + offsetY
|
||||
);
|
||||
|
||||
const referenceRect = reference.getBoundingClientRect();
|
||||
if (
|
||||
referenceRect.x === 0 &&
|
||||
referenceRect.y === 0 &&
|
||||
referenceRect.width === 0 &&
|
||||
referenceRect.height === 0
|
||||
)
|
||||
return null;
|
||||
|
||||
const positioningPoint = {
|
||||
x: referenceRect.x,
|
||||
y: referenceRect.y + (placement === 'bottom' ? referenceRect.height : 0),
|
||||
};
|
||||
|
||||
// TODO maybe use the editor container as the boundary rect to avoid the format bar being covered by other elements
|
||||
const boundaryRect = document.body.getBoundingClientRect();
|
||||
// Note: the popperRect.height maybe incorrect
|
||||
// because we are calculated its correct height
|
||||
const popperRect = popper?.getBoundingClientRect();
|
||||
|
||||
const safeCoordinate = calcSafeCoordinate({
|
||||
positioningPoint,
|
||||
objRect: popperRect,
|
||||
boundaryRect,
|
||||
offsetY: placement === 'bottom' ? offsetY : -offsetY,
|
||||
});
|
||||
|
||||
return {
|
||||
placement,
|
||||
/**
|
||||
* The height is the available space height.
|
||||
*
|
||||
* Note: it's a max height, not the real height,
|
||||
* because sometimes the popper's height is smaller than the available space.
|
||||
*/
|
||||
height,
|
||||
x: `${safeCoordinate.x}px`,
|
||||
y:
|
||||
placement === 'bottom'
|
||||
? `${safeCoordinate.y}px`
|
||||
: // We need to use `calc(-100%)` since the height of popper maybe incorrect
|
||||
`calc(${safeCoordinate.y}px - 100%)`,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user