API 参考
导出总览
@huiol/stream-ui 从 src/index.ts 导出:
ts
export { StreamContains } from './StreamContains'
export * from './component' // Think, Text, StreamBase, defineStreamBase, MdSupport, LatexSupport, ...
export * from './core/stream-form-data'
export * from './types' // StreamBlockData, StreamBlockComponentProps, streamBlockProps, ...类型定义
全部在 src/types/stream-ui.ts 中定义。
ts
type RenderMode = 'fast' | 'accurate'
type StreamBlockCategory = 'component' | 'fallback' | 'text'
type StreamBlockAttrs = Record<string, string | boolean>
interface StreamBlockData {
id: string
tagName: string
attrs?: StreamBlockAttrs
content: string
isClosed: boolean
category: StreamBlockCategory
payload?: unknown
}
// 组件标签存在字符串 id 属性时,会优先作为稳定区块 ID。
type StreamBlockReporter = (payload: unknown) => void
interface StreamContainsProps {
modelValue: string
mode: RenderMode
data?: StreamBlockData[]
components?: ComponentMap
baseComponent?: Component | null
literalTags?: string[]
}
interface StreamBlockBaseProps {
block: StreamBlockData
tagName: string
attrs?: StreamBlockAttrs
content: string
isClosed: boolean
reportData: StreamBlockReporter
}
interface StreamBlockComponentProps {
block?: StreamBlockData
attrs?: StreamBlockAttrs
content?: string
isClosed?: boolean
reportData?: StreamBlockReporter
}
interface StreamFormField {
id: string
name: string
tagName: string
label?: string
value?: unknown
required?: boolean
valid?: boolean
error?: string
attrs?: StreamBlockAttrs
payload?: unknown
}
interface StreamFormAction {
id: string
action: string
label?: string
clicked: boolean
at?: number
attrs?: StreamBlockAttrs
payload?: unknown
}
interface StreamFormData {
values: Record<string, unknown>
fields: Record<string, StreamFormField>
actions: StreamFormAction[]
valid: boolean
errors: Record<string, string>
submitted: boolean
lastAction?: StreamFormAction
blocks: StreamBlockData[]
}streamBlockProps 是对应的运行时 props 对象,适合在 defineComponent 写法中复用:
ts
import { defineComponent } from 'vue'
import { streamBlockProps } from '@huiol/stream-ui'
export default defineComponent({
name: 'MyBlock',
props: streamBlockProps
})表单数据辅助函数
collectStreamFormData
将 v-model:data 得到的 StreamBlockData[] 整理成表单视图:
ts
import { collectStreamFormData } from '@huiol/stream-ui'
const form = collectStreamFormData(blocks.value)
console.log(form.values.email)input-block 和 select-block 会进入 fields / values,button-block 会进入 actions。字段键优先使用 payload.name,其次使用 attrs.name,最后回退到区块 id。
required 字段为空或字段 payload 上报 valid: false 时,form.valid 会变为 false,错误信息会进入 form.errors。点击 action="submit" 的按钮后,form.submitted 会变为 true,最近一次点击动作可通过 form.lastAction 读取。
useStreamFormData
Vue 组件中可以直接传入 ref、getter 或普通数组:
ts
import { ref } from 'vue'
import { useStreamFormData, type StreamBlockData } from '@huiol/stream-ui'
const blocks = ref<StreamBlockData[]>([])
const form = useStreamFormData(blocks)
if (form.value.submitted && form.value.valid) {
submit(form.value.values)
}组件
StreamContains
核心容器组件。详见组件文档。
Think
内置的 <think> 标签拦截组件,可折叠推理面板。详见组件文档。
Text
内置的 <text> 标签拦截组件,内联 <span> 包装器。
DefaultTag
未注册标签的降级渲染组件。详见组件文档。
StreamBase
Base 组件工厂,支持插件式扩展。
ts
const BaseComponent = StreamBase.with([MdSupport, LatexSupport])defineStreamBase
StreamBase.with() 的底层函数,接收 DefineStreamBaseOptions。
ts
interface DefineStreamBaseOptions {
supports?: StreamBaseSupport[]
className?: string
}内核函数(底层,一般不直接调用)
ts
// 在 src/core/stream-contains-core.ts 中
function normalizeTagName(value: string): string
function toKebabCase(value: string): string
function parseTagAttrs(tagSource: string): StreamBlockAttrs
function getOpeningTagSource(tagSource: string): string
function buildComponentMap(defaultSlots: unknown[], explicitComponents?: ComponentMap): { componentMap: ComponentMap; rawTagNames: Set<string> }
function parseAccurateStream(rawText: string, options: ParserOptions): { root: StackNode; currentWarnings: string[] }
function createStreamContainsRender(props: StreamContainsProps, slots: Slots, options: StreamContainsRenderOptions): () => VNodeStreamContainsRenderOptions
ts
interface StreamContainsRenderOptions {
DefaultTag: Component
emit?: {
(event: 'update:data', value: StreamBlockData[]): void
(event: 'parse-warning', value: string): void
}
emptyClassName?: string // 默认: 'stream-content'
fastContainerClassName?: string // 默认: 'stream-ui-container mode-fast'
accurateContainerClassName?: string // 默认: 'stream-ui-container mode-accurate'
getUndefinedTagWarning?: (tagName: string) => string
getCrossedTagWarning?: (tagName: string, closedTags: string[]) => string
getIsolatedClosingTagWarning?: (tagName: string) => string
getParserWarningsTitle?: (count: number) => string
}StackNode
ts
interface StackNode {
tagName: string
attrs?: StreamBlockAttrs
children: (StackNode | string)[]
isClosed: boolean
}ComponentMap
ts
type ComponentMap = Record<string, Component>正则(源码中定义,仅供参考)
ts
// Fast 模式:单次匹配完整标签结构
const FAST_MODE_TAG_REGEX = /<([A-Za-z][\w-]*)(?:\s+[^>]*)?(?:(/>)|(?:>)([\s\S]*?)(?:<\/\1>|$))/gi
// Accurate 模式:分段匹配开/闭标签
const ACCURATE_MODE_TAG_REGEX = /<\/([A-Za-z][\w-]*(?:\s+[^>]*)?>|<([A-Za-z][\w-]*)(?:\s+[^>]*)?>/g
// 属性匹配
const ATTR_REGEX = /([^\s=\/>]+)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>`]+)))?/g