✨(frontend) preserve @ character when esc is pressed after typing it
improves user experience by keeping @ symbol after cancelling mention trigger Signed-off-by: Cyril <c.gromoff@gmail.com>
This commit is contained in:
@@ -11,6 +11,7 @@ and this project adheres to
|
|||||||
- ♿(frontend) improve accessibility:
|
- ♿(frontend) improve accessibility:
|
||||||
- ♿(frontend) improve ARIA in doc grid and editor for a11y #1519
|
- ♿(frontend) improve ARIA in doc grid and editor for a11y #1519
|
||||||
- 🐛(docx) fix image overflow by limiting width to 600px during export #1525
|
- 🐛(docx) fix image overflow by limiting width to 600px during export #1525
|
||||||
|
- 🐛(frontend) preserve @ character when esc is pressed after typing it #1512
|
||||||
|
|
||||||
## [3.9.0] - 2025-11-10
|
## [3.9.0] - 2025-11-10
|
||||||
|
|
||||||
|
|||||||
@@ -806,6 +806,12 @@ test.describe('Doc Editor', () => {
|
|||||||
});
|
});
|
||||||
await expect(interlinkChild1).toBeVisible({ timeout: 10000 });
|
await expect(interlinkChild1).toBeVisible({ timeout: 10000 });
|
||||||
await expect(interlinkChild1.locator('svg').first()).toBeVisible();
|
await expect(interlinkChild1.locator('svg').first()).toBeVisible();
|
||||||
|
|
||||||
|
await page.keyboard.press('@');
|
||||||
|
|
||||||
|
await page.keyboard.press('Escape');
|
||||||
|
|
||||||
|
await expect(editor.getByText('@')).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('it checks multiple big doc scroll to the top', async ({
|
test('it checks multiple big doc scroll to the top', async ({
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import {
|
|||||||
StyleSchema,
|
StyleSchema,
|
||||||
} from '@blocknote/core';
|
} from '@blocknote/core';
|
||||||
import { useBlockNoteEditor } from '@blocknote/react';
|
import { useBlockNoteEditor } from '@blocknote/react';
|
||||||
|
import type { KeyboardEvent } from 'react';
|
||||||
import { useEffect, useRef, useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { css } from 'styled-components';
|
import { css } from 'styled-components';
|
||||||
@@ -99,6 +100,55 @@ export const SearchPage = ({
|
|||||||
}, 100);
|
}, 100);
|
||||||
}, [inputRef]);
|
}, [inputRef]);
|
||||||
|
|
||||||
|
const closeSearch = (insertContent: string) => {
|
||||||
|
updateInlineContent({
|
||||||
|
type: 'interlinkingSearchInline',
|
||||||
|
props: {
|
||||||
|
disabled: true,
|
||||||
|
trigger,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
contentRef(null);
|
||||||
|
editor.focus();
|
||||||
|
editor.insertInlineContent([insertContent]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {
|
||||||
|
if (e.key === 'Escape') {
|
||||||
|
e.preventDefault();
|
||||||
|
// Keep the trigger character ('@' or '/') in the editor when closing with Escape
|
||||||
|
closeSearch(trigger);
|
||||||
|
} else if (e.key === 'Backspace' && search.length === 0) {
|
||||||
|
e.preventDefault();
|
||||||
|
closeSearch('');
|
||||||
|
} else if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
|
||||||
|
// Allow arrow keys to be handled by the command menu for navigation
|
||||||
|
const commandList = e.currentTarget
|
||||||
|
.closest('.inline-content')
|
||||||
|
?.nextElementSibling?.querySelector('[cmdk-list]');
|
||||||
|
|
||||||
|
// Create a synthetic keyboard event for the command menu
|
||||||
|
const syntheticEvent = new KeyboardEvent('keydown', {
|
||||||
|
key: e.key,
|
||||||
|
bubbles: true,
|
||||||
|
cancelable: true,
|
||||||
|
});
|
||||||
|
commandList?.dispatchEvent(syntheticEvent);
|
||||||
|
e.preventDefault();
|
||||||
|
} else if (e.key === 'Enter') {
|
||||||
|
// Handle Enter key to select the currently highlighted item
|
||||||
|
const selectedItem = e.currentTarget
|
||||||
|
.closest('.inline-content')
|
||||||
|
?.nextElementSibling?.querySelector(
|
||||||
|
'[cmdk-item][data-selected="true"]',
|
||||||
|
) as HTMLElement;
|
||||||
|
|
||||||
|
selectedItem?.click();
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box as="span" $position="relative">
|
<Box as="span" $position="relative">
|
||||||
<Box
|
<Box
|
||||||
@@ -124,50 +174,7 @@ export const SearchPage = ({
|
|||||||
const value = (e.target as HTMLInputElement).value;
|
const value = (e.target as HTMLInputElement).value;
|
||||||
setSearch(value);
|
setSearch(value);
|
||||||
}}
|
}}
|
||||||
onKeyDown={(e) => {
|
onKeyDown={handleKeyDown}
|
||||||
if (
|
|
||||||
(e.key === 'Backspace' && search.length === 0) ||
|
|
||||||
e.key === 'Escape'
|
|
||||||
) {
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
updateInlineContent({
|
|
||||||
type: 'interlinkingSearchInline',
|
|
||||||
props: {
|
|
||||||
disabled: true,
|
|
||||||
trigger,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
contentRef(null);
|
|
||||||
editor.focus();
|
|
||||||
editor.insertInlineContent(['']);
|
|
||||||
} else if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
|
|
||||||
// Allow arrow keys to be handled by the command menu for navigation
|
|
||||||
const commandList = e.currentTarget
|
|
||||||
.closest('.inline-content')
|
|
||||||
?.nextElementSibling?.querySelector('[cmdk-list]');
|
|
||||||
|
|
||||||
// Create a synthetic keyboard event for the command menu
|
|
||||||
const syntheticEvent = new KeyboardEvent('keydown', {
|
|
||||||
key: e.key,
|
|
||||||
bubbles: true,
|
|
||||||
cancelable: true,
|
|
||||||
});
|
|
||||||
commandList?.dispatchEvent(syntheticEvent);
|
|
||||||
e.preventDefault();
|
|
||||||
} else if (e.key === 'Enter') {
|
|
||||||
// Handle Enter key to select the currently highlighted item
|
|
||||||
const selectedItem = e.currentTarget
|
|
||||||
.closest('.inline-content')
|
|
||||||
?.nextElementSibling?.querySelector(
|
|
||||||
'[cmdk-item][data-selected="true"]',
|
|
||||||
) as HTMLElement;
|
|
||||||
|
|
||||||
selectedItem?.click();
|
|
||||||
e.preventDefault();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
<Box
|
<Box
|
||||||
@@ -224,6 +231,8 @@ export const SearchPage = ({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
contentRef(null);
|
||||||
|
|
||||||
editor.insertInlineContent([
|
editor.insertInlineContent([
|
||||||
{
|
{
|
||||||
type: 'interlinkingLinkInline',
|
type: 'interlinkingLinkInline',
|
||||||
|
|||||||
Reference in New Issue
Block a user