feat(workspace): add line numbers and horizontal scrolling to code block editor

This commit is contained in:
sandrodach committed 2026-10-30 16:17:17 +01:00
1 parent 108ac6621c
commit 1d6863824b
3 files changed
+132 -34

No files matched your search

@@ -209,4 +209,55 @@ describe('CodeBlockEditor', () => {
expect(res2.updates[res2.updates.length - 1]?.type).toBe('code');
expect(res2.updates[res2.updates.length - 1]?.lang).toBe('json');
});
it('renders line numbers column with aria-hidden, user-select: none, and correct line count including trailing empty lines and 100+ lines', () => {
// 1. Single empty line
const { container, rerender } = render(
<CodeBlockEditor block={makeCodeBlock({ id: 'code-empty', content: '' })} content="" canEdit />
);
const getLineContainer = () => container.querySelector('[data-testid="code-line-numbers"]') as HTMLElement;
expect(getLineContainer()).toBeTruthy();
expect(getLineContainer().getAttribute('aria-hidden')).toBe('true');
expect(getLineContainer().className).toContain('select-none');
let lineEls = container.querySelectorAll('[data-line-number]');
expect(lineEls).toHaveLength(1);
expect(lineEls[0].textContent?.trim()).toBe('1');
// 2. Trailing empty line gives an extra line number (e.g. line 1 + empty line 2)
rerender(
<CodeBlockEditor
block={makeCodeBlock({ id: 'code-trailing', content: `first line
` })}
content={`first line
`}
canEdit
/>
);
lineEls = container.querySelectorAll('[data-line-number]');
expect(lineEls).toHaveLength(2);
expect(lineEls[0].textContent?.trim()).toBe('1');
expect(lineEls[1].textContent?.trim()).toBe('2');
// 3. 120 lines (100+ lines test)
const longCode = Array.from({ length: 120 }, (_, i) => `const x_${i + 1} = ${i + 1};`).join('\n');
rerender(
<CodeBlockEditor
block={makeCodeBlock({ id: 'code-long', content: longCode })}
content={longCode}
canEdit
/>
);
lineEls = container.querySelectorAll('[data-line-number]');
expect(lineEls).toHaveLength(120);
expect(lineEls[0].textContent?.trim()).toBe('1');
expect(lineEls[99].textContent?.trim()).toBe('100');
expect(lineEls[119].textContent?.trim()).toBe('120');
// Textarea has whitespace-pre and overlay has whitespace-pre
const textarea = container.querySelector('textarea') as HTMLTextAreaElement;
const pre = container.querySelector('pre') as HTMLPreElement;
expect(textarea.className).toContain('whitespace-pre');
expect(pre.className).toContain('whitespace-pre');
});
});