原文定位

原文定位查看器 .kb-passage(右侧抽屉,滑入不打断对话):open(citation) 渲染来源标题 + KbLocation 三分型位置徽标(第 N 页 / 块 a–b / 字符 a–b),getDocument 同异步取 { content, loc, contextBefore, contextAfter },缺席回落 citedText → snippet;highlight(terms) 纯文本遍历 <mark> 多词轮转分色(data-hit 0|1|2);expand() 展开上下文;受限权限正文 blur 打码 + 申请访问(派 icen:kb-source-open)。Esc 关闭 / Tab 圈禁 / 焦点还原,跳转派 icen:kb-passage-jump,关闭派 icen:kb-passage-close。

右侧滑入抽屉(Esc 关闭,焦点还原触发前元素)

事件日志:等待交互

<div class="toolbar" style="margin-bottom:10px">  <button class="btn btn-sm btn-primary" type="button" id="demo-kb-passage-open">打开可读来源(第 3 页)</button>  <button class="btn btn-sm" type="button" id="demo-kb-passage-restricted">打开受限来源(打码 + 申请访问)</button>  <button class="btn btn-sm" type="button" id="demo-kb-passage-highlight">highlight 多词分色</button>  <button class="btn btn-sm" type="button" id="demo-kb-passage-expand">expand 上下文</button>  <button class="btn btn-sm" type="button" id="demo-kb-passage-close">close</button></div><p class="demo-label" style="margin:0 0 8px">右侧滑入抽屉(Esc 关闭,焦点还原触发前元素)</p><div id="demo-kb-passage-host"></div><p class="demo-label" id="demo-kb-passage-log" style="margin-top:8px">事件日志:等待交互</p>

安装

bun add @icen.ai/ui

一行引入该组件(CSS 与 behavior 自动带上,无需关心内部 CSS 文件名):

import '@icen.ai/ui/kit/kb-passage';

也可以用脚手架直接打印引入行:

bunx --bun @icen.ai/ui add kb-passage

Astro 项目注意:kit 入口里的 CSS import 在页面 <script> 里会被 Astro 的 client bundle 摇掉——请改在布局 frontmatter 里引 CSS(import '@icen.ai/ui/components/kb-ground.css';),JS 行为仍可走 kit。Vite SPA / webpack 项目无此问题。

用法

import { createKbPassage } from '@icen.ai/ui/kit/kb-passage';const viewer = createKbPassage(hostEl, {  getDocument: (citation) => fetch('/api/docs/' + citation.documentId).then((r) => r.json()),  // 返回 { content, loc?, contextBefore?, contextAfter? };未提供 / 落空回落 citedText → snippet  // anchor: anchorEl,   // 提供后 open 时滚动定位容器内 [data-kb-loc](精确匹配 → loc.start 最近匹配)  onJump: (citation) => console.log('jump', citation.title),});viewer.open({ id: 'c1', title: '供应商准入手册 v3.2', kind: 'wiki', documentId: 'doc-vendor-32',  loc: { kind: 'page', start: 3, end: 3 },          // KbLocation 三分型:char | page | block  citedText: '评分低于 60 分不予通过' });viewer.highlight(['供应商', '验厂']);   // <mark class="kb-passage-hit" data-hit="0|1|2"> 多词轮转分色viewer.expand();                        // 展示 contextBefore / contextAfter(一层,幂等)viewer.close();                         // 派 icen:kb-passage-close,焦点还原// 受限来源(permission ≠ readable)正文自动打码 +「申请访问」→ icen:kb-source-open// 事件:icen:kb-passage-jump { citation } / icen:kb-passage-close {}