Skip to content

Commit

Permalink
feat: maxLengthPlugin
Browse files Browse the repository at this point in the history
Fixes #345
  • Loading branch information
petyosi committed Feb 3, 2024
1 parent 4aa63e3 commit 95092a2
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 0 deletions.
6 changes: 6 additions & 0 deletions src/examples/maxlength.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import React from 'react'
import { maxLengthPlugin, MDXEditor } from '..'

export function Bare() {
return <MDXEditor plugins={[maxLengthPlugin(100)]} autoFocus={true} markdown={'hello world'} onChange={console.log} />
}
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export * from './plugins/link'
export * from './plugins/image'
export * from './plugins/frontmatter'
export * from './plugins/quote'
export * from './plugins/maxlength'

// JSX
export * from './plugins/jsx'
Expand Down
47 changes: 47 additions & 0 deletions src/plugins/maxlength/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { trimTextContentFromAnchor } from '@lexical/selection'
import { $restoreEditorState } from '@lexical/utils'
import { $getSelection, $isRangeSelection, EditorState, RootNode } from 'lexical'
import { realmPlugin } from '../../RealmWithPlugins'
import { createRootEditorSubscription$ } from '../core'

/**
* A plugin that limits the maximum length of the text content of the editor.
* Adapted from the Lexical plugin. https://github.com/facebook/lexical/blob/main/packages/lexical-playground/src/plugins/MaxLengthPlugin/index.tsx
* @example
* ```tsx
* <MDXEditor plugins={[maxLengthPlugin(100)]} markdown={'hello world'} />
* ```
* @group Utilities
*/
export const maxLengthPlugin = realmPlugin<number>({
init: (realm, maxLength = Infinity) => {
realm.pub(createRootEditorSubscription$, (editor) => {
let lastRestoredEditorState: EditorState | null = null

return editor.registerNodeTransform(RootNode, (rootNode: RootNode) => {
const selection = $getSelection()
if (!$isRangeSelection(selection) || !selection.isCollapsed()) {
return
}
const prevEditorState = editor.getEditorState()
const prevTextContentSize = prevEditorState.read(() => rootNode.getTextContentSize())
const textContentSize = rootNode.getTextContentSize()
if (prevTextContentSize !== textContentSize) {
const delCount = textContentSize - maxLength
const anchor = selection.anchor

if (delCount > 0) {
// Restore the old editor state instead if the last
// text content was already at the limit.
if (prevTextContentSize === maxLength && lastRestoredEditorState !== prevEditorState) {
lastRestoredEditorState = prevEditorState
$restoreEditorState(editor, prevEditorState)
} else {
trimTextContentFromAnchor(editor, anchor, delCount)
}
}
}
})
})
}
})

0 comments on commit 95092a2

Please sign in to comment.