mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-10-22 10:42:31 +00:00
core, ui: support block markdown (#7734)
* plan: support block markdown * update plans * core, ui: markdown plans and implementation * better * simplify * markdown tests and fixes * implement * fixes * fix test * bold * block markdown rendering * fix selection and rtl * fixes --------- Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
This commit is contained in:
1 parent
5a5a927821
commit
0563460204
55 files changed
+4641
-311
No files matched your search
@@ -230,6 +230,77 @@ BadgeStatus = Literal["active", "expired", "expiredOld", "failed", "unknownKey"]
|
||||
|
||||
BadgeType = Literal["supporter", "legend", "investor"]
|
||||
|
||||
class BlockToken_lineBreak(TypedDict):
|
||||
type: Literal["lineBreak"]
|
||||
|
||||
class BlockToken_softBreak(TypedDict):
|
||||
type: Literal["softBreak"]
|
||||
|
||||
class BlockToken_hardBreak(TypedDict):
|
||||
type: Literal["hardBreak"]
|
||||
|
||||
class BlockToken_paragraphBreak(TypedDict):
|
||||
type: Literal["paragraphBreak"]
|
||||
lineBreaks: int # int
|
||||
|
||||
class BlockToken_indent(TypedDict):
|
||||
type: Literal["indent"]
|
||||
|
||||
class BlockToken_headingMark(TypedDict):
|
||||
type: Literal["headingMark"]
|
||||
level: int # int
|
||||
|
||||
class BlockToken_headingClose(TypedDict):
|
||||
type: Literal["headingClose"]
|
||||
|
||||
class BlockToken_headingUnderline(TypedDict):
|
||||
type: Literal["headingUnderline"]
|
||||
level: int # int
|
||||
|
||||
class BlockToken_listMark(TypedDict):
|
||||
type: Literal["listMark"]
|
||||
number: NotRequired[str]
|
||||
|
||||
class BlockToken_quoteMark(TypedDict):
|
||||
type: Literal["quoteMark"]
|
||||
|
||||
class BlockToken_fenceMark(TypedDict):
|
||||
type: Literal["fenceMark"]
|
||||
language: NotRequired[str]
|
||||
|
||||
class BlockToken_rowMark(TypedDict):
|
||||
type: Literal["rowMark"]
|
||||
|
||||
class BlockToken_cellMark(TypedDict):
|
||||
type: Literal["cellMark"]
|
||||
|
||||
class BlockToken_delimiterRow(TypedDict):
|
||||
type: Literal["delimiterRow"]
|
||||
columns: list["TableAlign"]
|
||||
|
||||
class BlockToken_ruleMark(TypedDict):
|
||||
type: Literal["ruleMark"]
|
||||
|
||||
BlockToken = (
|
||||
BlockToken_lineBreak
|
||||
| BlockToken_softBreak
|
||||
| BlockToken_hardBreak
|
||||
| BlockToken_paragraphBreak
|
||||
| BlockToken_indent
|
||||
| BlockToken_headingMark
|
||||
| BlockToken_headingClose
|
||||
| BlockToken_headingUnderline
|
||||
| BlockToken_listMark
|
||||
| BlockToken_quoteMark
|
||||
| BlockToken_fenceMark
|
||||
| BlockToken_rowMark
|
||||
| BlockToken_cellMark
|
||||
| BlockToken_delimiterRow
|
||||
| BlockToken_ruleMark
|
||||
)
|
||||
|
||||
BlockToken_Tag = Literal["lineBreak", "softBreak", "hardBreak", "paragraphBreak", "indent", "headingMark", "headingClose", "headingUnderline", "listMark", "quoteMark", "fenceMark", "rowMark", "cellMark", "delimiterRow", "ruleMark"]
|
||||
|
||||
class BlockingInfo(TypedDict):
|
||||
reason: "BlockingReason"
|
||||
notice: NotRequired["ClientNotice"]
|
||||
@@ -692,6 +763,7 @@ class CIQuote(TypedDict):
|
||||
sentAt: str # ISO-8601 timestamp
|
||||
content: "MsgContent"
|
||||
formattedText: NotRequired[list["FormattedText"]]
|
||||
markdownBlocks: NotRequired[list["MarkdownBlock"]] # non-empty
|
||||
|
||||
class CIReaction(TypedDict):
|
||||
chatDir: "CIDirection"
|
||||
@@ -1224,6 +1296,7 @@ class ChatItem(TypedDict):
|
||||
content: "CIContent"
|
||||
mentions: dict[str, "CIMention"]
|
||||
formattedText: NotRequired[list["FormattedText"]]
|
||||
markdownBlocks: NotRequired[list["MarkdownBlock"]] # non-empty
|
||||
quotedItem: NotRequired["CIQuote"]
|
||||
reactions: list["CIReactionCount"]
|
||||
file: NotRequired["CIFile"]
|
||||
@@ -1795,8 +1868,11 @@ class FileTransferMeta(TypedDict):
|
||||
|
||||
FileType = Literal["normal", "roster"]
|
||||
|
||||
# The format markup is a token of block Markdown syntax; its text is the syntax. The format escape is the backslash of a backslash escape. Bold singleStar: written with single stars.
|
||||
|
||||
class Format_bold(TypedDict):
|
||||
type: Literal["bold"]
|
||||
singleStar: bool
|
||||
|
||||
class Format_italic(TypedDict):
|
||||
type: Literal["italic"]
|
||||
@@ -1850,6 +1926,13 @@ class Format_email(TypedDict):
|
||||
class Format_phone(TypedDict):
|
||||
type: Literal["phone"]
|
||||
|
||||
class Format_escape(TypedDict):
|
||||
type: Literal["escape"]
|
||||
|
||||
class Format_markup(TypedDict):
|
||||
type: Literal["markup"]
|
||||
token: "BlockToken"
|
||||
|
||||
Format = (
|
||||
Format_bold
|
||||
| Format_italic
|
||||
@@ -1866,9 +1949,11 @@ Format = (
|
||||
| Format_mention
|
||||
| Format_email
|
||||
| Format_phone
|
||||
| Format_escape
|
||||
| Format_markup
|
||||
)
|
||||
|
||||
Format_Tag = Literal["bold", "italic", "strikeThrough", "snippet", "secret", "small", "colored", "uri", "hyperLink", "simplexLink", "simplexName", "command", "mention", "email", "phone"]
|
||||
Format_Tag = Literal["bold", "italic", "strikeThrough", "snippet", "secret", "small", "colored", "uri", "hyperLink", "simplexLink", "simplexName", "command", "mention", "email", "phone", "escape", "markup"]
|
||||
|
||||
class FormattedText(TypedDict):
|
||||
format: NotRequired["Format"]
|
||||
@@ -2191,6 +2276,11 @@ class LinkPreview(TypedDict):
|
||||
image: str
|
||||
content: NotRequired["LinkContent"]
|
||||
|
||||
class ListEntry(TypedDict):
|
||||
number: NotRequired[str]
|
||||
content: "SegmentRange"
|
||||
items: list["ListEntry"]
|
||||
|
||||
class LocalBadge(TypedDict):
|
||||
badge: "BadgeInfo"
|
||||
status: "BadgeStatus"
|
||||
@@ -2210,6 +2300,50 @@ class LocalProfile(TypedDict):
|
||||
contactDomain: NotRequired["SimplexDomainClaim"]
|
||||
contactDomainVerified: NotRequired[bool]
|
||||
|
||||
class MarkdownBlock_paragraph(TypedDict):
|
||||
type: Literal["paragraph"]
|
||||
content: "SegmentRange"
|
||||
|
||||
class MarkdownBlock_heading(TypedDict):
|
||||
type: Literal["heading"]
|
||||
level: int # int
|
||||
content: "SegmentRange"
|
||||
|
||||
class MarkdownBlock_codeBlock(TypedDict):
|
||||
type: Literal["codeBlock"]
|
||||
language: NotRequired[str]
|
||||
content: "SegmentRange"
|
||||
|
||||
class MarkdownBlock_quote(TypedDict):
|
||||
type: Literal["quote"]
|
||||
content: "SegmentRange"
|
||||
|
||||
class MarkdownBlock_list(TypedDict):
|
||||
type: Literal["list"]
|
||||
items: list["ListEntry"] # non-empty
|
||||
|
||||
class MarkdownBlock_table(TypedDict):
|
||||
type: Literal["table"]
|
||||
columns: list["TableAlign"] # non-empty
|
||||
header: list["SegmentRange"]
|
||||
rows: list[list["SegmentRange"]]
|
||||
|
||||
class MarkdownBlock_rule(TypedDict):
|
||||
type: Literal["rule"]
|
||||
mark: "SegmentRange"
|
||||
|
||||
MarkdownBlock = (
|
||||
MarkdownBlock_paragraph
|
||||
| MarkdownBlock_heading
|
||||
| MarkdownBlock_codeBlock
|
||||
| MarkdownBlock_quote
|
||||
| MarkdownBlock_list
|
||||
| MarkdownBlock_table
|
||||
| MarkdownBlock_rule
|
||||
)
|
||||
|
||||
MarkdownBlock_Tag = Literal["paragraph", "heading", "codeBlock", "quote", "list", "table", "rule"]
|
||||
|
||||
MemberCriteria = Literal["all"]
|
||||
|
||||
# Connection link sent in a message - only short links are allowed.
|
||||
@@ -2937,6 +3071,10 @@ class SecurityCode(TypedDict):
|
||||
securityCode: str
|
||||
verifiedAt: str # ISO-8601 timestamp
|
||||
|
||||
class SegmentRange(TypedDict):
|
||||
from: int # int
|
||||
to: int # int
|
||||
|
||||
class SimplePreference(TypedDict):
|
||||
allow: "FeatureAllowed"
|
||||
|
||||
@@ -3573,6 +3711,8 @@ class SupportGroupPreference(TypedDict):
|
||||
|
||||
SwitchPhase = Literal["started", "confirmed", "secured", "completed"]
|
||||
|
||||
TableAlign = Literal["none", "left", "center", "right"]
|
||||
|
||||
class TimedMessagesGroupPreference(TypedDict):
|
||||
enable: "GroupFeatureEnabled"
|
||||
ttl: NotRequired[int] # int
|
||||
|
||||
Reference in new issue
Block a user