Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
156 commits
Select commit Hold shift + click to select a range
a80874c
feat: expand native editor fidelity
Chefski Jun 28, 2026
95e01db
fix: preserve overlapping inline comments
Chefski Jun 28, 2026
d80e892
fix: make inline comment marks nonisolated
Chefski Jun 28, 2026
431286b
fix: make prose mirror decoding budget nonisolated
Chefski Jun 28, 2026
2e5191b
fix: resolve strict concurrency compile errors
Chefski Jun 28, 2026
f35d489
Merge remote-tracking branch 'origin/dev' into codex/editor-fidelity-…
Chefski Jun 28, 2026
e680628
fix: return decoded table cells explicitly
Chefski Jun 28, 2026
f614ed7
feat: import markdown media links as native blocks
Chefski Jun 28, 2026
0b5f5b9
fix: isolate markdown import tests to main actor
Chefski Jun 28, 2026
2eafcbd
fix: stabilize editor inline atom encoding
Chefski Jun 28, 2026
34c38f9
test: cover inline markdown marks around atoms
Chefski Jun 28, 2026
9c335d9
fix: preserve inline marks around pasted atoms
Chefski Jun 28, 2026
bb72557
Merge remote-tracking branch 'origin/dev' into codex/editor-fidelity-…
Chefski Jun 28, 2026
6be3a98
feat: improve editor fidelity
Chefski Jun 28, 2026
a243429
fix: preserve markdown attachment ids
Chefski Jun 28, 2026
0def049
fix: support details markdown shortcut
Chefski Jun 28, 2026
231b5f9
fix: preserve user mention markdown
Chefski Jun 28, 2026
97fe3aa
fix: preserve inline comment markdown
Chefski Jun 28, 2026
b244c72
fix: match slash commands fuzzily
Chefski Jun 28, 2026
197817d
fix: align table slash command defaults
Chefski Jun 28, 2026
0f216c4
fix: support callout markdown shortcut
Chefski Jun 28, 2026
8cb18c4
fix: support math block markdown shortcut
Chefski Jun 28, 2026
fd026a1
fix: stabilize editor fidelity PR checks
Chefski Jun 28, 2026
a162c26
fix: rank slash command raw aliases after fuzzy titles
Chefski Jun 28, 2026
2afbd5f
fix: keep slash fuzzy matches visible
Chefski Jun 28, 2026
38c17ce
fix: serialize CRDT attachment tests
Chefski Jun 28, 2026
629b48c
fix: narrow no-factory CRDT test
Chefski Jun 28, 2026
05e748a
fix: support inline math input rule
Chefski Jun 28, 2026
15c62a0
test: cover slash menu code block gating
Chefski Jun 28, 2026
42bc426
fix: disable slash menu in code blocks
Chefski Jun 28, 2026
f7cdcc9
fix: require active slash query for command list
Chefski Jun 28, 2026
72c655d
test: cover image title markdown fidelity
Chefski Jun 28, 2026
500f18c
fix: preserve image markdown titles
Chefski Jun 28, 2026
a55cc49
test: cover iframe markdown embed import
Chefski Jun 28, 2026
d7b34da
test: cover iframe embed markdown export
Chefski Jun 28, 2026
fe85589
fix: preserve iframe embed markdown
Chefski Jun 28, 2026
5ee6573
test: cover markdown hard break import
Chefski Jun 28, 2026
2ab3a58
fix: preserve markdown hard breaks on import
Chefski Jun 28, 2026
5b1b0e7
fix: retain newlines in grouped markdown paragraphs
Chefski Jun 28, 2026
652fa94
test: cover status markdown fidelity
Chefski Jun 28, 2026
990a544
fix: preserve status atoms in markdown
Chefski Jun 28, 2026
32fa0cb
test: cover page break markdown fidelity
Chefski Jun 28, 2026
8f30637
fix: preserve page break markdown fidelity
Chefski Jun 28, 2026
90d5254
test: cover columns markdown fidelity
Chefski Jun 28, 2026
4b23139
fix: preserve columns markdown fidelity
Chefski Jun 28, 2026
761cabc
fix: avoid columns helper visibility collision
Chefski Jun 28, 2026
f0742fa
fix: type optional column width nil
Chefski Jun 28, 2026
eb667b6
fix: return parsed column widths
Chefski Jun 28, 2026
e083043
fix: close columns layout attribute
Chefski Jun 28, 2026
0dd4c66
fix: import legacy page breaks
Chefski Jun 28, 2026
003e7c6
test: cover diagram markdown fidelity
Chefski Jun 28, 2026
98adb75
fix: preserve diagram markdown fidelity
Chefski Jun 28, 2026
38e4593
test: cover columns normalization fidelity
Chefski Jun 28, 2026
0ab7c29
fix: normalize column block widths
Chefski Jun 28, 2026
2cbe1ed
test: cover media html fidelity
Chefski Jun 28, 2026
063c25a
fix: preserve media html fidelity
Chefski Jun 28, 2026
500eece
fix: remove duplicate media html escaping helper
Chefski Jun 28, 2026
20635c0
test: expect provider embed html export
Chefski Jun 28, 2026
a983fee
test: cover diagram html import edge cases
Chefski Jun 28, 2026
dfff871
fix: parse compact diagram html safely
Chefski Jun 28, 2026
3fdbe10
fix: preserve unsupported html as paragraph text
Chefski Jun 28, 2026
d6ddc4d
test: cover structural html block fidelity
Chefski Jun 28, 2026
e39546a
fix: preserve structural html blocks
Chefski Jun 28, 2026
1881299
fix: return structural markdown fallback
Chefski Jun 28, 2026
721b2c9
test: cover container html block fidelity
Chefski Jun 28, 2026
30226da
fix: preserve container html blocks
Chefski Jun 28, 2026
1adb9b4
test: cover compact media html import
Chefski Jun 28, 2026
df8a879
fix: import compact media html blocks
Chefski Jun 28, 2026
a4ad1c2
test: cover single segment file routes
Chefski Jun 28, 2026
a1031f8
fix: guard docmost attachment id routes
Chefski Jun 28, 2026
ebb828a
test: cover inline span comment import
Chefski Jun 28, 2026
302645b
fix: preserve inline comment span imports
Chefski Jun 28, 2026
4af924a
test: cover iframe markdown link fidelity
Chefski Jun 28, 2026
db0a0ae
fix: preserve iframe markdown links
Chefski Jun 28, 2026
72fe0dc
test: cover code slash cleanup
Chefski Jun 28, 2026
5395dc0
fix: clear code slash command text
Chefski Jun 28, 2026
eb4c0db
test: cover currency dollar markdown import
Chefski Jun 28, 2026
669626d
test: fix math markdown regression isolation
Chefski Jun 28, 2026
40265ab
fix: preserve currency dollars in markdown import
Chefski Jun 28, 2026
b8b96b3
fix: keep invalid inline math delimiters literal
Chefski Jun 28, 2026
fae9e25
test: assert currency import semantics
Chefski Jun 28, 2026
3151a8a
test: cover highlight markdown fidelity
Chefski Jun 28, 2026
c83824e
fix: preserve highlight markdown marks
Chefski Jun 28, 2026
1a4077d
test: cover text color markdown fidelity
Chefski Jun 28, 2026
86e1669
fix: preserve text color markdown marks
Chefski Jun 28, 2026
d11371b
test: cover relative table cell links
Chefski Jun 28, 2026
c84de04
fix: preserve relative table cell links
Chefski Jun 28, 2026
2ecb0c8
test: cover malformed status import recovery
Chefski Jun 28, 2026
65e951e
fix: recover after malformed status spans
Chefski Jun 28, 2026
8b47d57
test: cover image html title export
Chefski Jun 28, 2026
2445d47
fix: preserve image html titles
Chefski Jun 28, 2026
53111b2
test: cover details shortcut import
Chefski Jun 28, 2026
96f70c4
fix: import details shortcut after trimming
Chefski Jun 28, 2026
920049b
test: assert details shortcut encoded node
Chefski Jun 28, 2026
94eebc5
test: cover malformed column count clamp
Chefski Jun 28, 2026
0fb67c2
fix: clamp malformed columns normalization
Chefski Jun 28, 2026
286241f
test: cover slash word-start later match
Chefski Jun 28, 2026
3c00d10
fix: scan slash title word-start matches
Chefski Jun 28, 2026
350a05d
test: assert default table slash shape
Chefski Jun 28, 2026
84de1c7
test: cover markdown link title delimiters
Chefski Jun 28, 2026
456446e
test: run markdown link title tests on main actor
Chefski Jun 28, 2026
f5ee237
fix: parse common markdown link titles
Chefski Jun 28, 2026
af65b66
test: cover iconless callout html export
Chefski Jun 29, 2026
ca938ab
fix: export iconless callouts as docmost html
Chefski Jun 29, 2026
749b4a0
test: update rich markdown callout html fixture
Chefski Jun 29, 2026
f4855ac
test: cover nested docmost embed html import
Chefski Jun 29, 2026
3fdf2f0
fix: parse nested docmost media containers
Chefski Jun 29, 2026
815e4c6
test: cover locale independent html tag matching
Chefski Jun 29, 2026
5b44e0e
fix: make html tag matching locale independent
Chefski Jun 29, 2026
342ee29
fix: keep html tag matcher nonisolated
Chefski Jun 29, 2026
d33454b
fix: precompute markdown code spans
Chefski Jun 29, 2026
2a932b4
fix: skip code span html closures
Chefski Jun 29, 2026
c99ad61
test: cover table background color fidelity
Chefski Jun 29, 2026
afe1408
fix: preserve table cell background colors
Chefski Jun 29, 2026
9da8acc
fix: avoid table color helper shadowing
Chefski Jun 29, 2026
f6ae47f
test: cover editable block id fidelity
Chefski Jun 29, 2026
0a71e43
fix: preserve editable block ids
Chefski Jun 29, 2026
1f8fb2f
test: stabilize parallel iOS unit checks
Chefski Jun 29, 2026
366d74c
test: harden editable block id regression
Chefski Jun 29, 2026
a65fd7c
test: cover reviewed markdown fidelity gaps
Chefski Jun 29, 2026
9c0f6f6
test: isolate table color regression
Chefski Jun 29, 2026
c55e7a9
fix: harden markdown fidelity parsing
Chefski Jun 29, 2026
0dc8384
test: avoid color resolution in table alpha check
Chefski Jun 29, 2026
44c007a
test: isolate table alpha component assertions
Chefski Jun 29, 2026
f742f80
fix: keep inline parser on docmost atom prefixes
Chefski Jun 29, 2026
941d08f
fix: address status and table fidelity review gaps
Chefski Jun 29, 2026
9d6e2ea
test: cover docmost slash command titles
Chefski Jun 29, 2026
da1273b
fix: align slash command titles with docmost web
Chefski Jun 29, 2026
ef32715
test: update slash command title expectations
Chefski Jun 29, 2026
8868fd0
test: cover percentage rgb table backgrounds
Chefski Jun 29, 2026
ce58596
fix: parse percentage rgb table backgrounds
Chefski Jun 29, 2026
3b58d18
test: cover quoted html closing tag lookalikes
Chefski Jun 29, 2026
a3a2717
fix: ignore quoted html closing tag lookalikes
Chefski Jun 29, 2026
470efb3
test: cover synced block docmost ids
Chefski Jun 29, 2026
b40103b
fix: align synced block ids with docmost
Chefski Jun 29, 2026
dec2bb0
test: cover docmost slash command titles
Chefski Jun 29, 2026
e648969
fix: align slash command titles with docmost
Chefski Jun 29, 2026
c18e8b4
fix: prioritize slash command aliases
Chefski Jun 29, 2026
cbe78c5
fix: rank slash command fuzzy matches
Chefski Jun 29, 2026
0d865bd
fix: keep slash command fuzzy abbreviations visible
Chefski Jun 29, 2026
afd8f3f
test: cover inline markdown shortcuts
Chefski Jun 29, 2026
42b485f
fix: apply inline markdown shortcuts
Chefski Jun 29, 2026
df61142
test: cover underscore markdown shortcuts
Chefski Jun 29, 2026
7a6bf77
test: isolate underscore shortcut coverage
Chefski Jun 29, 2026
8884a53
fix: support underscore inline shortcuts
Chefski Jun 29, 2026
5305d3f
test: cover script underline markdown fidelity
Chefski Jun 29, 2026
abbac26
fix: preserve script underline markdown marks
Chefski Jun 29, 2026
a4d445c
test: cover table code span pipe import
Chefski Jun 29, 2026
48a85ca
fix: keep code span pipes in table import
Chefski Jun 29, 2026
223d411
test: cover double backtick code import
Chefski Jun 29, 2026
c4621ca
fix: parse multi-backtick inline code
Chefski Jun 29, 2026
16fed21
test: cover markdown front matter import
Chefski Jun 29, 2026
c715221
fix: strip markdown front matter on import
Chefski Jun 29, 2026
154c263
test: cover balanced inline link import
Chefski Jun 29, 2026
754bcde
fix: parse balanced markdown link destinations
Chefski Jun 29, 2026
c08627a
fix: import single-line math markdown blocks
Chefski Jun 29, 2026
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
158 changes: 156 additions & 2 deletions docmostly/Features/Editor/NativeEditorCommand+Behavior.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,168 @@ extension NativeEditorCommand {
func matchPriority(query: String) -> Int? {
guard query.isEmpty == false else { return 0 }

if title.localizedStandardContains(query) || rawValue.localizedStandardContains(query) {
if title.localizedStandardContainsAtWordStart(query) {
return 0
}

if subtitle.localizedStandardContains(query) {
if searchTerms.contains(where: { $0.localizedStandardContains(query) }) {
return 1
}

if title.fuzzyMatchesSlashCommandQuery(query) {
return 2
}

if rawValue.localizedStandardContains(query) {
return 3
}

if subtitle.localizedStandardContains(query) {
return 3
}

if title.localizedStandardContains(query) {
return 4
}

return nil
}

private var searchTerms: [String] {
switch self {
case .paragraph:
["p", "text", "paragraph"]
case .heading1:
["title", "big", "large", "h1"]
case .heading2:
["subtitle", "medium", "h2"]
case .heading3:
["subtitle", "small", "h3"]
case .bulletedList:
["unordered", "point", "list"]
case .numberedList:
["numbered", "ordered", "list", "ol"]
case .todoList:
["todo", "task", "list", "check", "checkbox"]
case .quote:
["blockquote", "quotes"]
case .codeBlock:
["codeblock", "snippet"]
case .image:
["photo", "picture", "media", "file", "attachment"]
case .video:
["mp4", "media", "file", "attachment"]
case .audio:
["music", "sound", "mp3", "media", "file", "attachment"]
case .pdf:
["document", "embed"]
case .fileAttachment:
["upload", "csv", "zip"]
case .table:
["rows", "columns"]
case .baseInline:
["base", "database", "grid", "spreadsheet"]
case .kanban:
["board", "cards", "status", "task", "database"]
case .callout:
["notice", "panel", "info", "warning", "success", "error", "danger"]
case .details:
["collapsible", "block", "toggle", "details", "expand"]
case .mathInline:
["math", "inline", "mathinline", "inlinemath", "inline math", "equation", "katex", "latex", "tex"]
case .pageBreak:
["page", "break", "pagebreak", "print"]
case .divider:
["horizontal rule", "hr"]
case .columns:
["layout", "split", "side"]
case .columns3:
["layout", "split", "triple"]
case .columns4, .columns5:
["layout", "split"]
case .subpages:
["child", "children", "nested", "hierarchy", "toc"]
case .syncedBlock:
["sync", "excerpt", "transclusion", "reusable", "snippet"]
case .embed:
["url", "external", "iframe"]
case .iframeEmbed:
["iframe"]
case .airtableEmbed:
["airtable"]
case .loomEmbed:
["loom"]
case .figmaEmbed:
["figma"]
case .typeformEmbed:
["typeform"]
case .miroEmbed:
["miro"]
case .youtubeEmbed:
["youtube", "yt", "media", "video"]
case .vimeoEmbed:
["vimeo"]
case .framerEmbed:
["framer"]
case .googleDriveEmbed:
["google drive", "gdrive"]
case .googleSheetsEmbed:
["google sheets", "gsheets"]
case .mathBlock:
["math", "block", "mathblock", "block math", "equation", "katex", "latex", "tex"]
case .mermaid:
["diagrams", "chart", "uml"]
case .drawio:
["diagrams", "charts", "uml", "whiteboard"]
case .excalidraw:
["diagrams", "draw", "sketch", "whiteboard"]
case .date:
["today"]
case .time:
["now", "clock"]
case .status:
["badge", "label", "lozenge"]
case .emoji:
["icon", "smiley", "emoticon", "symbol", "reaction"]
}
}
}

private extension String {
func localizedStandardContainsAtWordStart(_ query: String) -> Bool {
guard query.isEmpty == false else { return true }

var searchStart = startIndex
while searchStart < endIndex {
let searchText = self[searchStart..<endIndex]
guard let range = searchText.localizedStandardRange(of: query) else { return false }
if range.lowerBound == startIndex {
return true
}

let previousIndex = index(before: range.lowerBound)
let previousCharacter = self[previousIndex]
if previousCharacter.isWhitespace || previousCharacter.isPunctuation {
return true
}
searchStart = range.upperBound
}

return false
}
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.

func fuzzyMatchesSlashCommandQuery(_ query: String) -> Bool {
let normalizedQuery = query.lowercased()
guard normalizedQuery.isEmpty == false else { return true }

var queryIndex = normalizedQuery.startIndex
for character in lowercased() where character == normalizedQuery[queryIndex] {
queryIndex = normalizedQuery.index(after: queryIndex)
if queryIndex == normalizedQuery.endIndex {
return true
}
}

return false
}
}
41 changes: 23 additions & 18 deletions docmostly/Features/Editor/NativeEditorCommand+RichBlocks.swift
Original file line number Diff line number Diff line change
Expand Up @@ -108,18 +108,20 @@ extension NativeEditorCommand {
}

var defaultTableRows: [NativeEditorTableRow] {
[
NativeEditorTableRow(cells: [
NativeEditorTableCell(plainText: "Column 1", isHeader: true, backgroundColorName: nil),
NativeEditorTableCell(plainText: "Column 2", isHeader: true, backgroundColorName: nil)
]),
NativeEditorTableRow(cells: [
NativeEditorTableCell(plainText: "", isHeader: false, backgroundColorName: nil),
NativeEditorTableCell(plainText: "", isHeader: false, backgroundColorName: nil)
])
let columnCount = 3
return [
tableRow(columnCount: columnCount, isHeader: true),
tableRow(columnCount: columnCount, isHeader: false),
tableRow(columnCount: columnCount, isHeader: false)
]
}

private func tableRow(columnCount: Int, isHeader: Bool) -> NativeEditorTableRow {
NativeEditorTableRow(cells: (0..<columnCount).map { _ in
NativeEditorTableCell(plainText: "", isHeader: isHeader, backgroundColorName: nil)
})
}

private var baseBlock: NativeEditorBaseBlock {
if case .base(let base) = blockKind {
return base
Expand All @@ -129,9 +131,15 @@ extension NativeEditorCommand {
}

private var defaultSyncedBlockID: String {
"sync-\(UUID().uuidString)"
var generator = SystemRandomNumberGenerator()
return String((0..<Self.docmostNodeIDLength).map { _ in
Self.docmostNodeIDAlphabet.randomElement(using: &generator) ?? "a"
})
}

private static let docmostNodeIDAlphabet = Array("abcdefghijklmnopqrstuvwxyz")
private static let docmostNodeIDLength = 12

private func richBlock(id: UUID, kind: NativeEditorBlockKind, rawNode: ProseMirrorNode) -> NativeEditorBlock {
NativeEditorBlock(
id: id,
Expand All @@ -155,19 +163,16 @@ extension NativeEditorCommand {
}

private var tableNode: ProseMirrorNode {
ProseMirrorNode(type: "table", content: [
tableRowNode(cellType: "tableHeader", texts: ["Column 1", "Column 2"]),
tableRowNode(cellType: "tableCell", texts: ["", ""])
])
ProseMirrorNode(type: "table", content: defaultTableRows.map(tableRowNode))
}

private func tableRowNode(cellType: String, texts: [String]) -> ProseMirrorNode {
private func tableRowNode(from row: NativeEditorTableRow) -> ProseMirrorNode {
ProseMirrorNode(
type: "tableRow",
content: texts.map { text in
content: row.cells.map { cell in
ProseMirrorNode(
type: cellType,
content: [paragraphNode(text)]
type: cell.isHeader ? "tableHeader" : "tableCell",
content: [paragraphNode(cell.plainText)]
)
}
)
Expand Down
38 changes: 19 additions & 19 deletions docmostly/Features/Editor/NativeEditorCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -104,33 +104,33 @@ enum NativeEditorCommand: String, CaseIterable, Identifiable {
var title: String {
switch self {
case .paragraph:
"Paragraph"
"Text"
case .heading1:
"Heading 1"
case .heading2:
"Heading 2"
case .heading3:
"Heading 3"
case .bulletedList:
"Bulleted List"
"Bullet list"
case .numberedList:
"Numbered List"
"Numbered list"
case .todoList:
"To-do List"
"To-do list"
case .quote:
"Quote"
case .codeBlock:
"Code Block"
"Code"
case .image:
"Image"
case .video:
"Video"
case .audio:
"Audio"
case .pdf:
"PDF"
"Embed PDF"
case .fileAttachment:
"File"
"File attachment"
case .table:
"Table"
case .baseInline:
Expand All @@ -140,11 +140,11 @@ enum NativeEditorCommand: String, CaseIterable, Identifiable {
case .callout:
"Callout"
case .details:
"Details"
"Toggle block"
case .mathInline:
"Math Inline"
"Math inline"
case .pageBreak:
"Page Break"
"Page break"
case .divider:
"Divider"
case .columns:
Expand All @@ -156,9 +156,9 @@ enum NativeEditorCommand: String, CaseIterable, Identifiable {
case .columns5:
"5 Columns"
case .subpages:
"Subpages"
"Subpages (Child pages)"
case .syncedBlock:
"Synced Block"
"Synced block"
case .embed:
"Embed"
case .iframeEmbed:
Expand All @@ -184,13 +184,13 @@ enum NativeEditorCommand: String, CaseIterable, Identifiable {
case .googleSheetsEmbed:
"Google Sheets"
case .mathBlock:
"Math Block"
"Math block"
case .mermaid:
"Mermaid"
"Mermaid diagram"
case .drawio:
"Draw.io"
"Draw.io (diagrams.net)"
case .excalidraw:
"Excalidraw"
"Excalidraw (Whiteboard)"
case .date:
"Date"
case .time:
Expand Down Expand Up @@ -229,9 +229,9 @@ enum NativeEditorCommand: String, CaseIterable, Identifiable {
case .audio:
"Audio placeholder"
case .pdf:
"PDF placeholder"
"Upload and embed a PDF file"
case .fileAttachment:
"File attachment placeholder"
"Upload any file from your device"
case .table:
"Two-column table"
case .baseInline:
Expand All @@ -241,7 +241,7 @@ enum NativeEditorCommand: String, CaseIterable, Identifiable {
case .callout:
"Highlighted note"
case .details:
"Collapsible detail section"
"Insert collapsible block"
case .mathInline:
"Inline equation"
case .pageBreak:
Expand Down
23 changes: 22 additions & 1 deletion docmostly/Features/Editor/NativeEditorDocument+Decoding.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@ nonisolated extension NativeEditorDocument {
static func textBlock(kind: NativeEditorBlockKind, node: ProseMirrorNode) -> NativeEditorBlock {
let inlineContent = inlineContent(from: node.content ?? [])
let needsRawPreservation = inlineContent.contains(where: \.requiresRawPreservation)
let needsAttrPreservation = editableAttrsNeedRawPreservation(kind: kind, node: node)
let rawNode = needsRawPreservation || needsAttrPreservation ? node : nil

return NativeEditorBlock(
kind: kind,
text: attributedText(from: inlineContent),
alignment: NativeEditorTextAlignment(attrs: node.attrs),
inlineContent: needsRawPreservation ? inlineContent : nil,
rawNode: needsRawPreservation ? node : nil
rawNode: rawNode
)
}

Expand Down Expand Up @@ -60,6 +62,25 @@ nonisolated extension NativeEditorDocument {
}
}

private static func editableAttrsNeedRawPreservation(
kind: NativeEditorBlockKind,
node: ProseMirrorNode
) -> Bool {
guard let attrs = node.attrs, attrs.isEmpty == false else { return false }

let modeledKeys: Set<String>
switch kind {
case .paragraph:
modeledKeys = ["textAlign"]
case .heading:
modeledKeys = ["level", "textAlign"]
default:
return false
}

return attrs.keys.contains { modeledKeys.contains($0) == false }
}

private static func editableBlocks(from node: ProseMirrorNode) -> [NativeEditorBlock]? {
if let singleBlock = singleEditableBlock(from: node) {
return [singleBlock]
Expand Down
Loading
Loading