🐛(frontend) paste content with comments from another document
When pasting comments, the data-bn-thread-id attribute is present in the clipboard data. This indicates that the pasted content contains comments. But if the content with comments comes from another document, it will create orphaned comments that are not linked to this document and create errors. To avoid this, we refresh the threads to ensure that only comments relevant to the current document are displayed.
This commit is contained in:
@@ -15,6 +15,10 @@ and this project adheres to
|
||||
- 🚸(backend) use unaccented full name for user search #1637
|
||||
- 🌐(backend) internationalize demo #1644
|
||||
|
||||
### Fixed
|
||||
|
||||
- 🐛(frontend) paste content with comments from another document #1732
|
||||
|
||||
## [4.1.0] - 2025-12-09
|
||||
|
||||
### Added
|
||||
|
||||
@@ -318,6 +318,49 @@ test.describe('Doc Comments', () => {
|
||||
|
||||
await cleanup();
|
||||
});
|
||||
|
||||
test('it checks comments pasting from another document', async ({
|
||||
page,
|
||||
browserName,
|
||||
}) => {
|
||||
await createDoc(page, 'comment-doc-1', browserName, 1);
|
||||
|
||||
// We add a comment in the first document
|
||||
const editor1 = await writeInEditor({ page, text: 'Document One' });
|
||||
await editor1.getByText('Document One').selectText();
|
||||
await page.getByRole('button', { name: 'Comment' }).click();
|
||||
|
||||
const thread1 = page.locator('.bn-thread');
|
||||
await thread1.getByRole('paragraph').first().fill('Comment in Doc One');
|
||||
await thread1.locator('[data-test="save"]').click();
|
||||
await expect(thread1.getByText('Comment in Doc One').first()).toBeHidden();
|
||||
|
||||
await expect(editor1.getByText('Document One')).toHaveCSS(
|
||||
'background-color',
|
||||
'rgba(237, 180, 0, 0.4)',
|
||||
);
|
||||
|
||||
await editor1.getByText('Document One').click();
|
||||
// We copy the content including the comment from the first document
|
||||
await editor1.getByText('Document One').selectText();
|
||||
await page.keyboard.press('Control+C');
|
||||
|
||||
// We create a second document
|
||||
await createDoc(page, 'comment-doc-2', browserName, 1);
|
||||
|
||||
// We paste the content into the second document
|
||||
const editor2 = await writeInEditor({ page, text: '' });
|
||||
await editor2.click();
|
||||
await page.keyboard.press('Control+V');
|
||||
|
||||
await expect(editor2.getByText('Document One')).toHaveCSS(
|
||||
'background-color',
|
||||
'rgba(0, 0, 0, 0)',
|
||||
);
|
||||
|
||||
await editor2.getByText('Document One').click();
|
||||
await expect(page.locator('.bn-thread')).toBeHidden();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Doc Comments mobile', () => {
|
||||
|
||||
@@ -162,6 +162,26 @@ export const BlockNoteEditor = ({ doc, provider }: BlockNoteEditorProps) => {
|
||||
multi_column:
|
||||
multiColumnLocales?.[lang as keyof typeof multiColumnLocales],
|
||||
},
|
||||
pasteHandler: ({ event, defaultPasteHandler }) => {
|
||||
// Get clipboard data
|
||||
const blocknoteData = event.clipboardData?.getData('blocknote/html');
|
||||
|
||||
/**
|
||||
* When pasting comments, the data-bn-thread-id
|
||||
* attribute is present in the clipboard data.
|
||||
* This indicates that the pasted content contains comments.
|
||||
* But if the content with comments comes from another document,
|
||||
* it will create orphaned comments that are not linked to this document
|
||||
* and create errors.
|
||||
* To avoid this, we refresh the threads to ensure that only comments
|
||||
* relevant to the current document are displayed.
|
||||
*/
|
||||
if (blocknoteData && blocknoteData.includes('data-bn-thread-id')) {
|
||||
void threadStore.refreshThreads();
|
||||
}
|
||||
|
||||
return defaultPasteHandler();
|
||||
},
|
||||
resolveUsers: async (userIds) => {
|
||||
return Promise.resolve(
|
||||
userIds.map((encodedURIUserId) => {
|
||||
|
||||
@@ -117,7 +117,7 @@ export const cssComments = (
|
||||
}
|
||||
|
||||
& svg {
|
||||
color: var(--c--globals--colors--info-600);
|
||||
color: var(--c--contextuals--background--semantic--brand--primary);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,15 +134,23 @@ export const cssComments = (
|
||||
padding-inline: var(--c--globals--spacings--st);
|
||||
|
||||
&[data-test='save'] {
|
||||
border: 1px solid var(--c--globals--colors--info-600);
|
||||
background: var(--c--globals--colors--info-600);
|
||||
color: white;
|
||||
border: 1px solid
|
||||
var(--c--contextuals--background--semantic--brand--primary);
|
||||
background: var(
|
||||
--c--contextuals--background--semantic--brand--primary
|
||||
);
|
||||
color: var(
|
||||
--c--contextuals--content--semantic--brand--on-brand
|
||||
);
|
||||
}
|
||||
|
||||
&[data-test='cancel'] {
|
||||
background: white;
|
||||
border: 1px solid var(--c--globals--colors--gray-300);
|
||||
color: var(--c--globals--colors--info-600);
|
||||
border: 1px solid
|
||||
var(--c--contextuals--border--surface--primary);
|
||||
color: var(
|
||||
--c--contextuals--background--semantic--brand--primary
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -184,7 +192,9 @@ export const cssComments = (
|
||||
|
||||
button {
|
||||
font-size: 0;
|
||||
background: var(--c--globals--colors--info-600);
|
||||
background: var(
|
||||
--c--contextuals--background--semantic--brand--primary
|
||||
);
|
||||
width: var(--c--globals--spacings--md);
|
||||
height: var(--c--globals--spacings--md);
|
||||
padding: var(--c--globals--spacings--0);
|
||||
@@ -197,7 +207,7 @@ export const cssComments = (
|
||||
content: 'arrow_upward_alt';
|
||||
font-family: 'Material Symbols Outlined Variable', sans-serif;
|
||||
font-size: 18px;
|
||||
color: var(--c--globals--colors--gray-100);
|
||||
color: var(--c--contextuals--content--semantic--brand--on-brand);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user