生态产品多个设计器现已发布候选版本

查看生态总览
跳转到内容

CodeView 代码视图 ​

一段代码的逐行呈现:行号、指定行高亮、超长折叠、按语法块折叠、文件名,可选语法着色,支持流式追加时的未闭合状态。

用法 ​

代码原文由宿主提供,组件切出逐行结构并铺设记号;渲染文件名后它即成为代码块的可访问名

ticker.ts
export function createTicker(intervalTime: number) {  let handle = 0  return {    start(onTick: () => void) {      handle = setInterval(onTick, intervalTime)    },    stop() {      clearInterval(handle)    },  }}

组件结构 ​

加粗的是必需部件。

data-scope="code-view":root · header · filename · lang-label · pre · code · line · line-number · line-content · token · fold-trigger · line-fold-trigger

示例 ​

行号与高亮行 ​

行号由皮肤绘制,复制代码不会带上它;高亮行按行号写,与 startLine 对齐

function resolve(input: string) {  const trimmed = input.trim()  if (trimmed === '') {    return null  }  return trimmed.toLowerCase()}

折叠超长代码 ​

clamped 是纯受控的:组件只发意图,是否落实由宿主决定,便于全部展开这类操作统一持有

const step1 = pipeline.at(0)const step2 = pipeline.at(1)const step3 = pipeline.at(2)const step4 = pipeline.at(3)const step5 = pipeline.at(4)const step6 = pipeline.at(5)const step7 = pipeline.at(6)const step8 = pipeline.at(7)const step9 = pipeline.at(8)const step10 = pipeline.at(9)const step11 = pipeline.at(10)const step12 = pipeline.at(11)const step13 = pipeline.at(12)const step14 = pipeline.at(13)const step15 = pipeline.at(14)const step16 = pipeline.at(15)const step17 = pipeline.at(16)const step18 = pipeline.at(17)const step19 = pipeline.at(18)const step20 = pipeline.at(19)const step21 = pipeline.at(20)const step22 = pipeline.at(21)const step23 = pipeline.at(22)const step24 = pipeline.at(23)

流式追加 ​

代码仍在写入时默认不着色:不完整代码的词法本就不稳定,每来一个字符整块变色比不着色更差

头部内建复制 ​

复制交给剪贴板:把它放进头部条,用几个槽把描边按钮压为安静形态,1500 毫秒后自动回落

store.ts
export function createStore(reduce: Reducer, initial: State) {  let state = initial  return {    get: () => state,    dispatch(action: Action) {      state = reduce(state, action)    },  }}

着色端口 ​

着色是可替换的端口:无法识别的语言退回纯文本,接入自己的实现时组件侧无需修改,传 null 则整个关闭

# 部署清单image: xihan/ui:latestreplicas: 2env:  - name: MODE    value: production
# 部署清单image: xihan/ui:latestreplicas: 2env:  - name: MODE    value: production
# 部署清单image: xihan/ui:latestreplicas: 2env:  - name: MODE    value: production

流式期间也着色 ​

未闭合默认不着色;确需着色时开启 highlight-while-streaming,同一段不完整代码的两种呈现并排对照

const stream = await client.chat({  model: 'demo',  messages,  onToken(token) {    buffer +=
const stream = await client.chat({  model: 'demo',  messages,  onToken(token) {    buffer +=

尺寸 ​

size 切换字号、行高与内边距三档,行号槽与折叠按钮随之变化

clamp.sm.ts
export function clamp(n: number, min: number, max: number) {  return Math.min(Math.max(n, min), max)}
clamp.md.ts
export function clamp(n: number, min: number, max: number) {  return Math.min(Math.max(n, min), max)}
clamp.lg.ts
export function clamp(n: number, min: number, max: number) {  return Math.min(Math.max(n, min), max)}

头部下载 ​

下载交给下载触发器:放进头部条,文件名沿用代码的文件名,写出的是原文

retry.ts
export async function retry<T>(run: () => Promise<T>, times = 3): Promise<T> {  let last: unknown  for (let i = 0; i < times; i++) {    try {      return await run()    }    catch (error) {      last = error    }  }  throw last}

按块折叠 ​

block-folding 按缩进找出语法块,块头行首给一颗折叠钮;折叠集合写块头的行号,可受控(folded)也可非受控(default-folded);一组钮只占一个 Tab 位、上下方向键在组内走

export function createQueue<T>(limit: number) {  const pending: T[] = []  function push(item: T) {    if (pending.length >= limit) {      pending.shift()    }    pending.push(item)  }  function drain(handle: (item: T) => void) {  }  return { push, drain }}
折叠着的块头:11

设计指引 ​

何时使用 ​

  • 在 AI 回复、文档、评审意见中展示代码,需要行号或需要指出某几行。
  • 代码是流式生成的,需要边接收边渲染,闭合之后再着色。
  • 代码较长,默认只显示前若干行。

何时不用 ​

  • 只是一小段行内标识时,使用排印的 code 形态。
  • 展示运行日志时,使用日志。
  • 展示改动前后时,使用差异视图。

特性 ​

  • 逐行切分在连接层完成。一个记号可以横跨多行(未闭合的字符串与块注释),因此行号与高亮行不能由皮肤反推。
  • complete 标记这段代码是否已经写完。未闭合时默认不着色:半截代码的词法不稳定,逐字符变色比不着色更差。
  • highlighter 是着色端口,由宿主决定接入哪个着色器;返回 null 是合法结果,回到纯文本。适配器默认接 @xihan-ui/code-highlight,它是可选 peer:已安装时自动着色,未安装时保持纯文本。适配器显式传 null 时不请求默认模块;只有模块缺席才回到纯文本,已安装模块的加载或初始化异常照常抛出。
  • 行号由皮肤用 attr() 绘制,复制代码不会带上行号,读屏也不会逐行读出数字。
  • clamped 是纯受控的:折叠状态通常由外部“全部展开 / 全部折叠”统一持有,内建状态会与之冲突。
  • blockFolding 按缩进折叠语法块:一行之下缩进更深的连续行(夹在中间的空行算在内)是它的块,块头行首出现折叠钮,收起后块头正文后面画一枚省略号。按缩进而不按括号配对,是为了不依赖语言:Python、YAML 这类没有括号的语言一样能折;花括号语言的收尾括号与块头同缩进,折叠后留在外面。缩进不规整的代码(压缩过的、混排制表符的)找不出有意义的块,这时不要开它。
  • 折叠集合写块头的行号(随 startLine),folded 受控、defaultFolded 非受控,变化经 folded-change 报出;代码变了以后不再是块头的行号自动失效。收起的行不占高度,pre 预撑的行数按看得见的算。

组合 ​

  • 下载使用下载触发器,同样放进 header,data 给原文、fileName 沿用文件名。
  • 与剪贴板配合提供复制;需要非受控折叠时放入折叠区域。把剪贴板的三个部件放进 header,再用 --xh-clipboard-copy-trigger-border: transparent、--xh-clipboard-copy-trigger-bg: transparent、--xh-clipboard-copy-trigger-h: var(--xh-control-h-sm) 三个槽把按钮调整为头部内的低强调形态。
  • 内建词法只区分注释、字符串、数字、关键字、标点五档。需要区分函数名、类型名、属性名时,自行实现 highlighter 端口(同步纯函数,可接 Shiki 等)传入,皮肤按记号种类上色的规则不变。
  • 放进 AI 回复正文时由流式正文交付代码块。

最佳实践 ​

  • 标出语言,读者与着色器都需要它。
  • 高亮行用于指出重点,不一次点亮半屏。
  • 折叠阈值取十几行:过少时读者每次都要展开,过多时折叠失去意义。

反模式 ​

  • 把代码放进普通段落,空白与换行会被折叠。
  • 用行号作为跳转锚点,它是绘制上去的,DOM 中不可选中。

API 参考 ​

产物 ​

层值
自定义元素<xh-code-view>
Vue 组件XhCodeViewCode XhCodeViewFilename XhCodeViewFoldTrigger XhCodeViewHeader XhCodeViewLangLabel XhCodeViewPre XhCodeViewRoot
组合式函数useCodeView
状态机codeViewMachine
皮肤@xihan-ui/styles/code-view.css

Props ​

属性类型必填说明
codestring是
langstring围栏语言标注,空白一律落为 plaintext。
filenamestring文件名,渲染在 header 中;渲染之后它即为 pre 的可访问名。
labelledboolean作者渲染了 filename 部件时置真,由适配器统计而不是判断 filename 是否有值。 为假时 pre 用 translations.code 兜底:指向未渲染的 id 会使读屏读空。
completeboolean代码是否已闭合,未闭合时按行数预撑高度且默认不着色。
wrapboolean长行自动换行,默认关闭(长行横向滚动)。
lineNumbersboolean渲染行号槽。
startLinenumber首行的行号,默认 1;摘录与 patch 片段需要使用。
highlightLinesstring | readonly number[]要高亮的行号,写为 '3,7-9' 或行号数组;非法片段丢弃不报错。
clampnumber超过该行数才视为可折叠。
clampedboolean折叠态,纯受控:没有 defaultClamped,需要非受控时套用 collapsible。
blockFoldingboolean按缩进找出语法块,块头那一行的行首给一颗折叠钮,默认关闭。 一行之下缩进更深的连续行(夹在中间的空行算在内)是它的块;与语言无关, 花括号语言的收尾括号与块头同缩进,折叠后留在外面。
foldedreadonly number[]折叠着的块,写块头的行号(受 startLine 影响);受控。不是块头的行号忽略。
defaultFoldedreadonly number[]非受控时一开始就折叠着的块,写法同 folded。
onFoldedChange(details: CodeViewFoldedChangeDetails) => void语法块的折叠集合变化。
highlighterHighlighterPort着色实现。未提供时为纯文本,提供后也允许返回 null(语言未识别等),同样回退为纯文本。 未闭合的块默认不着色,见 {@link highlightWhileStreaming}。
highlightWhileStreamingboolean块尚未闭合时也着色,默认 false。 默认关闭是因为未闭合代码的词法本身不稳定:引号、括号随时会配对, 每到一个 token 整块变一次色,比不着色更差。
sizeSize尺寸:sm / md / lg。
translationsPartial<CodeViewTranslations>
onClampToggle(details: CodeViewClampToggleDetails) => void折叠态切换的意图回调;clamped 是纯受控的,是否落定由宿主决定。

事件 ​

自定义元素将载荷放在 detail;Vue 使用同名 emit。

事件载荷说明
clamp-toggleCustomEvent折叠态切换的意图;detail 为 { clamped: boolean }
folded-changeCustomEvent语法块的折叠集合变化;detail 为 { folded: number[] }

插槽 ​

仅列出带载荷的插槽。

Vue 组件插槽载荷说明
XhCodeViewCodelineCodeViewLineSlotProps
XhCodeViewRootdefaultCodeViewRootSlotProps

React 适配器 props ​

只列各组件自己声明的那些:继承自 ComponentPropsWithRef 的 DOM 属性不在其中,根组件上与上面 Props 表同名的也不重复列。Vue 的对应物是上面的插槽表。

React 组件属性类型必填说明
XhCodeViewCodechildrenSlotChildren<CodeViewLineSlotProps>逐行接管该行的正文;未提供时按着色结果铺设。
XhCodeViewFilenamefilenamestring未写 children 时显示它;也没给时取 XhCodeViewRoot 上的 filename。
XhCodeViewRootchildrenSlotChildren<CodeViewRootSlotProps>

状态 ​

公开状态写入 data-state。

部件取值
fold-trigger'closed' | 'open'
line-fold-trigger'open' | 'closed'

以下名称仅用于内部状态机。

状态:idle

事件:PRESS.START · PRESS.END · FOLD.TOGGLE · FOLD.FOCUS

判据:canPress

connect API ​

getXxxProps() 返回对应部件的宿主属性。

成员类型说明
langstring
filenamestring | undefined文件名;filename 部件没写内容时显示它。
lineCountnumber
linesreadonly CodeLine[]逐行切分后的文本与记号片段。
lineNumberAt(index: number) => number每行的行号,与 lines 同序。
lineNumbersboolean是否渲染行号槽;适配器据此决定是否创建该节点。
foldableboolean折叠可用:提供了正数 clamp 且行数确实超过它。
clampedboolean
setClamped(next: boolean) => void发出一次折叠意图;与当前态相同时不发。
foldRegionsreadonly CodeViewFoldRegion[]按缩进找出的语法块,按块头先后排;blockFolding 关闭时为空。
foldedreadonly number[]折叠着的块,写块头的行号,升序;只含当下确实是块头的行号。
isFoldStart(index: number) => boolean该行是不是某个语法块的块头;适配器据此决定要不要在行首建折叠钮。
toggleFold(line: number) => void翻转一个语法块的折叠,line 是块头的行号;不是块头时不做事。
getLineFoldTriggerProps(props: CodeViewLineProps) => T['button']
getRootProps() => T['element']
getHeaderProps() => T['element']
getFilenameProps() => T['element']
getLangLabelProps() => T['element']
getPreProps() => T['element']
getCodeProps() => T['element']
getLineProps(props: CodeViewLineProps) => T['element']
getLineNumberProps(props: CodeViewLineProps) => T['element']
getLineContentProps(props: CodeViewLineProps) => T['element']
getTokenProps(token: CodeToken) => T['element']
getFoldTriggerProps() => T['button']

无障碍 ​

键盘 ​

规格出处:W3C APG

按键生效条件行为
Tab代码块在 Tab 序列中<pre> 自身可聚焦,随后方向键的横向滚动交给浏览器,组件不接管
Enter / Space焦点在折叠按钮上翻面折叠态并发出意图;组件只接 click,按键走原生 button 的默认行为
Enter / Space按住折叠按钮且代码可折叠按住期间 fold-trigger 投影 data-pressed,与指针 :active 同一副按压面(disclosure trigger 只换面不缩放);抬起、失焦或折叠条收起撤下
Tab开了按块折叠一组行首折叠钮只占一个 Tab 位:落在上次聚焦的那颗,它被收起或不再是块头时落在第一颗看得见的钮上
Enter / Space焦点在行首折叠钮上折叠或展开这个语法块,走原生 button 的激活
ArrowDown / ArrowUp焦点在行首折叠钮上移到下一颗 / 上一颗看得见的折叠钮,收起在块里的跳过;到头不回绕
Home / End焦点在行首折叠钮上移到第一颗 / 最后一颗看得见的折叠钮

ARIA ​

以下属性由 connect 生成。

部件属性值
lang-labelaria-hidden'true'
prerole'group'
line-numberaria-hidden'true'
fold-triggeraria-controlspre 部件的 id
fold-triggeraria-expanded'false' | 'true'
fold-triggeraria-labeltranslations.expand | translations.collapse
line-fold-triggeraria-expanded'true' | 'false'
line-fold-triggeraria-labelundefined | foldLabel(lineNumberAt(region.start + 1), lineNumberA…
  • pre 可聚焦并带可访问名称:渲染了文件名时指向它,否则使用 translations.code。
  • 折叠按钮带 aria-expanded 与 aria-controls,指向 pre。
  • 行首折叠钮合起来只占一个 Tab 位,上下方向键在看得见的钮之间走,Home / End 到首末;名字写这个块收起的是哪几行(translations.foldBlock),开合由 aria-expanded 表达。
  • 语言角标与行号槽都对读屏隐藏,它们是装饰而非内容。

样式参考 ​

皮肤 ​

@xihan-ui/styles/code-view.css 按 [data-scope="code-view"][data-part="root"] 部件选择器书写,发布产物以挂载类 .xh-scope-code-view 代替其中的 data-scope(特异性相同),位于 xihan.components 层。覆盖样式使用 xihan.overrides,部件选择器照常可用。

forced-colors: active 下另有一套规则:颜色交给系统,边框与状态标记改用系统色关键字。

数据属性 ​

由 connect 生成;条件不成立时不输出无值属性。

部件属性值
rootdata-block-folding''(条件成立时才出现)
rootdata-clamped''(条件成立时才出现)
rootdata-complete''(条件成立时才出现)
rootdata-digitsString(Math.min( String(lineNumberAt(lineCount - 1)).…
rootdata-foldable''(条件成立时才出现)
rootdata-langprop('lang')?.trim() || CODE_VIEW_FALLBACK_LANG
rootdata-line-numbers''(条件成立时才出现)
rootdata-sizeprops.size
predata-complete''(条件成立时才出现)
predata-wrap''(条件成立时才出现)
codedata-langprop('lang')?.trim() || CODE_VIEW_FALLBACK_LANG
codedata-wrap''(条件成立时才出现)
linedata-folded''(条件成立时才出现)
linedata-highlighted''(条件成立时才出现)
linedata-line-numberString(lineNumberAt(index))
line-numberdata-folded''(条件成立时才出现)
line-numberdata-highlighted''(条件成立时才出现)
line-numberdata-line-numberString(lineNumberAt(index))
line-contentdata-folded''(条件成立时才出现)
line-contentdata-highlighted''(条件成立时才出现)
line-contentdata-line-numberString(lineNumberAt(index))
tokendata-kindtoken.kind
fold-triggerdata-pressed''(条件成立时才出现)
fold-triggerdata-state'closed' | 'open'
fold-triggerdata-xh-action-control''
fold-triggerdata-xh-action-display'always'
fold-triggerdata-xh-action-profile'disclosure-trigger'
fold-triggerdata-xh-action-sizeprops.size
fold-triggerdata-xh-action-variant'ghost'
line-fold-triggerdata-state'open' | 'closed'
line-fold-triggerdata-xh-action-control''
line-fold-triggerdata-xh-action-display'always'
line-fold-triggerdata-xh-action-profile'icon'
line-fold-triggerdata-xh-action-sizeprops.size
line-fold-triggerdata-xh-action-variant'ghost'

CSS 变量 ​

本组件公开覆盖槽由独立皮肤的实际消费位生成;默认来源、作用部件和状态均与 CSS 同源。

变量部件CSS 属性状态默认来源说明
--xh-code-view-bgrootbackgrounddefault--xh-bg-surfacecode-view 的 root 部件 background 覆盖槽。
--xh-code-view-borderrootborderdefault--xh-border-defaultcode-view 的 root 部件 border 覆盖槽。
--xh-code-view-comment-fgtokencolorkind=comment--xh-fg-mutedcode-view 的 token 部件 color 覆盖槽。
--xh-code-view-fgrootcolordefault--xh-fg-mutedcode-view 的 root 部件 color 覆盖槽。
--xh-code-view-filename-fgfilenamecolordefault--xh-fg-defaultcode-view 的 filename 部件 color 覆盖槽。
--xh-code-view-fold-bg-hoverfold-triggerbackground-colordisabled
hover
loading
not([data-disabled])
not([data-loading])
--xh-_action-variant-bg-hovercode-view 的 fold-trigger 部件 background-color 覆盖槽。
--xh-code-view-fold-colline-content
line-fold-trigger
root
block-size
inline-size
min-block-size
min-inline-size
padding-inline-start
block-folding
line-numbers
not([data-line-numbers])
xh-action-profile=disclosure-trigger
xh-action-profile=icon
--xh-code-view-line-heightcode-view 的 line-content、line-fold-trigger、root 部件 block-size、inline-size、min-block-size、min-inline-size、padding-inline-start 覆盖槽。
--xh-code-view-fold-fgfold-triggercolordefault--xh-fg-mutedcode-view 的 fold-trigger 部件 color 覆盖槽。
--xh-code-view-fold-pyfold-triggerpadding-blockxh-action-profile=disclosure-trigger--xh-space-2code-view 的 fold-trigger 部件 padding-block 覆盖槽。
--xh-code-view-folded-fgline-contentbackground-colorfolded--xh-fg-subtlecode-view 的 line-content 部件 background-color 覆盖槽。
--xh-code-view-folded-gapline-contentmargin-inline-startfolded--xh-space-1code-view 的 line-content 部件 margin-inline-start 覆盖槽。
--xh-code-view-fontcode
filename
font-familydefault--xh-font-family-monocode-view 的 code、filename 部件 font-family 覆盖槽。
--xh-code-view-font-sizerootfont-sizedefault--xh-_code-view-font-sizecode-view 的 root 部件 font-size 覆盖槽。
--xh-code-view-gutter-borderline-numberborder-inline-enddefault--xh-border-subtlecode-view 的 line-number 部件 border-inline-end 覆盖槽。
--xh-code-view-gutter-gapline-numberpadding-inline-enddefault--xh-space-1code-view 的 line-number 部件 padding-inline-end 覆盖槽。
--xh-code-view-header-borderfold-trigger
header
border
border-block-end
border-color
default
disabled
focus-visible
hover
is(:active, [data-pressed])
loading
not([data-disabled])
not([data-loading])
pressed
--xh-border-subtlecode-view 的 fold-trigger、header 部件 border、border-block-end、border-color 覆盖槽。
--xh-code-view-header-fgheadercolordefault--xh-fg-mutedcode-view 的 header 部件 color 覆盖槽。
--xh-code-view-header-font-sizefold-trigger
header
font-sizedefault--xh-text-secondary-sizecode-view 的 fold-trigger、header 部件 font-size 覆盖槽。
--xh-code-view-header-gapheadergapdefault--xh-space-2code-view 的 header 部件 gap 覆盖槽。
--xh-code-view-header-hheadermin-block-sizedefault--xh-control-h-lgcode-view 的 header 部件 min-block-size 覆盖槽。
--xh-code-view-header-pxheaderpadding-inlinedefault--xh-space-4code-view 的 header 部件 padding-inline 覆盖槽。
--xh-code-view-header-pyheaderpadding-blockdefault--xh-space-2code-view 的 header 部件 padding-block 覆盖槽。
--xh-code-view-highlight-barlinebox-shadow
outline
outline-offset
@media print
highlighted
--xh-stroke-thickcode-view 的 line 部件 box-shadow、outline、outline-offset 覆盖槽。
--xh-code-view-highlight-bglinebackgroundhighlighted--xh-bg-subtlecode-view 的 line 部件 background 覆盖槽。
--xh-code-view-highlight-fglinebox-shadowhighlighted--xh-border-strongcode-view 的 line 部件 box-shadow 覆盖槽。
--xh-code-view-icon-sizeline-fold-trigger--xh-icon-sizedefault--xh-glyph-size-smcode-view 的 line-fold-trigger 部件 --xh-icon-size 覆盖槽。
--xh-code-view-keyword-fgtokencolorkind=keyword--xh-syntax-keywordcode-view 的 token 部件 color 覆盖槽。
--xh-code-view-keyword-weighttokenfont-weightkind=keyword--xh-font-weight-semiboldcode-view 的 token 部件 font-weight 覆盖槽。
--xh-code-view-label-fglang-labelcolordefault--xh-fg-subtlecode-view 的 lang-label 部件 color 覆盖槽。
--xh-code-view-label-font-sizelang-labelfont-sizedefault--xh-text-caption-sizecode-view 的 lang-label 部件 font-size 覆盖槽。
--xh-code-view-line-fold-trigger-fgline-fold-triggercolordefault--xh-fg-subtlecode-view 的 line-fold-trigger 部件 color 覆盖槽。
--xh-code-view-line-fold-trigger-radiusline-fold-triggerborder-radiusdefault--xh-shape-controlcode-view 的 line-fold-trigger 部件 border-radius 覆盖槽。
--xh-code-view-line-heightline
line-content
line-fold-trigger
pre
root
block-size
inline-size
line-height
min-block-size
min-inline-size
padding-inline-start
block-folding
default
line-numbers
not([data-line-numbers])
xh-action-profile=disclosure-trigger
xh-action-profile=icon
--xh-text-code-leadingcode-view 的 line、line-content、line-fold-trigger、pre、root 部件 block-size、inline-size、line-height、min-block-size、min-inline-size、padding-inline-start 覆盖槽。
--xh-code-view-number-fgline-numbercolordefault--xh-fg-subtlecode-view 的 line-number 部件 color 覆盖槽。
--xh-code-view-number-font-sizeline-numberfont-sizedefault--xh-text-caption-sizecode-view 的 line-number 部件 font-size 覆盖槽。
--xh-code-view-number-token-fgtokencolorkind=number--xh-syntax-numbercode-view 的 token 部件 color 覆盖槽。
--xh-code-view-punctuation-fgtokencolorkind=punctuation--xh-fg-subtlecode-view 的 token 部件 color 覆盖槽。
--xh-code-view-pxfold-trigger
line
line-content
line-fold-trigger
line-number
root
inset-inline-start
padding-inline
padding-inline-end
padding-inline-start
block-folding
default
line-numbers
not([data-line-numbers])
--xh-space-3code-view 的 fold-trigger、line、line-content、line-fold-trigger、line-number、root 部件 inset-inline-start、padding-inline、padding-inline-end、padding-inline-start 覆盖槽。
--xh-code-view-pyprepadding-blockdefault--xh-space-3code-view 的 pre 部件 padding-block 覆盖槽。
--xh-code-view-radiusrootborder-radiusdefault--xh-shape-surfacecode-view 的 root 部件 border-radius 覆盖槽。
--xh-code-view-shadowrootbox-shadowdefaultnonecode-view 的 root 部件 box-shadow 覆盖槽。
--xh-code-view-string-fgtokencolorkind=string--xh-syntax-stringcode-view 的 token 部件 color 覆盖槽。

动效 ​

动效角色:按压 · 状态 · 披露(见动效规范)。

background-color · box-shadow · rotate 走 transition 过渡。时长与缓动读动效令牌,改令牌即改全局节奏。

系统开启减弱动效时由令牌层统一收敛,皮肤不另作判断。

RTL ​

皮肤用逻辑属性排布(inline-start 一族),dir="rtl" 下自动镜像;只认物理方向的量乘 --xh-direction-sign 换向,按就近的 dir 走。

Released under The MIT License