Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: html inline node #105

Merged
merged 3 commits into from
Sep 22, 2024
Merged
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
2 changes: 1 addition & 1 deletion .github/workflows/test-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
run: yarn test:coverage

- name: Upload coverage
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: coverage
path: coverage/
Expand Down
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.1.0-beta.2",
"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.36"
}
}
1 change: 1 addition & 0 deletions src/editor/components/ErrorBoundary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

render() {
if (this.state.hasError) {
console.error(this.props.error)

Check warning on line 33 in src/editor/components/ErrorBoundary.tsx

View check run for this annotation

Codecov / codecov/patch

src/editor/components/ErrorBoundary.tsx#L33

Added line #L33 was not covered by tests
return (
<>
<Title data-testid='editor_error'>Sorry, something went wrong!</Title>
Expand Down
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 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 @@
alignItems: 'center',
}}
>
<Loading3QuartersOutlined spin size={40} />
<Icon.Loading3QuartersOutlined spin size={40} />

Check warning on line 85 in src/editor/components/Preview/preview.tsx

View check run for this annotation

Codecov / codecov/patch

src/editor/components/Preview/preview.tsx#L85

Added line #L85 was not covered by tests
</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 @@
codeEditor?: boolean
}

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

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

Check warning on line 16 in src/editor/components/Text/index.tsx

View check run for this annotation

Codecov / codecov/patch

src/editor/components/Text/index.tsx#L15-L16

Added lines #L15 - L16 were not covered by tests
return (
<div {...props} {...getRootProps()} spellCheck={false} >
<div {...props} {...rootProps} spellCheck={false} >

Check warning on line 18 in src/editor/components/Text/index.tsx

View check run for this annotation

Codecov / codecov/patch

src/editor/components/Text/index.tsx#L18

Added line #L18 was not covered by tests
{children}
</div>
)
}
})

Check warning on line 22 in src/editor/components/Text/index.tsx

View check run for this annotation

Codecov / codecov/patch

src/editor/components/Text/index.tsx#L22

Added line #L22 was not covered by tests

export default Text
20 changes: 18 additions & 2 deletions src/editor/extensions/HtmlBr/br-extension.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import type { ApplySchemaAttributes, NodeExtensionSpec, NodeSpecOverride } from '@remirror/core'
import { extension, ExtensionTag, NodeExtension } from '@remirror/core'
import type {
ApplySchemaAttributes,
InputRule,
NodeExtensionSpec,
NodeSpecOverride,
} from '@remirror/core'
import { extension, ExtensionTag, NodeExtension, nodeInputRule } from '@remirror/core'
import type { NodeSerializerOptions } from '@/editor/transform'
import { ParserRuleType } from '@/editor/transform'

Expand Down Expand Up @@ -37,6 +42,17 @@
}
}

createInputRules(): InputRule[] {
const rules: InputRule[] = [
nodeInputRule({
regexp: new RegExp('<br/>'),
type: this.type,
}),
]

return rules
}

Check warning on line 54 in src/editor/extensions/HtmlBr/br-extension.ts

View check run for this annotation

Codecov / codecov/patch

src/editor/extensions/HtmlBr/br-extension.ts#L46-L54

Added lines #L46 - L54 were not covered by tests

public fromMarkdown() {
return [
{
Expand Down
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
}

Check warning on line 62 in src/editor/extensions/HtmlNode/html-inline-node.tsx

View check run for this annotation

Codecov / codecov/patch

src/editor/extensions/HtmlNode/html-inline-node.tsx#L61-L62

Added lines #L61 - L62 were not covered by tests

createTags() {
return [ExtensionTag.InlineNode]
}

Check warning on line 66 in src/editor/extensions/HtmlNode/html-inline-node.tsx

View check run for this annotation

Codecov / codecov/patch

src/editor/extensions/HtmlNode/html-inline-node.tsx#L65-L66

Added lines #L65 - L66 were not covered by tests

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
},
}
}

Check warning on line 94 in src/editor/extensions/HtmlNode/html-inline-node.tsx

View check run for this annotation

Codecov / codecov/patch

src/editor/extensions/HtmlNode/html-inline-node.tsx#L69-L94

Added lines #L69 - L94 were not covered by tests

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

Check warning on line 98 in src/editor/extensions/HtmlNode/html-inline-node.tsx

View check run for this annotation

Codecov / codecov/patch

src/editor/extensions/HtmlNode/html-inline-node.tsx#L97-L98

Added lines #L97 - L98 were not covered by tests

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
}

Check warning on line 141 in src/editor/extensions/HtmlNode/html-inline-node.tsx

View check run for this annotation

Codecov / codecov/patch

src/editor/extensions/HtmlNode/html-inline-node.tsx#L101-L141

Added lines #L101 - L141 were not covered by tests

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

Check warning on line 151 in src/editor/extensions/HtmlNode/html-inline-node.tsx

View check run for this annotation

Codecov / codecov/patch

src/editor/extensions/HtmlNode/html-inline-node.tsx#L144-L151

Added lines #L144 - L151 were not covered by tests

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

Check warning on line 155 in src/editor/extensions/HtmlNode/html-inline-node.tsx

View check run for this annotation

Codecov / codecov/patch

src/editor/extensions/HtmlNode/html-inline-node.tsx#L154-L155

Added lines #L154 - L155 were not covered by tests
}
Loading
Loading