Skip to content

Commit

Permalink
feat: support callout pick icon (#24)
Browse files Browse the repository at this point in the history
  • Loading branch information
qinluhe authored Jan 13, 2025
1 parent 7ff3344 commit 8fabf8f
Show file tree
Hide file tree
Showing 7 changed files with 181 additions and 32 deletions.
1 change: 1 addition & 0 deletions src/application/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ export interface CodeBlockData extends BlockData {

export interface CalloutBlockData extends BlockData {
icon: string;
icon_type?: 'emoji' | 'icon',
}

export interface MathEquationBlockData extends BlockData {
Expand Down
42 changes: 21 additions & 21 deletions src/components/_shared/emoji-picker/EmojiPickerCategories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import AutoSizer from 'react-virtualized-auto-sizer';
import { FixedSizeList } from 'react-window';
import { EmojiCategory, getRowsWithCategories } from './EmojiPicker.hooks';

function EmojiPickerCategories({
function EmojiPickerCategories ({
emojiCategories,
onEmojiSelect,
onEscape,
Expand All @@ -30,7 +30,7 @@ function EmojiPickerCategories({
}, [emojiCategories]);
const mouseY = useRef<number | null>(null);
const mouseX = useRef<number | null>(null);

const ref = React.useRef<HTMLDivElement>(null);

const getCategoryName = useCallback(
Expand All @@ -49,7 +49,7 @@ function EmojiPickerCategories({

return i18nName[id];
},
[t]
[t],
);

useEffect(() => {
Expand All @@ -71,7 +71,10 @@ function EmojiPickerCategories({
const isFlags = item.category === 'flags';

return (
<div style={style} data-index={index}>
<div
style={style}
data-index={index}
>
{item.type === 'category' ? (
<div className={'pt-2 text-base font-medium text-text-caption'}>{tagName}</div>
) : null}
Expand All @@ -86,8 +89,6 @@ function EmojiPickerCategories({

if (isSelected) {
classList.push('bg-fill-list-hover');
} else {
classList.push('hover:bg-transparent');
}

if (isDefaultEmoji) {
Expand All @@ -99,7 +100,13 @@ function EmojiPickerCategories({
}

return (
<Tooltip key={emoji.id} title={emoji.name} placement={'top'} enterDelay={500} disableInteractive={true}>
<Tooltip
key={emoji.id}
title={emoji.name}
placement={'top'}
enterDelay={500}
disableInteractive={true}
>
<div
data-key={emoji.id}
style={{
Expand All @@ -114,13 +121,6 @@ function EmojiPickerCategories({
mouseX.current = e.clientX;
}}
onMouseEnter={(e) => {
if (mouseY.current === null || mouseY.current !== e.clientY || mouseX.current !== e.clientX) {
setSelectCell({
row: index,
column: columnIndex,
});
}

mouseX.current = e.clientX;
mouseY.current = e.clientY;
}}
Expand All @@ -135,7 +135,7 @@ function EmojiPickerCategories({
</div>
);
},
[defaultEmoji, getCategoryName, onEmojiSelect, rows, selectCell.column, selectCell.row]
[defaultEmoji, getCategoryName, onEmojiSelect, rows, selectCell],
);

const getNewColumnIndex = useCallback(
Expand All @@ -150,7 +150,7 @@ function EmojiPickerCategories({

return newColumnIndex;
},
[rows]
[rows],
);

const findNextRow = useCallback(
Expand All @@ -171,7 +171,7 @@ function EmojiPickerCategories({
column: newColumnIndex,
};
},
[getNewColumnIndex, rows]
[getNewColumnIndex, rows],
);

const findPrevRow = useCallback(
Expand All @@ -191,7 +191,7 @@ function EmojiPickerCategories({
column: newColumnIndex,
};
},
[getNewColumnIndex, rows]
[getNewColumnIndex, rows],
);

const findPrevCell = useCallback(
Expand All @@ -215,7 +215,7 @@ function EmojiPickerCategories({
column: prevColumn,
};
},
[findPrevRow, rows]
[findPrevRow, rows],
);

const findNextCell = useCallback(
Expand All @@ -239,7 +239,7 @@ function EmojiPickerCategories({
column: nextColumn,
};
},
[findNextRow, rows]
[findNextRow, rows],
);

useEffect(() => {
Expand Down Expand Up @@ -325,7 +325,7 @@ function EmojiPickerCategories({
rows,
selectCell.column,
selectCell.row,
]
],
);

useEffect(() => {
Expand Down
4 changes: 4 additions & 0 deletions src/components/_shared/emoji-picker/EmojiPickerHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,17 +55,20 @@ function EmojiPickerHeader ({ hideRemove, onEmojiSelect, onSkinSelect, searchVal
onClick,
tooltip,
children,
testId,
}: {
onClick: (e: React.MouseEvent<HTMLButtonElement>) => void;
tooltip: string;
children: React.ReactNode;
testId?: string;
}) => {
return (
<Tooltip title={tooltip}>
<Button
size={'small'}
variant={'outlined'}
color={'inherit'}
data-testid={testId}
className={'h-9 w-9 min-w-[36px] px-0 py-0'}
onClick={onClick}
>
Expand Down Expand Up @@ -105,6 +108,7 @@ function EmojiPickerHeader ({ hideRemove, onEmojiSelect, onSkinSelect, searchVal

onEmojiSelect(emoji);
},
testId: 'random-emoji',
tooltip: t('emoji.random'),
children: <ShuffleIcon className={'h-5 w-5'} />,
})}
Expand Down
4 changes: 2 additions & 2 deletions src/components/_shared/icon-picker/IconPicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -134,14 +134,14 @@ function IconPicker ({
<Button
size="small"
color="inherit"
className="h-8 w-8 min-w-[32px] items-center px-1 py-1"
className="h-8 w-8 min-w-[32px] items-center p-[7px]"
onClick={(e) => {
setSelectIcon(icon.id);
setAnchorEl(e.currentTarget);
}}
>
<div
className={'w-6 h-6 text-text-title'}
className={'w-5 h-5 text-text-title'}
dangerouslySetInnerHTML={{ __html: icon.cleanSvg }}
/>
</Button>
Expand Down
7 changes: 6 additions & 1 deletion src/components/_shared/view-icon/ChangeIconPopover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,10 @@ function ChangeIconPopover ({
anchorPosition={anchorPosition}
anchorReference={anchorPosition ? 'anchorPosition' : 'anchorEl'}
>
<div className={'border-b w-[402px] border-line-divider px-4 pt-2 flex items-center justify-between'}>
<div
data-testid="change-icon-popover"
className={'border-b w-[402px] border-line-divider px-4 pt-2 flex items-center justify-between'}
>
<ViewTabs
onChange={(_e, newValue) => setValue(newValue)}
value={value}
Expand All @@ -63,6 +66,7 @@ function ChangeIconPopover ({
className={'flex items-center flex-row justify-center gap-1.5'}
value={'emoji'}
label={'Emojis'}
data-testid="emoji-tab"
/>
)
}
Expand All @@ -72,6 +76,7 @@ function ChangeIconPopover ({
className={'flex items-center flex-row justify-center gap-1.5'}
value={'icon'}
label={'Icons'}
data-testid="icon-tab"
/>
)
}
Expand Down
77 changes: 77 additions & 0 deletions src/components/editor/__tests__/blocks/CalloutBlock.cy.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { BlockType } from '@/application/types';
import { initialEditorTest } from '@/components/editor/__tests__/mount';
import { FromBlockJSON } from 'cypress/support/document';

const initialData: FromBlockJSON[] = [{
type: BlockType.CalloutBlock,
data: {},
text: [{ insert: 'Hello Callout' }],
children: [],
}];

const { assertJSON, initializeEditor } = initialEditorTest();

describe('CalloutBlock', () => {
beforeEach(() => {
cy.viewport(1280, 720);
Object.defineProperty(window.navigator, 'language', { value: 'en-US' });
initializeEditor(initialData);
const selector = '[role="textbox"]';

cy.get(selector).as('editor');

cy.wait(1000);

cy.get(selector).focus();
});

it('should show callout icon popover when clicking icon button', () => {
cy.get('@editor').get('[data-block-type="callout"]').as('callout');
cy.get('@callout').find('[data-testid="callout-icon-button"]').click();
cy.get('[data-testid="change-icon-popover"]').should('exist');
});

it('should display `📌` emoji as default icon', () => {
cy.get('@editor').get('[data-block-type="callout"]').as('callout');
cy.get('@callout').find('[data-testid="callout-icon-button"]').should('have.text', '📌');
});

it('should add child block when pressing enter', () => {
cy.selectMultipleText(['Hello Callout']);
cy.wait(100);

cy.get('@editor').realPress('ArrowRight');
cy.get('@editor').realPress('Enter');
cy.get('@editor').type('Hello World');
assertJSON([
{
type: BlockType.CalloutBlock,
data: {},
children: [{
type: BlockType.Paragraph,
data: {},
children: [],
text: [{ insert: 'Hello World' }],
}],
text: [{ insert: 'Hello Callout' }],
},
]);
});

it('should turn to paragraph block when pressing backspace at the beginning of the block', () => {
cy.selectMultipleText(['Hello Callout']);
cy.wait(100);

cy.get('@editor').realPress('ArrowLeft');

cy.get('@editor').realPress('Backspace');
assertJSON([
{
type: BlockType.Paragraph,
data: {},
children: [],
text: [{ insert: 'Hello Callout' }],
},
]);
});
});
Loading

0 comments on commit 8fabf8f

Please sign in to comment.