Swift Markdown Kit · DOCS

主题与语法

主题与语法

配色模式与主题

刻意分成两件事:colorScheme 决定这套设计渲染成浅色还是深色,theme 决定这套 设计本身是什么。

var options = MarkdownRenderOptions()
options.colorScheme = .auto        // .auto 跟随系统;.light / .dark 强制
options.theme = .github            // .system(默认)或 .github

两者都在运行时生效 —— 不需要重新出包,也没有额外的样式表。

Token 覆盖

一个主题 = 命名预设 + 逐 token 覆盖,每个覆盖都同时给浅色和深色值:

let theme = MarkdownTheme.github
    .textColor(light: .label, dark: .label)
    .linkColor(light: .systemIndigo, dark: .systemTeal)
    .codeBlockSurface(light: .secondarySystemBackground, dark: .tertiarySystemBackground)
    .blockquoteBorder(light: .systemGreen, dark: .systemGreen)
    .bodyLineHeight(1.55)
    .codeCornerRadius(8)
    .headingSize(level: 1, em: 1.4)
    .headingSize(level: 2, em: 1.25)

var options = MarkdownRenderOptions()
options.theme = theme

命名方法没覆盖到的部分,直接设底层的 CSS 自定义属性:

let theme = MarkdownTheme.system
    .token("--md-reasoning-color", light: .secondaryLabel, dark: .secondaryLabel)
    .token("--chat-table-border", light: "#d0d7de", dark: "#30363d")
    .metric("--md-paragraph-margin", "0.9em")
    .codeToken("--hljs-keyword", light: .systemPink, dark: .systemPink)

三类 token:token 是深浅色不同的颜色,metric 是与配色无关的尺寸, codeToken 是语法高亮。

字体与布局

var options = MarkdownRenderOptions()
options.baseFontSize = 16
options.respectsDynamicType = true    // 跟随系统字号
options.minFontScale = 0.85           // 夹住倍率,避免无障碍字号撑破布局
options.maxFontScale = 1.6
options.contentPadding = UIEdgeInsets(top: 20, left: 16, bottom: 20, right: 16)
options.bottomGap = 24                // 给覆盖在底部的输入框留出空间
options.backgroundColor = .systemBackground

会话还多两个,因为消息气泡和它所在的栏是两个宽度:

var chat = MarkdownChatRenderOptions()
chat.maxMessageWidth = .points(780)                    // 阅读栏宽度
chat.userMessageMaxWidth = .fraction(0.82, upTo: 620)  // 用户自己的气泡
chat.messageSpacing = 14

自定义行内语法

声明式注册行内扩展。没有任何代码跨越 bridge:每条规则只是一个识别模式,每个 匹配渲染成完全转义的 .md-ext-{name} span,点击后回传给你。

var options = MarkdownRenderOptions()
options.extensions = [
    .mention(),   // @handle
    .hashtag(),   // #tag
    .ticker(),    // $AAPL —— 仅大写,所以 "$5" 不受影响
    .wikilink(),  // [[Page]]
    .prefix(name: "issue", trigger: "ISSUE-", body: .upperDigit, action: "issue"),
    .delimiter(name: "spoiler", open: "||", close: "||", action: "spoiler")
]

两种识别模式:

  • prefix —— 触发串加一段受字符类约束的正文(.word、.alnum、.letter、 .upper、.upperDigit,或 .chars("…"))。热路径上没有正则,因此不存在 灾难性回溯。
  • delimiter —— 一对开闭定界符,捕获中间的文本。

点击以 action 形式抵达:

var options = MarkdownRenderOptions()
options.extensions = [.mention(), .wikilink()]

MarkdownRenderView(markdown: article, options: options) { event in
    guard case .action(let action) = event else { return }
    if case .extensionTapped(let name, let tapped, let value) = action {
        route(name: name, action: tapped, value: value)
    }
}

每个扩展都暴露自己的主题 token —— --md-ext-{name}-color、-bg、-radius、 -padding、-weight、-decoration —— 所以样式走的是和其他一切相同的机制:

let theme = MarkdownTheme.system
    .token("--md-ext-mention-color", light: .systemBlue, dark: .systemTeal)
    .metric("--md-ext-mention-radius", "4px")

运行时改不了的部分

基线样式表 —— 默认间距、代码块外框、表格分隔线 —— 编译在渲染核心里。预设和 token 覆盖能改到视觉表层;要改基线本身需要重新构建 framework。如果你需要的 token 缺失,告诉我们,通常是一个很小的改动。