mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-15 05:37:32 +00:00
Merge branch 'develop' into feature/fix-backspace
This commit is contained in:
@@ -102,6 +102,12 @@ export const RenderRoot: FC<PropsWithChildren<RenderRootProps>> = ({
|
||||
editor.getHooks().onRootNodeMouseLeave(event);
|
||||
};
|
||||
|
||||
const onContextmenu = (
|
||||
event: React.MouseEvent<HTMLDivElement, MouseEvent>
|
||||
) => {
|
||||
selectionRef.current?.onContextmenu(event);
|
||||
};
|
||||
|
||||
const onKeyDown: React.KeyboardEventHandler<HTMLDivElement> = event => {
|
||||
// IMP move into keyboard managers?
|
||||
editor.getHooks().onRootNodeKeyDown(event);
|
||||
@@ -165,6 +171,7 @@ export const RenderRoot: FC<PropsWithChildren<RenderRootProps>> = ({
|
||||
onMouseUp={onMouseUp}
|
||||
onMouseLeave={onMouseLeave}
|
||||
onMouseOut={onMouseOut}
|
||||
onContextMenu={onContextmenu}
|
||||
onKeyDown={onKeyDown}
|
||||
onKeyDownCapture={onKeyDownCapture}
|
||||
onKeyUp={onKeyUp}
|
||||
|
||||
@@ -29,6 +29,9 @@ export type SelectionRef = {
|
||||
onMouseDown: (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => void;
|
||||
onMouseMove: (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => void;
|
||||
onMouseUp: (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => void;
|
||||
onContextmenu: (
|
||||
event: React.MouseEvent<HTMLDivElement, MouseEvent>
|
||||
) => void;
|
||||
};
|
||||
|
||||
const getFixedPoint = (
|
||||
@@ -207,10 +210,17 @@ export const SelectionRect = forwardRef<SelectionRef, SelectionProps>(
|
||||
scrollManager.stopAutoScroll();
|
||||
};
|
||||
|
||||
const onContextmenu = () => {
|
||||
if (mouseType.current === 'down') {
|
||||
onMouseUp();
|
||||
}
|
||||
};
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
onMouseDown,
|
||||
onMouseMove,
|
||||
onMouseUp,
|
||||
onContextmenu,
|
||||
}));
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -3,6 +3,8 @@ import { styled } from '@toeverything/components/ui';
|
||||
import type { AsyncBlock } from '../editor';
|
||||
import { PendantPopover } from './pendant-popover';
|
||||
import { PendantRender } from './pendant-render';
|
||||
import { useRef } from 'react';
|
||||
import { getRecastItemValue, useRecastBlockMeta } from '../recast-block';
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
@@ -14,13 +16,27 @@ export const BlockPendantProvider: FC<PropsWithChildren<BlockTagProps>> = ({
|
||||
block,
|
||||
children,
|
||||
}) => {
|
||||
const triggerRef = useRef<HTMLDivElement>();
|
||||
const { getProperties } = useRecastBlockMeta();
|
||||
const properties = getProperties();
|
||||
const { getValue } = getRecastItemValue(block);
|
||||
const showTriggerLine =
|
||||
properties.filter(property => getValue(property.id)).length === 0;
|
||||
|
||||
return (
|
||||
<Container>
|
||||
{children}
|
||||
|
||||
<PendantPopover block={block}>
|
||||
<StyledTriggerLine />
|
||||
</PendantPopover>
|
||||
{showTriggerLine ? (
|
||||
<StyledPendantContainer ref={triggerRef}>
|
||||
<PendantPopover
|
||||
block={block}
|
||||
container={triggerRef.current}
|
||||
>
|
||||
<StyledTriggerLine />
|
||||
</PendantPopover>
|
||||
</StyledPendantContainer>
|
||||
) : null}
|
||||
|
||||
<PendantRender block={block} />
|
||||
</Container>
|
||||
@@ -28,7 +44,7 @@ export const BlockPendantProvider: FC<PropsWithChildren<BlockTagProps>> = ({
|
||||
};
|
||||
|
||||
export const LINE_GAP = 16;
|
||||
const TAG_GAP = 4;
|
||||
export const TAG_GAP = 4;
|
||||
|
||||
const StyledTriggerLine = styled('div')({
|
||||
padding: `${TAG_GAP}px 0`,
|
||||
@@ -43,10 +59,12 @@ const StyledTriggerLine = styled('div')({
|
||||
width: '100%',
|
||||
height: '2px',
|
||||
background: '#dadada',
|
||||
display: 'none',
|
||||
display: 'flex',
|
||||
position: 'absolute',
|
||||
left: '0',
|
||||
top: '4px',
|
||||
transition: 'opacity .2s',
|
||||
opacity: '0',
|
||||
},
|
||||
'::after': {
|
||||
content: "''",
|
||||
@@ -60,18 +78,24 @@ const StyledTriggerLine = styled('div')({
|
||||
transition: 'width .3s',
|
||||
},
|
||||
});
|
||||
|
||||
const Container = styled('div')({
|
||||
position: 'relative',
|
||||
paddingBottom: `${LINE_GAP - TAG_GAP * 2}px`,
|
||||
const StyledPendantContainer = styled('div')({
|
||||
width: '100px',
|
||||
'&:hover': {
|
||||
[StyledTriggerLine.toString()]: {
|
||||
'&::before': {
|
||||
display: 'flex',
|
||||
},
|
||||
[`${StyledTriggerLine}`]: {
|
||||
'&::after': {
|
||||
width: '100%',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
const Container = styled('div')({
|
||||
position: 'relative',
|
||||
padding: `${TAG_GAP * 2}px 0 ${LINE_GAP - TAG_GAP * 4}px 0`,
|
||||
'&:hover': {
|
||||
[`${StyledTriggerLine}`]: {
|
||||
'&::before': {
|
||||
opacity: '1',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -29,6 +29,7 @@ export const PendantHistoryPanel = ({
|
||||
|
||||
const [history, setHistory] = useState<RecastBlockValue[]>([]);
|
||||
const popoverHandlerRef = useRef<{ [key: string]: PopperHandler }>({});
|
||||
const historyPanelRef = useRef<HTMLDivElement>();
|
||||
const { getValueHistory } = getRecastItemValue(block);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -84,7 +85,7 @@ export const PendantHistoryPanel = ({
|
||||
}, [block, getProperties, groupBlock, recastBlock]);
|
||||
|
||||
return (
|
||||
<StyledPendantHistoryPanel>
|
||||
<StyledPendantHistoryPanel ref={historyPanelRef}>
|
||||
{history.map(item => {
|
||||
const property = getProperty(item.id);
|
||||
return (
|
||||
@@ -116,6 +117,7 @@ export const PendantHistoryPanel = ({
|
||||
/>
|
||||
}
|
||||
trigger="click"
|
||||
container={historyPanelRef.current}
|
||||
>
|
||||
<PendantTag
|
||||
style={{
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Input, Option, Select, Tooltip } from '@toeverything/components/ui';
|
||||
import {
|
||||
Input,
|
||||
message,
|
||||
Option,
|
||||
Select,
|
||||
Tooltip,
|
||||
} from '@toeverything/components/ui';
|
||||
import { HelpCenterIcon } from '@toeverything/components/icons';
|
||||
import { AsyncBlock } from '../../editor';
|
||||
|
||||
@@ -18,6 +24,7 @@ import {
|
||||
generateRandomFieldName,
|
||||
generateInitialOptions,
|
||||
getPendantConfigByType,
|
||||
checkPendantForm,
|
||||
} from '../utils';
|
||||
import { useOnCreateSure } from './hooks';
|
||||
|
||||
@@ -74,7 +81,7 @@ export const CreatePendantPanel = ({
|
||||
setFieldName(e.target.value);
|
||||
}}
|
||||
endAdornment={
|
||||
<Tooltip content="Help info here">
|
||||
<Tooltip content="Help info here" placement="top">
|
||||
<StyledInputEndAdornment>
|
||||
<HelpCenterIcon />
|
||||
</StyledInputEndAdornment>
|
||||
@@ -98,6 +105,17 @@ export const CreatePendantPanel = ({
|
||||
)}
|
||||
iconConfig={getPendantConfigByType(selectedOption.type)}
|
||||
onSure={async (type, newPropertyItem, newValue) => {
|
||||
const checkResult = checkPendantForm(
|
||||
type,
|
||||
fieldName,
|
||||
newPropertyItem,
|
||||
newValue
|
||||
);
|
||||
|
||||
if (!checkResult.passed) {
|
||||
await message.error(checkResult.message);
|
||||
return;
|
||||
}
|
||||
await onCreateSure({
|
||||
type,
|
||||
newPropertyItem,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useState } from 'react';
|
||||
import { Input, Tooltip } from '@toeverything/components/ui';
|
||||
import { Input, message, Tooltip } from '@toeverything/components/ui';
|
||||
import { HelpCenterIcon } from '@toeverything/components/icons';
|
||||
import { PendantModifyPanel } from '../pendant-modify-panel';
|
||||
import type { AsyncBlock } from '../../editor';
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
type RecastBlockValue,
|
||||
type RecastMetaProperty,
|
||||
} from '../../recast-block';
|
||||
import { getPendantConfigByType } from '../utils';
|
||||
import { checkPendantForm, getPendantConfigByType } from '../utils';
|
||||
import {
|
||||
StyledPopoverWrapper,
|
||||
StyledOperationLabel,
|
||||
@@ -70,7 +70,7 @@ export const UpdatePendantPanel = ({
|
||||
setFieldName(e.target.value);
|
||||
}}
|
||||
endAdornment={
|
||||
<Tooltip content="Help info here">
|
||||
<Tooltip content="Help info here" placement="top">
|
||||
<StyledInputEndAdornment>
|
||||
<HelpCenterIcon />
|
||||
</StyledInputEndAdornment>
|
||||
@@ -98,6 +98,17 @@ export const UpdatePendantPanel = ({
|
||||
property={property}
|
||||
type={property.type}
|
||||
onSure={async (type, newPropertyItem, newValue) => {
|
||||
const checkResult = checkPendantForm(
|
||||
type,
|
||||
fieldName,
|
||||
newPropertyItem,
|
||||
newValue
|
||||
);
|
||||
|
||||
if (!checkResult.passed) {
|
||||
await message.error(checkResult.message);
|
||||
return;
|
||||
}
|
||||
await onUpdateSure({
|
||||
type,
|
||||
newPropertyItem,
|
||||
|
||||
@@ -23,12 +23,7 @@ import {
|
||||
PendantTypes,
|
||||
type TempInformationType,
|
||||
} from '../types';
|
||||
import {
|
||||
checkPendantForm,
|
||||
getOfficialSelected,
|
||||
getPendantConfigByType,
|
||||
} from '../utils';
|
||||
import { message } from '@toeverything/components/ui';
|
||||
import { getOfficialSelected, getPendantConfigByType } from '../utils';
|
||||
|
||||
type SelectPropertyType = MultiSelectProperty | SelectProperty;
|
||||
type SureParams = {
|
||||
@@ -56,18 +51,6 @@ export const useOnCreateSure = ({ block }: { block: AsyncBlock }) => {
|
||||
newPropertyItem,
|
||||
newValue,
|
||||
}: SureParams) => {
|
||||
const checkResult = checkPendantForm(
|
||||
type,
|
||||
fieldName,
|
||||
newPropertyItem,
|
||||
newValue
|
||||
);
|
||||
|
||||
if (!checkResult.passed) {
|
||||
await message.error(checkResult.message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
type === PendantTypes.MultiSelect ||
|
||||
type === PendantTypes.Select ||
|
||||
@@ -181,18 +164,6 @@ export const useOnUpdateSure = ({
|
||||
newPropertyItem,
|
||||
newValue,
|
||||
}: SureParams) => {
|
||||
const checkResult = checkPendantForm(
|
||||
type,
|
||||
fieldName,
|
||||
newPropertyItem,
|
||||
newValue
|
||||
);
|
||||
|
||||
if (!checkResult.passed) {
|
||||
await message.error(checkResult.message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
type === PendantTypes.MultiSelect ||
|
||||
type === PendantTypes.Select ||
|
||||
|
||||
@@ -26,6 +26,7 @@ export const PendantPopover: FC<
|
||||
block={block}
|
||||
endElement={
|
||||
<AddPendantPopover
|
||||
container={popoverProps.container}
|
||||
block={block}
|
||||
onSure={() => {
|
||||
popoverHandlerRef.current?.setVisible(false);
|
||||
|
||||
@@ -105,6 +105,8 @@ export const PendantRender = ({ block }: { block: AsyncBlock }) => {
|
||||
<AddPendantPopover
|
||||
block={block}
|
||||
iconStyle={{ marginTop: 4 }}
|
||||
trigger="click"
|
||||
// trigger={isKanbanView ? 'hover' : 'click'}
|
||||
container={blockRenderContainerRef.current}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -162,7 +162,7 @@ export class BlockCommands {
|
||||
public async moveInNewGridItem(
|
||||
blockId: string,
|
||||
gridItemId: string,
|
||||
isBefore = false
|
||||
type = GridDropType.left
|
||||
) {
|
||||
const block = await this._editor.getBlockById(blockId);
|
||||
if (block) {
|
||||
@@ -175,7 +175,7 @@ export class BlockCommands {
|
||||
await block.remove();
|
||||
await gridItemBlock.append(block);
|
||||
if (targetGridItemBlock && gridItemBlock) {
|
||||
if (isBefore) {
|
||||
if (type === GridDropType.left) {
|
||||
await targetGridItemBlock.before(gridItemBlock);
|
||||
} else {
|
||||
await targetGridItemBlock.after(gridItemBlock);
|
||||
|
||||
@@ -95,6 +95,9 @@ export class DragDropManager {
|
||||
}
|
||||
|
||||
private async _handleDropBlock(event: React.DragEvent<Element>) {
|
||||
const targetBlock = await this._editor.getBlockById(
|
||||
this._blockDragTargetId
|
||||
);
|
||||
if (this._blockDragDirection !== BlockDropPlacement.none) {
|
||||
const blockId = event.dataTransfer.getData(this._blockIdKey);
|
||||
if (!(await this._canBeDrop(event))) return;
|
||||
@@ -109,13 +112,24 @@ export class DragDropManager {
|
||||
this._blockDragDirection
|
||||
)
|
||||
) {
|
||||
await this._editor.commands.blockCommands.createLayoutBlock(
|
||||
blockId,
|
||||
this._blockDragTargetId,
|
||||
const dropType =
|
||||
this._blockDragDirection === BlockDropPlacement.left
|
||||
? GridDropType.left
|
||||
: GridDropType.right
|
||||
);
|
||||
: GridDropType.right;
|
||||
// if target is a grid item create grid item
|
||||
if (targetBlock.type !== Protocol.Block.Type.gridItem) {
|
||||
await this._editor.commands.blockCommands.createLayoutBlock(
|
||||
blockId,
|
||||
this._blockDragTargetId,
|
||||
dropType
|
||||
);
|
||||
} else {
|
||||
await this._editor.commands.blockCommands.moveInNewGridItem(
|
||||
blockId,
|
||||
this._blockDragTargetId,
|
||||
dropType
|
||||
);
|
||||
}
|
||||
}
|
||||
if (
|
||||
[
|
||||
@@ -123,9 +137,6 @@ export class DragDropManager {
|
||||
BlockDropPlacement.outerRight,
|
||||
].includes(this._blockDragDirection)
|
||||
) {
|
||||
const targetBlock = await this._editor.getBlockById(
|
||||
this._blockDragTargetId
|
||||
);
|
||||
if (targetBlock.type !== Protocol.Block.Type.grid) {
|
||||
await this._editor.commands.blockCommands.createLayoutBlock(
|
||||
blockId,
|
||||
@@ -154,7 +165,7 @@ export class DragDropManager {
|
||||
await this._editor.commands.blockCommands.moveInNewGridItem(
|
||||
blockId,
|
||||
gridItems[0].id,
|
||||
true
|
||||
GridDropType.right
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -347,10 +358,10 @@ export class DragDropManager {
|
||||
blockId: string
|
||||
) {
|
||||
const { clientX, clientY } = event;
|
||||
this._setBlockDragTargetId(blockId);
|
||||
const path = await this._editor.getBlockPath(blockId);
|
||||
const mousePoint = new Point(clientX, clientY);
|
||||
const rect = domToRect(blockDom);
|
||||
let targetBlock: AsyncBlock = path[path.length - 1];
|
||||
/**
|
||||
* IMP: compute the level of the target block
|
||||
* future feature drag drop has level support do not delete
|
||||
@@ -386,13 +397,30 @@ export class DragDropManager {
|
||||
const gridBlocks = path.filter(
|
||||
block => block.type === Protocol.Block.Type.grid
|
||||
);
|
||||
// limit grid block floor counts, when drag block to init grid
|
||||
if (gridBlocks.length >= MAX_GRID_BLOCK_FLOOR) {
|
||||
const parentBlock = path[path.length - 2];
|
||||
// a new grid should not be grid item`s child
|
||||
if (
|
||||
parentBlock &&
|
||||
parentBlock.type === Protocol.Block.Type.gridItem
|
||||
) {
|
||||
targetBlock = parentBlock;
|
||||
// gridItem`s parent must be grid block
|
||||
const gridItemCounts = (await path[path.length - 3].children())
|
||||
.length;
|
||||
if (
|
||||
gridItemCounts >=
|
||||
this._editor.configManager.grid.maxGridItemCount
|
||||
) {
|
||||
direction = BlockDropPlacement.none;
|
||||
}
|
||||
// limit grid block floor counts, when drag block to init grid
|
||||
} else if (gridBlocks.length >= MAX_GRID_BLOCK_FLOOR) {
|
||||
direction = BlockDropPlacement.none;
|
||||
}
|
||||
}
|
||||
this._setBlockDragTargetId(targetBlock.id);
|
||||
this._setBlockDragDirection(direction);
|
||||
return direction;
|
||||
return { direction, block: targetBlock };
|
||||
}
|
||||
|
||||
public handlerEditorDrop(event: React.DragEvent<Element>) {
|
||||
|
||||
Reference in New Issue
Block a user