mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-19 02:56:23 +08:00
feat: grid item style
This commit is contained in:
@@ -124,7 +124,7 @@ export const GridItem: FC<ChildrenView> = function (props) {
|
||||
const GridItemContainer = styled('div')({
|
||||
transition: 'background-color 0.3s ease-in-out',
|
||||
maxWidth: 'calc(100% - 10px)',
|
||||
padding: '4px',
|
||||
padding: '1px 3px',
|
||||
flexGrow: 1,
|
||||
border: '1px solid transparent',
|
||||
borderRadius: '4px',
|
||||
|
||||
@@ -3,6 +3,8 @@ import { useState } from 'react';
|
||||
import { styled } from '@toeverything/components/ui';
|
||||
import { BlockEditor } from '@toeverything/framework/virgo';
|
||||
|
||||
const GRID_ADD_HANDLE_NAME = 'rid-add-handle';
|
||||
|
||||
type GridHandleProps = {
|
||||
editor: BlockEditor;
|
||||
onDrag?: (e: MouseEvent) => void;
|
||||
@@ -56,7 +58,7 @@ export const GridHandle: FC<GridHandleProps> = function ({
|
||||
{enabledAddItem ? (
|
||||
<AddGridHandle
|
||||
onClick={handleCreateGridItem}
|
||||
className="grid-add-handle"
|
||||
className={GRID_ADD_HANDLE_NAME}
|
||||
>
|
||||
+
|
||||
</AddGridHandle>
|
||||
@@ -70,14 +72,14 @@ const GridHandleContainer = styled('div')(({ theme }) => ({
|
||||
width: '10px',
|
||||
flexGrow: '0',
|
||||
flexShrink: '0',
|
||||
padding: '5px 4px',
|
||||
padding: '5px 4.5px',
|
||||
minHeight: '15px',
|
||||
cursor: 'col-resize',
|
||||
borderRadius: '1px',
|
||||
backgroundClip: 'content-box',
|
||||
' &:hover': {
|
||||
backgroundColor: theme.affine.palette.primary,
|
||||
'.grid-add-handle': {
|
||||
[`.${GRID_ADD_HANDLE_NAME}`]: {
|
||||
display: 'block',
|
||||
},
|
||||
},
|
||||
@@ -87,25 +89,18 @@ const AddGridHandle = styled('div')(({ theme }) => ({
|
||||
display: 'none',
|
||||
position: 'absolute',
|
||||
transition: 'all 0.2s ease-in-out',
|
||||
height: '6px',
|
||||
width: '6px',
|
||||
borderRadius: '6px',
|
||||
top: '-6px',
|
||||
left: '2px',
|
||||
cursor: 'pointer',
|
||||
backgroundColor: theme.affine.palette.menuSeparator,
|
||||
color: theme.affine.palette.menuSeparator,
|
||||
overflow: 'hidden',
|
||||
fontWeight: 'bold',
|
||||
height: '20px',
|
||||
lineHeight: '18px',
|
||||
width: '10px',
|
||||
borderRadius: '6px',
|
||||
top: 'calc(50% - 10px)',
|
||||
left: '0px',
|
||||
cursor: 'pointer',
|
||||
color: theme.affine.palette.primary,
|
||||
overflow: 'hidden',
|
||||
textAlign: 'center',
|
||||
' &:hover': {
|
||||
width: '20px',
|
||||
height: '20px',
|
||||
borderRadius: '10px',
|
||||
backgroundColor: theme.affine.palette.primary,
|
||||
color: theme.affine.palette.white,
|
||||
top: '-20px',
|
||||
left: '-5px',
|
||||
backgroundColor: theme.affine.palette.white,
|
||||
'&:hover': {
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
}));
|
||||
|
||||
@@ -177,7 +177,7 @@ export const Grid: FC<CreateView> = function (props) {
|
||||
style={{
|
||||
transition: isOnDrag
|
||||
? 'none'
|
||||
: 'width 0.2s ease-in-out',
|
||||
: 'all 0.2s ease-in-out',
|
||||
}}
|
||||
key={id}
|
||||
className={GRID_ITEM_CLASS_NAME}
|
||||
@@ -218,9 +218,11 @@ const GridContainer = styled('div')({
|
||||
position: 'relative',
|
||||
display: 'flex',
|
||||
alignItems: 'stretch',
|
||||
borderRadius: '10px',
|
||||
border: '1px solid #FFF',
|
||||
minWidth: `${GRID_ITEM_MIN_WIDTH}%`,
|
||||
[`&:hover .${GRID_ITEM_CONTENT_CLASS_NAME}`]: {
|
||||
backgroundColor: 'rgba(100, 106, 115, 0.05)',
|
||||
borderColor: '#E0E6EB',
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -16,11 +16,12 @@ interface SelectionProps {
|
||||
editor: BlockEditor;
|
||||
}
|
||||
|
||||
const RectContainer = styled('div')({
|
||||
backgroundColor: 'rgba(152, 172, 189, 0.1)',
|
||||
position: 'absolute',
|
||||
zIndex: 99,
|
||||
});
|
||||
const DIRECTION_VALUE_MAP = {
|
||||
right: -1,
|
||||
left: 1,
|
||||
down: -1,
|
||||
up: 1,
|
||||
} as const;
|
||||
|
||||
type VerticalTypes = 'up' | 'down' | null;
|
||||
type HorizontalTypes = 'left' | 'right' | null;
|
||||
@@ -106,7 +107,7 @@ export const SelectionRect = forwardRef<SelectionRef, SelectionProps>(
|
||||
const startPointRef = useRef<Point>();
|
||||
const endPointRef = useRef<Point>();
|
||||
const [rect, setRect] = useState<Rect>(Rect.fromLTRB(0, 0, 0, 0));
|
||||
const startPointAtBlock = useRef<boolean>(false);
|
||||
const startPointBlock = useRef<AsyncBlock | null>();
|
||||
const mouseType = useRef<MouseType>('up');
|
||||
|
||||
const scrollContainerRect = useRef<Rect>();
|
||||
@@ -116,9 +117,12 @@ export const SelectionRect = forwardRef<SelectionRef, SelectionProps>(
|
||||
) => {
|
||||
await selectionManager.setSelectedNodesIds([]);
|
||||
startPointRef.current = new Point(event.clientX, event.clientY);
|
||||
startPointAtBlock.current =
|
||||
(await selectionManager.rootDomReady()) &&
|
||||
(await selectionManager.isPointInBlocks(startPointRef.current));
|
||||
startPointBlock.current =
|
||||
((await selectionManager.rootDomReady()) &&
|
||||
(await selectionManager.getBlockByPoint(
|
||||
startPointRef.current
|
||||
))) ||
|
||||
null;
|
||||
mouseType.current = 'down';
|
||||
if (scrollManager.scrollContainer) {
|
||||
scrollContainerRect.current = domToRect(
|
||||
@@ -130,11 +134,35 @@ export const SelectionRect = forwardRef<SelectionRef, SelectionProps>(
|
||||
const onMouseMove = async (
|
||||
event: React.MouseEvent<HTMLDivElement, MouseEvent>
|
||||
) => {
|
||||
if (mouseType.current === 'down' && !startPointAtBlock.current) {
|
||||
event.preventDefault();
|
||||
if (mouseType.current === 'down') {
|
||||
endPointRef.current = new Point(event.clientX, event.clientY);
|
||||
if (startPointBlock.current) {
|
||||
const endpointBlock =
|
||||
await selectionManager.getBlockByPoint(
|
||||
endPointRef.current
|
||||
);
|
||||
// TODO: delete after multi-block text selection done
|
||||
// if drag out of startblock change selection type to block
|
||||
if (endpointBlock?.id === startPointBlock.current.id) {
|
||||
return;
|
||||
}
|
||||
const selection = window.getSelection();
|
||||
if (
|
||||
selection &&
|
||||
selection.rangeCount > 0 &&
|
||||
editor.blockHelper.hasBlockTextUtils(
|
||||
startPointBlock.current.id
|
||||
)
|
||||
) {
|
||||
// slate will run hooks reset selection unless mouseup,
|
||||
// remove slate selection by textUtils
|
||||
editor.blockHelper.setBlockBlur(
|
||||
startPointBlock.current.id
|
||||
);
|
||||
}
|
||||
event.preventDefault();
|
||||
}
|
||||
setShow(true);
|
||||
|
||||
if (startPointRef.current) {
|
||||
await setSelectedNodesByPoints(
|
||||
editor,
|
||||
@@ -177,7 +205,7 @@ export const SelectionRect = forwardRef<SelectionRef, SelectionProps>(
|
||||
|
||||
const onMouseUp = () => {
|
||||
mouseType.current = 'up';
|
||||
startPointAtBlock.current = false;
|
||||
startPointBlock.current = null;
|
||||
setShow(false);
|
||||
scrollManager.stopAutoScroll();
|
||||
};
|
||||
@@ -200,24 +228,14 @@ export const SelectionRect = forwardRef<SelectionRef, SelectionProps>(
|
||||
scrollManager.scrollContainer &&
|
||||
scrollContainerRect.current
|
||||
) {
|
||||
const xValue =
|
||||
direction[0] === 'right'
|
||||
? -1
|
||||
: direction[0] === 'left'
|
||||
? 1
|
||||
: 0;
|
||||
const yValue =
|
||||
direction[1] === 'down'
|
||||
? -1
|
||||
: direction[1] === 'up'
|
||||
? 1
|
||||
: 0;
|
||||
const xSign = DIRECTION_VALUE_MAP[direction[0]] || 0;
|
||||
const ySign = DIRECTION_VALUE_MAP[direction[1]] || 0;
|
||||
|
||||
startPointRef.current = new Point(
|
||||
startPointRef.current.x +
|
||||
xValue * scrollManager.scrollMoveOffset,
|
||||
xSign * scrollManager.scrollMoveOffset,
|
||||
startPointRef.current.y +
|
||||
yValue * scrollManager.scrollMoveOffset
|
||||
ySign * scrollManager.scrollMoveOffset
|
||||
);
|
||||
|
||||
setSelectedNodesByPoints(
|
||||
@@ -260,3 +278,9 @@ export const SelectionRect = forwardRef<SelectionRef, SelectionProps>(
|
||||
) : null;
|
||||
}
|
||||
);
|
||||
|
||||
const RectContainer = styled('div')({
|
||||
backgroundColor: 'rgba(62, 111, 219, 0.1)',
|
||||
position: 'absolute',
|
||||
zIndex: 99,
|
||||
});
|
||||
|
||||
@@ -57,6 +57,10 @@ export class BlockHelper {
|
||||
delete this._blockTextUtilsMap[blockId];
|
||||
}
|
||||
|
||||
public hasBlockTextUtils(blockId: string) {
|
||||
return !!this._blockTextUtilsMap[blockId];
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* get block serializer text by block id
|
||||
|
||||
@@ -292,14 +292,22 @@ export class SelectionManager implements VirgoSelection {
|
||||
const rootBlock = await this._editor.getBlockById(rootBlockId);
|
||||
return Boolean(rootBlock?.dom);
|
||||
}
|
||||
// TODO: Maybe just check root block
|
||||
public async isPointInBlocks(point: Point) {
|
||||
|
||||
public async getBlockByPoint(point: Point) {
|
||||
const blockList = await this._editor.getBlockList();
|
||||
return blockList.some(block => {
|
||||
const outBlockList = blockList.filter(block => {
|
||||
return (
|
||||
Boolean(block.dom) && domToRect(block.dom).isContainPoint(point)
|
||||
);
|
||||
});
|
||||
|
||||
return outBlockList.length
|
||||
? outBlockList[outBlockList.length - 1]
|
||||
: undefined;
|
||||
}
|
||||
|
||||
public async isPointInBlocks(point: Point) {
|
||||
return Boolean(this.getBlockByPoint(point));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -362,7 +370,6 @@ export class SelectionManager implements VirgoSelection {
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log({ selectedNodes });
|
||||
return selectedNodes;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user