mirror of
https://github.com/supabase/supabase.git
synced 2026-10-06 01:45:10 +03:00
## Context We've gotten some requests for a better markdown editing experience in the Explorer so this PR adds a proper live preview markdown editor, similar UX to how you'd edit notion or obsidian documents. Opting to use `lexical` as the main library to support this UI for its size and composability without going too low level like prose mirror <img width="933" height="452" alt="image" src="https://github.com/user-attachments/assets/7161ae6c-3dff-4b36-818f-01b5e573f121" /> Actual file changes are just this size excluding the package-lock <img width="150" height="39" alt="image" src="https://github.com/user-attachments/assets/bb01f2cf-8ef7-4daf-975b-614b2d817b54" /> ## Changes involved This adjusts the UX for markdown cells a little - Clicking on a markdown cell immediately allows you to edit - Instead of the existing behaviour which requires a double click to enter "Edit" state - Editing doesn't eject you into a monaco editor, but rather inline editor - Nicer transition - Clicking out of the cell persists the cell's content - No more "Cancel" or "Save" buttons ## To test - [ ] Verify that editing markdown cells are still working - [ ] Verify that tabs do get marked with unsaved changes if you edit a markdown cell <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Replaced the previous Markdown editing workflow with an always-visible inline editor. - Added rich Markdown editing for headings, lists, links, blockquotes, code blocks, inline code, and text formatting. - Changes are saved automatically when leaving the editor. - Markdown formatting shortcuts take precedence within the editor. - **Bug Fixes** - Avoids unnecessary saves when content has not changed. - **Tests** - Added coverage verifying Markdown formatting conversions remain consistent and repeatable. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
51 lines
1.7 KiB
TypeScript
51 lines
1.7 KiB
TypeScript
import { createHeadlessEditor } from '@lexical/headless'
|
|
import { $convertFromMarkdownString, $convertToMarkdownString } from '@lexical/markdown'
|
|
import { describe, expect, it } from 'vitest'
|
|
|
|
import { MARKDOWN_EDITOR_NODES, MARKDOWN_TRANSFORMERS } from './MarkdownEditor.utils'
|
|
|
|
function roundTrip(markdown: string): string {
|
|
const editor = createHeadlessEditor({
|
|
nodes: MARKDOWN_EDITOR_NODES,
|
|
onError: (error) => {
|
|
throw error
|
|
},
|
|
})
|
|
editor.update(() => $convertFromMarkdownString(markdown, MARKDOWN_TRANSFORMERS), {
|
|
discrete: true,
|
|
})
|
|
|
|
let result = ''
|
|
editor.getEditorState().read(() => {
|
|
result = $convertToMarkdownString(MARKDOWN_TRANSFORMERS)
|
|
})
|
|
return result
|
|
}
|
|
|
|
describe('MarkdownEditor markdown <-> editor state round trip', () => {
|
|
it.each([
|
|
['heading', '# Heading one'],
|
|
['sub-heading', '## Heading two'],
|
|
['bold', 'Some **bold** text'],
|
|
['italic', 'Some *italic* text'],
|
|
['strikethrough', 'Some ~~struck out~~ text'],
|
|
['inline code', 'Some `inline code` text'],
|
|
['blockquote', '> A quote'],
|
|
['unordered list', '- one\n- two\n- three'],
|
|
['ordered list', '1. one\n2. two\n3. three'],
|
|
['link', '[Supabase](https://supabase.com)'],
|
|
['fenced code block', '```\nconst x = 1\n```'],
|
|
['fenced code block with language', '```ts\nconst x = 1\n```'],
|
|
])('round-trips %s unchanged', (_name, markdown) => {
|
|
expect(roundTrip(markdown)).toBe(markdown)
|
|
})
|
|
|
|
it('is idempotent on a second round trip', () => {
|
|
const markdown =
|
|
'# Title\n\nSome **bold** and *italic* text with a [link](https://supabase.com).\n\n- one\n- two'
|
|
const once = roundTrip(markdown)
|
|
const twice = roundTrip(once)
|
|
expect(twice).toBe(once)
|
|
})
|
|
})
|