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:
L-Sun
2025-03-06 16:12:06 +00:00
parent 289d3cd20e
commit 62d8c0c7cb
73 changed files with 397 additions and 230 deletions

View File

@@ -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';

View 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%)`,
};
}