@eventcatalogtest/studio
Version:
A drag and drop UI for distributed systems that keeps your diagrams where they belong – in your repo
90 lines (71 loc) • 2.4 kB
text/typescript
import { Editor, Range, Transforms, Element, Point, Text } from 'slate'
import { ReactEditor } from 'slate-react'
export interface MentionElement {
type: 'mention'
nodeId: string
nodeType: string
children: { text: string }[]
}
// Helper to check if a node is a mention
export const isMentionElement = (element: any): element is MentionElement => {
return element.type === 'mention'
}
// Find mentions in text
export const withMentions = (editor: Editor) => {
const { isInline, isVoid, markableVoid } = editor
editor.isInline = element => {
return element.type === 'mention' ? true : isInline(element)
}
editor.isVoid = element => {
return element.type === 'mention' ? true : isVoid(element)
}
editor.markableVoid = element => {
return element.type === 'mention' || markableVoid(element)
}
return editor
}
// Get current mention search
export const getMentionSearch = (editor: Editor): { range: Range; search: string } | null => {
const { selection } = editor
if (!selection || !Range.isCollapsed(selection)) {
return null
}
const [start] = Range.edges(selection)
// Get text before cursor (up to 20 characters to find @)
const beforeRange = {
anchor: Editor.before(editor, start, { distance: 20, unit: 'character' }) || Editor.start(editor, []),
focus: start,
}
const beforeText = Editor.string(editor, beforeRange)
// Look for @ followed by word characters at the end of the text
const match = beforeText.match(/@(\w*)$/)
if (match) {
const matchStart = beforeText.lastIndexOf(match[0])
const matchRange = {
anchor: Editor.before(editor, start, { distance: beforeText.length - matchStart, unit: 'character' }) || start,
focus: start,
}
return {
range: matchRange,
search: match[1] || ''
}
}
return null
}
// Insert mention
export const insertMention = (editor: Editor, nodeId: string, nodeType: string, nodeName: string) => {
const mention: MentionElement = {
type: 'mention',
nodeId,
nodeType,
children: [{ text: '' }]
}
const mentionSearch = getMentionSearch(editor)
if (mentionSearch) {
// Replace the @ and search text with the mention
Transforms.select(editor, mentionSearch.range)
Transforms.insertNodes(editor, mention)
Transforms.insertText(editor, ` ${nodeName} `)
Transforms.move(editor)
}
}