Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
660 changes: 447 additions & 213 deletions package-lock.json

Large diffs are not rendered by default.

21 changes: 11 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,16 @@
"@codemirror/merge": "^6.4.0",
"@codemirror/state": "^6.4.0",
"@codemirror/view": "^6.23.0",
"@lexical/clipboard": "^0.35.0",
"@lexical/link": "^0.35.0",
"@lexical/list": "^0.35.0",
"@lexical/markdown": "^0.35.0",
"@lexical/plain-text": "^0.35.0",
"@lexical/react": "^0.35.0",
"@lexical/rich-text": "^0.35.0",
"@lexical/selection": "^0.35.0",
"@lexical/utils": "^0.35.0",
"@lexical/clipboard": "^0.48.0",
"@lexical/extension": "^0.48.0",
"@lexical/link": "^0.48.0",
"@lexical/list": "^0.48.0",
"@lexical/markdown": "^0.48.0",
"@lexical/plain-text": "^0.48.0",
"@lexical/react": "^0.48.0",
"@lexical/rich-text": "^0.48.0",
"@lexical/selection": "^0.48.0",
"@lexical/utils": "^0.48.0",
"@mdxeditor/gurx": "^1.2.4",
"@radix-ui/colors": "^3.0.0",
"@radix-ui/react-dialog": "^1.1.11",
Expand All @@ -68,7 +69,7 @@
"codemirror": "^6.0.1",
"downshift": "^7.6.0",
"js-yaml": "4.2.0",
"lexical": "^0.35.0",
"lexical": "^0.48.0",
"mdast-util-directive": "^3.0.0",
"mdast-util-from-markdown": "^2.0.0",
"mdast-util-frontmatter": "^2.0.1",
Expand Down
21 changes: 3 additions & 18 deletions src/MDXEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useCellValue, useCellValues, usePublisher, useRealm } from '@mdxeditor/
import React, { JSX } from 'react'
import {
activeEditor$,
activePlugins$,
AdditionalLexicalNode,
bottomAreaChildren$,
composerChildren$,
Expand All @@ -10,19 +11,14 @@ import {
corePlugin,
editorRootElementRef$,
editorWrappers$,
exportVisitors$,
insertMarkdown$,
jsxComponentDescriptors$,
jsxIsAvailable$,
markdown$,
markdownSourceEditorValue$,
placeholder$,
rootEditor$,
contentEditableWrapperElement$,
setMarkdown$,
spellCheck$,
toMarkdownExtensions$,
toMarkdownOptions$,
topAreaChildren$,
Translation,
useTranslation,
Expand Down Expand Up @@ -271,20 +267,9 @@ const Methods: React.FC<{ mdxRef: React.ForwardedRef<MDXEditorMethods> }> = ({ m
return ''
}

// Get all export parameters from realm
const visitors = realm.getValue(exportVisitors$)
const toMarkdownExtensions = realm.getValue(toMarkdownExtensions$)
const toMarkdownOptions = realm.getValue(toMarkdownOptions$)
const jsxComponentDescriptors = realm.getValue(jsxComponentDescriptors$)
const jsxIsAvailable = realm.getValue(jsxIsAvailable$)
const activePlugins = realm.getValue(activePlugins$)

return getSelectionAsMarkdown(activeEditor, {
visitors,
toMarkdownExtensions,
toMarkdownOptions,
jsxComponentDescriptors,
jsxIsAvailable
})
return getSelectionAsMarkdown(activeEditor, activePlugins)
}
}
},
Expand Down
8 changes: 6 additions & 2 deletions src/mdastUtilHtmlComment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@
import type { Handle, Transform } from 'mdast-util-from-markdown'
import { factorySpace } from 'micromark-factory-space'
import { markdownLineEnding } from 'micromark-util-character'
import { codes, types } from 'micromark-util-symbol'
import { codes as rawCodes, types as rawTypes } from 'micromark-util-symbol'

import type { Code, Extension, Tokenizer } from 'micromark-util-types'
import type { Code, Extension, Tokenizer, TokenType } from 'micromark-util-types'

// Type these to avoid moduleResolution issues
const codes = rawCodes as Record<string, Code>
const types = rawTypes as Record<string, TokenType>

declare module 'micromark-util-types' {
interface TokenTypeMap {
Expand Down
4 changes: 2 additions & 2 deletions src/plugins/codeblock/CodeBlockNode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ export class CodeBlockNode extends DecoratorNode<JSX.Element> {
this.__focusEmitter = voidEmitter()
}

static importJSON(serializedNode: SerializedCodeBlockNode): CodeBlockNode {
const { code, meta, language } = serializedNode
static importJSON(serializedNode: SerializedLexicalNode & Record<string, unknown>): CodeBlockNode {
const { code, meta, language } = serializedNode as unknown as SerializedCodeBlockNode
return $createCodeBlockNode({
code,
language,
Expand Down
27 changes: 3 additions & 24 deletions src/plugins/markdown-shortcut/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ import {
} from '@lexical/markdown'
import { MarkdownShortcutPlugin } from '@lexical/react/LexicalMarkdownShortcutPlugin'
import { $createHeadingNode, $isHeadingNode, HeadingNode, HeadingTagType } from '@lexical/rich-text'
import { ElementNode, LexicalNode } from 'lexical'
import { ElementNode } from 'lexical'
import { realmPlugin } from '../../RealmWithPlugins'
import { $createCodeBlockNode, CodeBlockNode } from '../codeblock/CodeBlockNode'
import { activePlugins$, addComposerChild$, addNestedEditorChild$, addTableCellEditorChild$ } from '../core'
import { HEADING_LEVEL, allowedHeadingLevels$ } from '../headings'
import { $createHorizontalRuleNode, $isHorizontalRuleNode, HorizontalRuleNode } from '@lexical/react/LexicalHorizontalRuleNode'
import { THEMATIC_BREAK_TRANSFORMER } from '../thematic-break/transformer'

/**
* A plugin that adds markdown shortcuts to the editor.
Expand Down Expand Up @@ -53,27 +53,6 @@ const createBlockNode = (createNode: (match: string[]) => ElementNode): ElementT
}
}

const THEMATIC_BREAK: ElementTransformer = {
dependencies: [HorizontalRuleNode],
export: (node: LexicalNode) => {
return $isHorizontalRuleNode(node) ? '***' : null
},
regExp: /^(---|\*\*\*|___)\s?$/,
replace: (parentNode, _1, _2, isImport) => {
const line = $createHorizontalRuleNode()

// TODO: Get rid of isImport flag
if (isImport || parentNode.getNextSibling() != null) {
parentNode.replace(line)
} else {
parentNode.insertBefore(line)
}

line.selectNext()
},
type: 'element'
}

const LIST_TRANSFORMERS: ReadonlySet<Transformer> = new Set([ORDERED_LIST, UNORDERED_LIST, CHECK_LIST])

function pickTransformersForActivePlugins(pluginIds: string[], allowedHeadingLevels: readonly HEADING_LEVEL[]) {
Expand Down Expand Up @@ -116,7 +95,7 @@ function pickTransformersForActivePlugins(pluginIds: string[], allowedHeadingLev
}

if (pluginIds.includes('thematicBreak')) {
transformers.push(THEMATIC_BREAK)
transformers.push(THEMATIC_BREAK_TRANSFORMER)
}

if (pluginIds.includes('quote')) {
Expand Down
11 changes: 10 additions & 1 deletion src/plugins/table/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,20 @@ import * as Mdast from 'mdast'
import { gfmTableFromMarkdown, gfmTableToMarkdown, Options as GfmTableOptions } from 'mdast-util-gfm-table'
import { gfmTable } from 'micromark-extension-gfm-table'
import {
addActivePlugin$,
addExportVisitor$,
addImportVisitor$,
addLexicalNode$,
addMdastExtension$,
addSyntaxExtension$,
addToMarkdownExtension$,
insertDecoratorNode$
insertDecoratorNode$,
toMarkdownExtensions$
} from '../core'
import { LexicalTableVisitor } from './LexicalTableVisitor'
import { MdastTableVisitor } from './MdastTableVisitor'
import { $createTableNode, TableNode } from './TableNode'
import { setTableTransformerExtensions } from './transformer'
export * from './TableNode'

function seedTable(rows = 1, columns = 1): Mdast.Table {
Expand Down Expand Up @@ -82,6 +85,7 @@ export const insertTable$ = Signal<{
export const tablePlugin = realmPlugin<GfmTableOptions>({
init(realm, params) {
realm.pubIn({
[addActivePlugin$]: 'table',
// import
[addMdastExtension$]: gfmTableFromMarkdown(),
[addSyntaxExtension$]: gfmTable(),
Expand All @@ -94,5 +98,10 @@ export const tablePlugin = realmPlugin<GfmTableOptions>({
tablePipeAlign: params?.tablePipeAlign ?? true
})
})

// Subscribe to toMarkdownExtensions$ to keep the transformer in sync with active extensions
realm.sub(toMarkdownExtensions$, (extensions) => {
setTableTransformerExtensions(extensions)
})
}
})
42 changes: 42 additions & 0 deletions src/plugins/table/transformer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { type ElementTransformer } from '@lexical/markdown'
import { type LexicalNode } from 'lexical'
import { $isTableNode, TableNode } from './TableNode'
import { toMarkdown } from 'mdast-util-to-markdown'
import { ToMarkdownExtension } from '../../exportMarkdownFromLexical'

let cachedExtensions: ToMarkdownExtension[] = []

/**
* Update the cached markdown extensions used by the table transformer.
* Called by the table plugin when extensions change.
*/
export function setTableTransformerExtensions(extensions: ToMarkdownExtension[]) {
cachedExtensions = extensions
}

/**
* Transformer for table nodes.
* Exports TableNode to GFM (GitHub Flavored Markdown) table syntax.
*/
export const TABLE_TRANSFORMER: ElementTransformer = {
dependencies: [TableNode],
export: (node: LexicalNode) => {
if ($isTableNode(node)) {
const mdastTable = node.getMdastNode()

try {
return toMarkdown(mdastTable, {
// Use cached extensions that are set by the plugin
extensions: cachedExtensions
})
} catch (e) {
console.error('Failed to export table node:', e)
return null
}
}
return null
},
regExp: /^\|.+\|.*/,
replace: () => false,
type: 'element'
}
2 changes: 1 addition & 1 deletion src/plugins/thematic-break/LexicalThematicBreakVisitor.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { $isHorizontalRuleNode, HorizontalRuleNode } from '@lexical/react/LexicalHorizontalRuleNode.js'
import { $isHorizontalRuleNode, HorizontalRuleNode } from '@lexical/extension'
import * as Mdast from 'mdast'
import { LexicalExportVisitor } from '../../exportMarkdownFromLexical'

Expand Down
2 changes: 2 additions & 0 deletions src/plugins/thematic-break/MdastThematicBreakVisitor.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
// eslint-disable-next-line @typescript-eslint/no-deprecated
import { $createHorizontalRuleNode } from '@lexical/react/LexicalHorizontalRuleNode.js'
import * as Mdast from 'mdast'
import { MdastImportVisitor } from '../../importMarkdownToLexical'

export const MdastThematicBreakVisitor: MdastImportVisitor<Mdast.ThematicBreak> = {
testNode: 'thematicBreak',
visitNode({ actions }) {
// eslint-disable-next-line @typescript-eslint/no-deprecated
actions.addAndStepInto($createHorizontalRuleNode())
}
}
9 changes: 7 additions & 2 deletions src/plugins/thematic-break/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { realmPlugin } from '../../RealmWithPlugins'
import { HorizontalRuleNode, INSERT_HORIZONTAL_RULE_COMMAND } from '@lexical/react/LexicalHorizontalRuleNode.js'
import { HorizontalRulePlugin } from '@lexical/react/LexicalHorizontalRulePlugin.js'
import { INSERT_HORIZONTAL_RULE_COMMAND } from '@lexical/extension'
// eslint-disable-next-line @typescript-eslint/no-deprecated
import { HorizontalRuleNode } from '@lexical/react/LexicalHorizontalRuleNode'
// eslint-disable-next-line @typescript-eslint/no-deprecated
import { HorizontalRulePlugin } from '@lexical/react/LexicalHorizontalRulePlugin'
import { Action, withLatestFrom } from '@mdxeditor/gurx'
import { activeEditor$, addActivePlugin$, addComposerChild$, addExportVisitor$, addImportVisitor$, addLexicalNode$ } from '../core'
import { LexicalThematicBreakVisitor } from './LexicalThematicBreakVisitor'
Expand All @@ -25,8 +28,10 @@ export const thematicBreakPlugin = realmPlugin({
realm.pubIn({
[addActivePlugin$]: 'thematicBreak',
[addImportVisitor$]: MdastThematicBreakVisitor,
// eslint-disable-next-line @typescript-eslint/no-deprecated
[addLexicalNode$]: HorizontalRuleNode,
[addExportVisitor$]: LexicalThematicBreakVisitor,
// eslint-disable-next-line @typescript-eslint/no-deprecated
[addComposerChild$]: HorizontalRulePlugin
})
}
Expand Down
32 changes: 32 additions & 0 deletions src/plugins/thematic-break/transformer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { type ElementTransformer } from '@lexical/markdown'
import { $isHorizontalRuleNode } from '@lexical/react/LexicalHorizontalRuleNode'
// eslint-disable-next-line @typescript-eslint/no-deprecated
import { $createHorizontalRuleNode, HorizontalRuleNode } from '@lexical/react/LexicalHorizontalRuleNode'
import { type LexicalNode } from 'lexical'

/**
* Transformer for thematic break (horizontal rule) nodes.
* Exports HorizontalRuleNode as "***" (thematic break).
*/
export const THEMATIC_BREAK_TRANSFORMER: ElementTransformer = {
// eslint-disable-next-line @typescript-eslint/no-deprecated
dependencies: [HorizontalRuleNode],
export: (node: LexicalNode) => {
return $isHorizontalRuleNode(node) ? '***' : null
},
regExp: /^(---|\*\*\*|___)\s?$/,
replace: (parentNode, _1, _2, isImport) => {
// eslint-disable-next-line @typescript-eslint/no-deprecated
const line = $createHorizontalRuleNode()

// TODO: Get rid of isImport flag
if (isImport || parentNode.getNextSibling() != null) {
parentNode.replace(line)
} else {
parentNode.insertBefore(line)
}

line.selectNext()
},
type: 'element'
}
Loading