Skip to content

Commit

Permalink
fix: the code block wrap state shoud be persisted in database (#7062)
Browse files Browse the repository at this point in the history
### TL;DR

This Pull Request moves the `wrap` property from temporary state to persistent data model. When user refreshes the web browser, the code block warp style keeps.

Fix affine-design/issue/BS-297.

### What changed?

- In `code-block.ts`, the `_wrap` private state variable has been removed, and all references to it have instead been directed to `this.model.wrap`.
- A `setWrap` function has been added to handle updating the `wrap` property in the block model, which can be persisted in database.

### How to test?

Test this change by creating a code block in document and toggle the `wrap` icon. Check if this modifies the wrap state in the model and updates the UI accordingly. Refresh the browser, the code block warp styles keeps.

<img width="735" alt="截屏2024-05-15 16 03 20" src="https://github.com/toeverything/blocksuite/assets/12724894/4a36124c-9bfb-451a-a1d4-bbc3888f7fa7">

<img width="723" alt="截屏2024-05-15 16 03 02" src="https://github.com/toeverything/blocksuite/assets/12724894/d613f033-038f-4f53-a476-4be87083fd2f">

---
  • Loading branch information
akumatus committed May 16, 2024
1 parent 6609974 commit 3274a6c
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 25 deletions.
21 changes: 12 additions & 9 deletions packages/blocks/src/code-block/code-block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,6 @@ import { getHighLighter } from './utils/high-lighter.js';
export class CodeBlockComponent extends BlockElement<CodeBlockModel> {
static override styles = codeBlockStyles;

@state()
private _wrap = false;

@query('.lang-button')
private _langButton!: HTMLButtonElement;

Expand Down Expand Up @@ -176,9 +173,9 @@ export class CodeBlockComponent extends BlockElement<CodeBlockModel> {
CodeOptionTemplate({
anchor: this,
model: this.model,
wrap: this._wrap,
onClickWrap: () => {
this._wrap = !this._wrap;
wrap: this.model.wrap,
toggleWrap: () => {
this.setWrap(!this.model.wrap);
updatePortal();
},
abortController,
Expand Down Expand Up @@ -429,6 +426,10 @@ export class CodeBlockComponent extends BlockElement<CodeBlockModel> {
});
}

setWrap(wrap: boolean) {
this.doc.updateBlock(this.model, { wrap });
}

private _onClickLangBtn() {
if (this.readonly) return;
if (this._langListAbortController) return;
Expand Down Expand Up @@ -477,7 +478,9 @@ export class CodeBlockComponent extends BlockElement<CodeBlockModel> {
this.querySelector<HTMLElement>('#line-numbers');
assertExists(lineNumbersContainer);

const next = this._wrap ? generateLineNumberRender() : lineNumberRender;
const next = this.model.wrap
? generateLineNumberRender()
: lineNumberRender;

render(
repeat(Array.from(this.querySelectorAll('v-line')), next),
Expand All @@ -491,7 +494,7 @@ export class CodeBlockComponent extends BlockElement<CodeBlockModel> {
${ref(this._whenHover.setReference)}
class=${classMap({
'affine-code-block-container': true,
wrap: this._wrap,
wrap: this.model.wrap,
})}
>
${this._curLanguageButtonTemplate()}
Expand All @@ -507,7 +510,7 @@ export class CodeBlockComponent extends BlockElement<CodeBlockModel> {
.inlineRangeProvider=${this._inlineRangeProvider}
.enableClipboard=${false}
.enableUndoRedo=${false}
.wrapText=${this._wrap}
.wrapText=${this.model.wrap}
.verticalScrollContainer=${getViewportElement(this.host)}
>
</rich-text>
Expand Down
1 change: 1 addition & 0 deletions packages/blocks/src/code-block/code-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const CodeBlockSchema = defineBlockSchema({
props: internal => ({
text: internal.Text(),
language: FALLBACK_LANG,
wrap: false,
}),
metadata: {
version: 1,
Expand Down
28 changes: 15 additions & 13 deletions packages/blocks/src/code-block/components/code-option.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ export function CodeOptionTemplate({
ref: containerRef,
model,
wrap,
onClickWrap,
toggleWrap,
anchor,
}: {
ref?: RefOrCallback;
anchor: CodeBlockComponent;
model: BlockModel;
wrap: boolean;
abortController: AbortController;
onClickWrap: () => void;
toggleWrap: () => void;
}) {
const page = model.doc;
const readonly = page.readonly;
Expand Down Expand Up @@ -71,17 +71,19 @@ export function CodeOptionTemplate({
>Copy to Clipboard</affine-tooltip
>
</icon-button>
<icon-button
size="32px"
data-testid="wrap-button"
?active=${wrap}
@click=${onClickWrap}
>
${wrap ? CancelWrapIcon : WrapIcon}
<affine-tooltip tip-position="right" .offset=${12}
>${wrap ? 'Cancel wrap' : 'Wrap code'}</affine-tooltip
>
</icon-button>
${readonly
? nothing
: html`<icon-button
size="32px"
data-testid="wrap-button"
?active=${wrap}
@click=${toggleWrap}
>
${wrap ? CancelWrapIcon : WrapIcon}
<affine-tooltip tip-position="right" .offset=${12}
>${wrap ? 'Cancel wrap' : 'Wrap code'}</affine-tooltip
>
</icon-button>`}
${readonly
? nothing
: html`<icon-button
Expand Down
96 changes: 93 additions & 3 deletions tests/code.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ test('use markdown syntax can create code block', async ({ page }) => {
>
<affine:code
prop:language="Plain Text"
prop:wrap={false}
/>
<affine:paragraph
prop:text="aaa"
Expand Down Expand Up @@ -277,6 +278,7 @@ test('change code language can work', async ({ page }) => {
/*xml*/ `
<affine:code
prop:language="rust"
prop:wrap={false}
/>`,
codeBlockId
);
Expand All @@ -286,6 +288,7 @@ test('change code language can work', async ({ page }) => {
/*xml*/ `
<affine:code
prop:language="Plain Text"
prop:wrap={false}
/>`,
codeBlockId
);
Expand Down Expand Up @@ -418,10 +421,12 @@ test.skip('use keyboard copy inside code block copy', async ({ page }) => {
<affine:code
prop:language="Plain Text"
prop:text="use"
prop:wrap={false}
/>
<affine:code
prop:language="Plain Text"
prop:text="use"
prop:wrap={false}
/>
</affine:note>
</affine:page>`
Expand Down Expand Up @@ -473,10 +478,12 @@ test.fixme(
<affine:code
prop:language="javascript"
prop:text="use"
prop:wrap={false}
/>
<affine:code
prop:language="javascript"
prop:text="use"
prop:wrap={false}
/>
</affine:note>
</affine:page>`
Expand Down Expand Up @@ -711,6 +718,89 @@ test('should tab works in code block', async ({ page }) => {
await assertRichTexts(page, ['const a = 10;\n \nconst b = "NothingToSay"']);
});

test('toggle code block wrap can work', async ({ page }) => {
await enterPlaygroundRoom(page);
const { codeBlockId } = await initEmptyCodeBlockState(page);
await focusRichText(page);

const codeBlockController = getCodeBlock(page);
await assertStoreMatchJSX(
page,
/*xml*/ `
<affine:code
prop:language="Plain Text"
prop:wrap={false}
/>`,
codeBlockId
);

await codeBlockController.codeBlock.hover();
await expect(codeBlockController.wrapButton).toBeVisible();
await codeBlockController.wrapButton.click();
await assertStoreMatchJSX(
page,
/*xml*/ `
<affine:code
prop:language="Plain Text"
prop:wrap={true}
/>`,
codeBlockId
);

await codeBlockController.wrapButton.click();
await assertStoreMatchJSX(
page,
/*xml*/ `
<affine:code
prop:language="Plain Text"
prop:wrap={false}
/>`,
codeBlockId
);
});

test('undo code block wrap can work', async ({ page }) => {
await enterPlaygroundRoom(page);
const { codeBlockId } = await initEmptyCodeBlockState(page);
await focusRichText(page);

const codeBlockController = getCodeBlock(page);
await assertStoreMatchJSX(
page,
/*xml*/ `
<affine:code
prop:language="Plain Text"
prop:wrap={false}
/>`,
codeBlockId
);

await codeBlockController.codeBlock.hover();
await expect(codeBlockController.wrapButton).toBeVisible();
await codeBlockController.wrapButton.click();
await assertStoreMatchJSX(
page,
/*xml*/ `
<affine:code
prop:language="Plain Text"
prop:wrap={true}
/>`,
codeBlockId
);

await focusRichText(page);
await undoByKeyboard(page);
await assertStoreMatchJSX(
page,
/*xml*/ `
<affine:code
prop:language="Plain Text"
prop:wrap={false}
/>`,
codeBlockId
);
});

test('should code block wrap active after click', async ({ page }) => {
await enterPlaygroundRoom(page);
await initEmptyCodeBlockState(page);
Expand Down Expand Up @@ -748,9 +838,9 @@ test('should code block works in read only mode', async ({ page }) => {
await codeBlockController.clickLanguageButton();
await expect(codeBlockController.langList).toBeHidden();
await expect(codeBlockController.codeOption).toBeVisible();
await expect(
codeBlockController.codeOption.locator('icon-button')
).toHaveCount(2);
await expect(codeBlockController.copyButton).toBeVisible();
await expect(codeBlockController.wrapButton).toBeHidden();
await expect(codeBlockController.deleteButton).toBeHidden();
});

test('should code block lang input supports alias', async ({ page }) => {
Expand Down
1 change: 1 addition & 0 deletions tests/format-bar.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1318,6 +1318,7 @@ test('should format quick bar show after convert to code block', async ({
<affine:code
prop:language="Plain Text"
prop:text="123\n456\n789"
prop:wrap={false}
/>
</affine:note>`,
noteId
Expand Down

0 comments on commit 3274a6c

Please sign in to comment.