Skip to content

Commit

Permalink
refactor: html inline node
Browse files Browse the repository at this point in the history
  • Loading branch information
drl990114 committed Aug 26, 2024
1 parent d61c5a1 commit f762805
Show file tree
Hide file tree
Showing 13 changed files with 941 additions and 119 deletions.
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "rme",
"version": "0.0.73",
"version": "0.0.74",
"type": "module",
"scripts": {
"build": "yarn clear && yarn build-esbuild && yarn types",
Expand Down Expand Up @@ -146,6 +146,7 @@
"@remirror/react-core": "^2.0.18",
"@remirror/theme": "^2.0.8",
"@remirror/types": "^1.0.1",
"@uiw/react-codemirror": "^4.23.0",
"color": "^4.2.3",
"create-context-state": "^2.0.0",
"fuse.js": "^7.0.0",
Expand Down Expand Up @@ -177,6 +178,6 @@
"svgmoji": "^3.2.0",
"void-elements": "^3.1.0",
"yjs": "^13.6.14",
"zens": "^0.0.33"
"zens": "^0.0.35"
}
}
4 changes: 2 additions & 2 deletions src/editor/components/Preview/preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { createWysiwygDelegate } from '../WysiwygEditor'
import HTML from 'html-parse-stringify'
import { useEffect, useState } from 'react'
import { nanoid } from 'nanoid'
import { Loading3QuartersOutlined } from 'zens/esm/Icons'
import { Icon } from 'zens'

interface PreviewProps {
doc: Node | string
Expand Down Expand Up @@ -82,7 +82,7 @@ export const Preview: React.FC<PreviewProps> = (props) => {
alignItems: 'center',
}}
>
<Loading3QuartersOutlined spin size={40} />
<Icon.Loading3QuartersOutlined spin size={40} />
</div>
)
}
Expand Down
10 changes: 6 additions & 4 deletions src/editor/components/Text/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useRemirrorContext } from '@remirror/react'
import type { CSSProperties, FC } from 'react'
import React from 'react'
import React, { memo } from 'react'

interface ITextProps {
children?: React.ReactNode
Expand All @@ -9,14 +9,16 @@ interface ITextProps {
codeEditor?: boolean
}

const Text: FC<ITextProps> = ({ children, ...props }) => {
const Text: FC<ITextProps> = memo(({ children, ...props }) => {
const { getRootProps } = useRemirrorContext()

const { key, ...rootProps} = getRootProps()

return (
<div {...props} {...getRootProps()} spellCheck={false} >
<div {...props} {...rootProps} spellCheck={false} >
{children}
</div>
)
}
})

export default Text
156 changes: 156 additions & 0 deletions src/editor/extensions/HtmlNode/html-inline-node.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
import { NodeSerializerOptions, ParserRuleType } from '@/editor/transform'
import { getAttrsBySignalHtmlContent, getTagName, isImageElement } from '@/editor/utils/html'
import { EditorState, PluginKey, TextSelection } from '@remirror/pm/state'
import { EditorView } from '@remirror/pm/view'
import { NodeViewComponentProps } from '@remirror/react'
import ReactCodeMirror from '@uiw/react-codemirror'
import { ComponentType, useEffect, useRef, useState } from 'react'
import type {
ApplySchemaAttributes,
CreateExtensionPlugin,
InputRule,
MarkExtensionSpec,
NodeExtensionSpec,
NodeSpecOverride,
NodeViewMethod,
} from 'remirror'
import {
ExtensionTag,
MarkExtension,
NodeExtension,
extension,
nodeInputRule,
plainInputRule,
prosemirrorNodeToDom,
} from 'remirror'
import { HTMLInlineView } from './html-inline-view'
import {
excludeHtmlInlineNodes,
needSplitInlineHtmlTokenTags,
} from '@/editor/transform/markdown-it-html-inline'
import block_names from 'markdown-it/lib/common/html_blocks.mjs'

const attr_name = '[a-zA-Z_:][a-zA-Z0-9:._-]*'

const unquoted = '[^"\'=<>`\\x00-\\x20]+'
const single_quoted = "'[^']*'"
const double_quoted = '"[^"]*"'

const attr_value = '(?:' + unquoted + '|' + single_quoted + '|' + double_quoted + ')'

const attribute = '(?:\\s+' + attr_name + '(?:\\s*=\\s*' + attr_value + ')?)'

const open_tag = '<[A-Za-z][A-Za-z0-9\\-]*' + attribute + '*\\s*\\/?>'

const close_tag = '<\\/[A-Za-z][A-Za-z0-9\\-]*\\s*>'

const HTML_OPEN_CLOSE_TAG_RE = new RegExp('(?:' + open_tag + '|' + close_tag + ')', 'g')

type LineHtmlInlineExtensionOptions = {
handleViewImgSrcUrl?: (src: string) => Promise<string>
}
@extension<LineHtmlInlineExtensionOptions>({
defaultOptions: {
handleViewImgSrcUrl: async (src: string) => src,
},
})
export class HtmlInlineNodeExtension extends NodeExtension<LineHtmlInlineExtensionOptions> {
static disableExtraAttributes = true

get name() {
return 'html_inline_node' as const
}

createTags() {
return [ExtensionTag.InlineNode]
}

createNodeSpec(): NodeExtensionSpec {
return {
inline: true,
selectable: true,
atom: true,
marks: '',
attrs: {
key: {
default: '',
},
htmlText: {
default: '',
},
fromInput: {
default: false,
},
},
toDOM: (node) => {
const dom = document.createElement('div')

dom.classList.add('inline-html-render')
dom.innerHTML = node.attrs.htmlText

return dom
},
}
}

createNodeViews(): NodeViewMethod | Record<string, NodeViewMethod> {
return (node, view, getPos) => new HTMLInlineView(node, view, getPos)
}

createInputRules(): InputRule[] {
const rules: InputRule[] = [
nodeInputRule({
regexp: HTML_OPEN_CLOSE_TAG_RE,
type: this.type,
getAttributes: (match) => {
return {
htmlText: match[0],
fromInput: true,
}
},
beforeDispatch: ({ tr, start, match }) => {
const $pos = tr.doc.resolve(start)
const node = $pos.node(1)
console.log('last', node.lastChild)

// if (node.lastChild?.type.name === 'html_inline_node') {
// tr.setNodeAttribute(start, 'fromInput', true )
// }
console.log('node', node)
// tr.setSelection(TextSelection.near($pos))
},
shouldSkip: (props) => {
const tagName = getTagName(props.fullMatch)

if (needSplitInlineHtmlTokenTags.includes(tagName) || block_names.includes(tagName)) {
return true
}

props.state.tr.replaceRangeWith(
props.start,
props.end,
this.type.create({ htmlText: props.fullMatch, fromInput: true }),
)

return false
},
}),
]

return rules
}

public fromMarkdown() {
return [
{
type: ParserRuleType.inline,
token: 'html_inline_node',
node: this.name,
},
] as const
}

public toMarkdown({ state, node }: NodeSerializerOptions) {
state.text(node.attrs.htmlText || '')
}
}
Loading

0 comments on commit f762805

Please sign in to comment.