AI 组件

侧边信息栏

展示 AI 场景下的配置和详情信息

使用场景

侧边信息栏主要用于在 AI 场景下,用于信息展示,功能配置。包括 MCP 配置、参考来源、代码预览、富文本预览及编辑等功能

代码演示

如何引入

<script setup lang="ts">
    import { Annotation, MCPConfigure, Sidebar } from '@fibrous/semi-ai-vue';

    const { Container, CodeContent, CodeItem, FileContent, FileItem } = Sidebar;
    const { AnnotationContent } = Annotation;
</script>

基础容器

侧边信息栏的基础容器,基础容器是MCP 配置、参考来源、以及侧边消息栏的基础容器。

  • v-model:visible 控制显示和隐藏。点击关闭按钮,或在 closeOnEsc 为 true 时按下 Esc,会先更新为 false 再触发 cancel
  • title 设置纯文本标题,需要自定义内容时使用 #title 插槽
  • motion 设置是否有展开动画
  • resizable 设置宽度是否可伸缩,为 true 时候可通过 minWidth,maxWidth 设置最小,最大宽度
是否有动画
是否可伸缩
代码
<script setup lang="ts">
    import { shallowRef } from 'vue';
    import { Sidebar } from '@fibrous/semi-ai-vue';
    import { Button, Switch } from '@fibrous/semi-ui-vue';

    const { Container } = Sidebar;

    const containerStyle = {
        display: 'flex',
        height: '500px',
        border: '1px solid var(--semi-color-border)',
        borderRadius: '8px',
        overflow: 'hidden',
        boxSizing: 'border-box',
    } as const;

    const visible = shallowRef(true);
    const motion = shallowRef(true);
    const resizable = shallowRef(true);
</script>

<template>
    <div :style="containerStyle">
        <div :style="{ flexGrow: 1, flexShrink: 1, padding: '20px' }">
            <div>
                <Button :aria-pressed="visible" @click="visible = !visible">显示容器</Button>
                <div :style="{ display: 'flex', alignItems: 'center', marginTop: '10px' }">
                    <span id="sidebar-container-motion">是否有动画</span>
                    <Switch v-model="motion" aria-labelledby="sidebar-container-motion" />
                </div>
                <div :style="{ display: 'flex', alignItems: 'center', marginTop: '10px' }">
                    <span id="sidebar-container-resizable">是否可伸缩</span>
                    <Switch v-model="resizable" aria-labelledby="sidebar-container-resizable" />
                </div>
            </div>
        </div>
        <Container v-model:visible="visible" maxWidth="60%" :minWidth="250" :motion="motion" :resizable="resizable" :style="resizable ? undefined : { width: '200px' }" title="基础容器示例" />
    </div>
</template>

MCP 配置

使用 MCPConfigure 进行 MCP 工具的展示、启用/关闭、配置及搜索

  • 通过 v-model:options 和 v-model:customOptions 绑定内置的 MCP 工具和自定义 MCP 工具,切换启用/关闭时先更新绑定值,再触发 statusChange
  • 通过 v-model:visible 设置组件的显示和隐藏,使用 cancel 监听用户的关闭行为
  • 使用 statusChange 自定义处理 MCP 工具的启用/关闭
  • 使用 addClick 处理自定义 MCP 页的点击添加按钮后的操作
  • 可通过 configureClick 监听内置 MCP 工具的配置,通过 editClick 监听自定义 MCP 工具的配置
  • 工具项的图标和描述使用 #icon、#desc 插槽,整行用 #item 替换;插槽参数为 { item, index, custom }

其他 MCPConfigure 的 API 见 MCPConfigure

传入 MCP 工具项的类型如下

interface MCPConfigureOption {
    icon?: string; // 图片地址,其他内容使用 #icon 插槽
    label?: string;
    value: string; // 必填,标识工具项,需唯一
    desc?: string; // 纯文本,其他内容使用 #desc 插槽
    active?: boolean;
    disabled?: boolean;
    configure?: boolean; // 是否显示配置按钮
}

用例如下:

MCP 配置
已激活 MCP 数: 0/2
支持 Semi 的文档、源码搜索,辅助开发
Figma MCP Server 连接Figma与AI开发工具的功能。它通过标准化的模型上下文协MCP),将组件、变量等设计数据和上下文暴露给AI,从而实现从设计稿到代码的智能生成,显著提升开发效率。
代码
<script setup lang="ts">
    import { shallowRef, useTemplateRef, type Component } from 'vue';
    import { MCPConfigure, type MCPConfigureOption } from '@fibrous/semi-ai-vue';
    import { IconFigma, IconSemiLogo } from '@fibrous/semi-icons-vue';
    import { Button, Form, FormInput, FormTextArea, Modal, type FormHandle } from '@fibrous/semi-ui-vue';

    interface McpFormValues {
        name: string;
        src: string;
        desc: string;
    }

    const containerStyle = {
        display: 'flex',
        height: '500px',
        border: '1px solid var(--semi-color-border)',
        borderRadius: '8px',
        overflow: 'hidden',
        boxSizing: 'border-box',
    } as const;

    // icon only takes an image URL, so the built-in options get their icons from the #icon slot
    const builtinIcons: Record<string, Component> = {
        'Semi mcp': IconSemiLogo,
        figma: IconFigma,
    };

    const srcRules = [
        { required: true, message: '请输入 MCP 图标 URL' },
        {
            validator: (_rule: unknown, value: string) => /^(?:https?:\/\/)?(?:www\.)?[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)+(?::\d+)?(?:\/[^\s]*)?$/i.test(value),
            message: '请输入有效的 MCP 图标 URL',
        },
    ];

    let index = 1;

    const visible = shallowRef(true);
    const options = shallowRef<MCPConfigureOption[]>([
        {
            value: 'Semi mcp',
            label: 'Semi',
            configure: true,
            desc: '支持 Semi 的文档、源码搜索,辅助开发',
        },
        {
            value: 'figma',
            label: 'Figma',
            desc: 'Figma MCP Server 连接Figma与AI开发工具的功能。它通过标准化的模型上下文协MCP),将组件、变量等设计数据和上下文暴露给AI,从而实现从设计稿到代码的智能生成,显著提升开发效率。',
        },
    ]);
    const customOptions = shallowRef<MCPConfigureOption[]>([]);
    const modalVisible = shallowRef(false);
    const form = useTemplateRef<FormHandle<McpFormValues>>('form');

    const handleOk = () => {
        form.value?.formApi
            .validate()
            .then((values) => {
                customOptions.value = [
                    ...customOptions.value,
                    {
                        label: values.name,
                        icon: values.src,
                        value: `mcp-${index++}`,
                        desc: values.desc,
                    },
                ];
                modalVisible.value = false;
            })
            .catch((errors) => {
                console.log('errors', errors);
            });
    };

    const onConfigureClick = (_event: MouseEvent, option: MCPConfigureOption) => {
        console.log('configure click', option);
    };

    const onEditClick = (_event: MouseEvent, option: MCPConfigureOption) => {
        console.log('edit click', option);
    };
</script>

<template>
    <div :style="containerStyle">
        <div :style="{ flexGrow: 1, flexShrink: 1, padding: '20px' }">
            <Button :aria-pressed="visible" @click="visible = !visible">MCP 配置</Button>
        </div>
        <MCPConfigure v-model:customOptions="customOptions" v-model:options="options" v-model:visible="visible" :resizable="false" :style="{ width: '500px' }" @addClick="modalVisible = true" @configureClick="onConfigureClick" @editClick="onEditClick">
            <template #icon="{ item }">
                <img v-if="item.icon" alt="" :src="item.icon" :style="{ width: '100%', height: '100%' }" />
                <component :is="builtinIcons[item.value]" v-else />
            </template>
        </MCPConfigure>
        <Modal v-model:visible="modalVisible" closeOnEsc title="自定义 MCP" @ok="handleOk">
            <Form ref="form" layout="vertical" @valueChange="(values) => console.log(values)">
                <FormInput field="name" label="MCP 名称" :rules="[{ required: true, message: '请输入 MCP 名称' }]" :style="{ width: '100%' }" />
                <FormInput field="src" initValue="/assets/placeholder/avatar-a.svg" label="MCP 图标 URL" :rules="srcRules" :style="{ width: '100%' }" />
                <FormTextArea field="desc" label="MCP 介绍" :rules="[{ required: true, message: '请输入 MCP 介绍' }]" :style="{ width: '100%' }" />
            </Form>
        </Modal>
    </div>
</template>

参考来源

使用 Annotation 组件可以管理参考来源的展示

  • v-model:activeKey 管理当前展开的项
  • info 设置参考来源的具体内容
  • click 在点击某条参考来源时触发,参数为事件和该条目
  • 分组标题使用 #infoHeader 插槽,条目使用 #item 插槽替换;#header 是整个容器头部
代码
<script setup lang="ts">
    import { shallowRef } from 'vue';
    import { Annotation, type AnnotationInfo, type AnnotationItem } from '@fibrous/semi-ai-vue';
    import { Button } from '@fibrous/semi-ui-vue';

    const containerStyle = {
        display: 'flex',
        height: '500px',
        border: '1px solid var(--semi-color-border)',
        borderRadius: '8px',
        overflow: 'hidden',
        boxSizing: 'border-box',
    } as const;

    const logo = '/assets/placeholder/avatar-a.svg';
    const img = '/assets/root-web-sites/abstract.jpg';

    const defaultInfoList: AnnotationInfo[] = [
        {
            header: 'Semi design introduction',
            key: '1',
            annotations: [
                {
                    order: 1,
                    type: 'video',
                    duration: 4432,
                    title: 'Semi Design is a design system designed',
                    url: 'https://semi.design/',
                    logo,
                    siteName: 'Semi Design',
                    detail: ' As a comprehensive, easy-to-use, and high-quality modern enterprise-level application UI solution',
                    img,
                },
                {
                    order: 2,
                    title: 'Quick start',
                    type: 'video',
                    duration: 56,
                    url: 'https://semi.design/',
                    detail: ' As a comprehensive, easy-to-use, and high-quality modern enterprise-level application UI solution',
                    logo,
                    siteName: 'Semi Design',
                    img,
                },
                {
                    order: 3,
                    title: 'Use components in a modular way',
                    url: 'https://semi.design/',
                    detail: `Semi provides esm format dist, and the css of the component is only imported by the corresponding js.
When used in Webpack, Rspack, create-react-app or Vite projects, there is no need to configure any compilation items.`,
                    logo,
                    siteName: 'Semi Design',
                    img,
                },
            ],
        },
        {
            header: 'Design resource',
            key: '2',
            annotations: [
                {
                    order: 2,
                    title: 'Semi Design resource',
                    url: 'https://semi.design/',
                    detail: 'Semi Design provides a wealth of design resources to help designers and developers collaborate efficiently. Whether you are a community user or a ByteDance internal designer, you can find UI Kit resource and Figma plug-ins that suit you here.',
                    logo,
                    siteName: 'Semi Design resource',
                    img,
                },
            ],
        },
    ];

    const defaultSize = { width: 420 };
    const visible = shallowRef(true);
    const activeKey = shallowRef<string | string[]>('1');

    const onChange = (key: string | string[]) => {
        console.log('change', key);
    };

    const onClick = (event: MouseEvent, item: AnnotationItem) => {
        console.log('click', event, item);
    };
</script>

<template>
    <div :style="containerStyle">
        <div :style="{ flexGrow: 1, flexShrink: 1, padding: '20px' }">
            <Button :aria-pressed="visible" @click="visible = !visible">参考来源</Button>
        </div>
        <Annotation v-model:activeKey="activeKey" v-model:visible="visible" :defaultSize="defaultSize" :info="defaultInfoList" @change="onChange" @click="onClick" />
    </div>
</template>

代码展示

可通过 Sidebar 中的 CodeItem 展示代码,CodeItem 基于 JsonViewer 以及 CodeHighlight 实现。

  • content: 内容字符串
  • isJson: 是否为 json
  • language: 编程语言名称,同 CodeHighlight 的 language,需先通过 CodeHighlight.register 注册
  • jsonViewerProps: 配置其他 JsonViewer 参数
  • codeHighlightProps: 配置其他 CodeHighlight 参数

jsonViewerProps 中 JsonViewer 的 value 在 Vue 中叫 modelValue,jsonViewerProps 与 codeHighlightProps 还可以带 class、style。JsonViewer 的自定义渲染与搜索按钮通过 CodeItem 的 #customRender、#searchButton 插槽使用。

代码
<script setup lang="ts">
    import { computed, shallowRef } from 'vue';
    import { Sidebar } from '@fibrous/semi-ai-vue';
    import { Radio, RadioGroup, type RadioValue } from '@fibrous/semi-ui-vue';

    const { CodeItem } = Sidebar;

    const code = `.semi-animation-react-demo-auto {
    button {
        height: 50px;
        border: 0;
        cursor: pointer !important;
        background: #777;
        color: white;
        outline: none;
        -webkit-appearance: none;
    }

    button:hover {
        background: #878787;
    }

    .auto-main {
        display: grid;
        grid-template-columns: repeat(3, 1fr);
        grid-template-rows: auto 1fr;
        background: #575757;
    }

    .content {
        grid-column: span 3;
    }

    .item {
        background: indianred;
        width: 100%;
        overflow: hidden;
        color: white;
    }

    .item p {
        margin: 0;
        padding: 10px;
    }
}
`;

    const json = `{
    "axisX": {
        "title": {
            "visible": false,
            "position": "center"
        },
        "label": {
            "visible": true,
            "style": {
                "fontSize": 12,
                "fontWeight": 400,
                "lineHeight": 16,
                "fontFamily": [
                    "Inter"
                ],
                "fill": "rgba(0, 0, 0, 0.47843137254901963)"
            },
            "space": 12
        }
    }
}`;

    const codeProps = {
        content: code,
        language: 'css',
    };

    const jsonProps = {
        isJson: true,
        content: json,
    };

    const type = shallowRef<RadioValue | undefined>('json');
    const itemProps = computed(() => (type.value === 'json' ? jsonProps : codeProps));
</script>

<template>
    <RadioGroup v-model="type" buttonSize="middle" :style="{ marginBottom: '10px' }" type="button">
        <Radio value="json">JSON</Radio>
        <Radio value="css">CSS</Radio>
    </RadioGroup>
    <div :style="{ height: '200px', overflow: 'auto' }">
        <CodeItem v-bind="itemProps" />
    </div>
</template>

代码列表

用户可通过 Sidebar 中的 CodeContent 组件展示代码列表信息。

  • v-model:activeKey 管理当前展开的面板
  • expand 监听面板头部的展开按钮
  • #customRender、#searchButton 转发给每个 JSON 面板中的 JsonViewer
import React from 'react';
import { AutoComplete } from '@fibrous/semi-ui-react';
import { IconSearch } from '@fibrous/semi-icons-react';

() => {
    const [stringData, setStringData] = useState([]);
    const [value, setValue] = useState('');
    const handleStringSearch = (value) => {
        let result;
        if (value) {
            result = ['gmail.com', '163.com', 'qq.com'].map(domain => value+domain);
        } else {
            result = [];
        }
        setStringData(result);
    };

    const handleChange = (value) => {
        console.log('onChange', value);
        setValue(value);
    };
    return (
        <AutoComplete
            data={stringData}
            value={value}
            showClear
            prefix={<IconSearch />}
            placeholder="搜索... "
            onSearch={handleStringSearch}
            onChange={handleChange}
            style={{ width: 200 }}
        />
    );
};
代码
<script setup lang="ts">
    import { shallowRef } from 'vue';
    import { Sidebar } from '@fibrous/semi-ai-vue';

    const { CodeContent } = Sidebar;

    const defaultCodes = [
        {
            name: 'Component.js',
            key: 'code1',
            language: 'javascript',
            content: `import React from 'react';
import { AutoComplete } from '@fibrous/semi-ui-react';
import { IconSearch } from '@fibrous/semi-icons-react';

() => {
    const [stringData, setStringData] = useState([]);
    const [value, setValue] = useState('');
    const handleStringSearch = (value) => {
        let result;
        if (value) {
            result = ['gmail.com', '163.com', 'qq.com'].map(domain => value+domain);
        } else {
            result = [];
        }
        setStringData(result);
    };

    const handleChange = (value) => {
        console.log('onChange', value);
        setValue(value);
    };
    return (
        <AutoComplete
            data={stringData}
            value={value}
            showClear
            prefix={<IconSearch />}
            placeholder="搜索... "
            onSearch={handleStringSearch}
            onChange={handleChange}
            style={{ width: 200 }}
        />
    );
};
`,
        },
        {
            name: 'Style.css',
            key: 'code2',
            language: 'css',
            content: `.semi-animation-react-demo-auto {
    button {
        height: 50px;
        border: 0;
        cursor: pointer !important;
        background: #777;
        color: white;
        outline: none;
        -webkit-appearance: none;
    }

    button:hover {
        background: #878787;
    }

    .auto-main {
        display: grid;
        grid-template-columns: repeat(3, 1fr);
        grid-template-rows: auto 1fr;
        background: #575757;
    }

    .content {
        grid-column: span 3;
    }

    .item {
        background: indianred;
        width: 100%;
        overflow: hidden;
        color: white;
    }

    .item p {
        margin: 0;
        padding: 10px;
    }
}
`,
        },
        {
            name: 'Chart.json',
            key: 'code3',
            isJson: true,
            language: 'html',
            content: `{
    "axisX": {
        "title": {
            "visible": false,
            "position": "center"
        },
        "label": {
            "visible": true,
            "style": {
                "fontSize": 12,
                "fontWeight": 400,
                "lineHeight": 16,
                "fontFamily": [
                    "Inter"
                ],
                "fill": "rgba(0, 0, 0, 0.47843137254901963)"
            },
            "space": 12
        },
        "domainLine": {
            "visible": true,
            "style": {
                "lineWidth": 1,
                "stroke": "rgba(0, 0, 0, 0.12156862745098039)",
                "lineDash": []
            }
        },
        "tick": {
            "visible": false,
            "style": {
                "lineWidth": 1,
                "stroke": "rgba(255, 255, 255, 0)"
            }
        },
        "subTick": {
            "visible": false
        },
        "grid": {
            "visible": false
        },
        "subGrid": {
            "visible": false
        }
    }
}`,
        },
    ];

    const activeKey = shallowRef<string | string[]>('code1');
</script>

<template>
    <div class="semi-sidebar-main">
        <CodeContent v-model:activeKey="activeKey" :codes="defaultCodes" :style="{ width: '600px' }" />
    </div>
</template>

富文本编辑器

可通过 Sidebar 中的 FileItem 查看、编辑富文本内容, FileItem 基于 tiptap 实现。

  • content:富文本 HTML。挂载后变化会同步到编辑器,与编辑器当前内容相同时不会重置,不会打断输入也不会丢失光标,同步不触发 contentChange
  • editable: 设置是否可编辑,挂载后变化会同步到编辑器
  • imgUploadProps: 设置图片上传路径以及图片上传后 src 的设置,通过 action 设置上传地址,通过 getUploadImageSrc(response) 函数根据上传响应返回图片上传后地址(未提供时,响应是字符串则直接作为地址,否则取 response.src),用于富文本中 img 节点的 src;Upload 的 on 开头监听(如 onSuccess)也可在这里传入。只有设置了 action 或 customRequest,工具栏才显示图片按钮
  • extensions 与 imgUploadProps 只在创建编辑器时读取,要换用新值时更换 key 重新挂载
  • contentChange 在编辑后触发,参数为 HTML 字符串


代码
<script setup lang="ts">
    import { shallowRef } from 'vue';
    import { Sidebar, type ImageUploadNodeOptions } from '@fibrous/semi-ai-vue';
    import { Button } from '@fibrous/semi-ui-vue';

    const { FileItem } = Sidebar;

    const content = `<h2>
  Semi Design 介绍
</h2>
<p>
  Semi Design 是由 <strong>抖音前端团队</strong>和MED产品设计团队设计、开发并维护的<em>设计系统</em>。作为一个全面、易用、优质的现代应用UI解决方案,Semi Design从字节跳动各业务线的复杂场景中提炼而来,目前已经支撑了近千个平台产品,服务了内外部超过10万用户,详情见https://semi.design/zh-CN/start/introduction。Semi Design的特点包括:
</p>
<ul>
  <li>
    设计简洁、现代化。
  </li>
  <li>
    提供主题方案,可深度样式定制。
  </li>
</ul>
<p>
  国际化,覆盖了简/繁体中文、英语、日语、韩语、葡萄牙语等20+种语言,日期时间组件提供全球时区支持,全部组件可自动适配阿拉伯文RTL布局。
</p>
<pre><code class="language-css">body {
  display: none;
}</code></pre>
<p>
  采用 Foundation 和 Adapter 跨框架技术方案,方便扩展。
</p>
<blockquote>
  Semi Design 是由抖音前端团队和MED产品设计团队设计、开发并维护的设计系统
  <br />
  — Semi Design
</blockquote>`;

    const imgUploadProps: ImageUploadNodeOptions = {
        action: 'https://api.semi.design/upload',
        // response is the action's result; real code reads the uploaded image URL from it
        getUploadImageSrc: () => '/assets/placeholder/avatar-a.svg',
    };

    const editable = shallowRef(true);
</script>

<template>
    <Button :aria-pressed="editable" @click="editable = !editable">可编辑</Button>
    <br />
    <br />
    <FileItem :content="content" :editable="editable" :imgUploadProps="imgUploadProps" name="Semi Design 介绍" :style="{ border: '1px solid var(--semi-color-border)', padding: '12px' }" />
</template>

富文本列表

用户可通过 Sidebar 中的 FileContent 组件展示富文本列表信息。

  • v-model:activeKey 管理当前展开的面板
  • expand 监听面板头部的展开按钮
代码
<script setup lang="ts">
    import { shallowRef } from 'vue';
    import { Sidebar } from '@fibrous/semi-ai-vue';

    const { FileContent } = Sidebar;

    const defaultFiles = [
        {
            key: 'file1',
            name: 'Semi Design 介绍',
            content: `
<h2>
  Semi Design 介绍
</h2>
<p>
  Semi Design 是由 <strong>抖音前端团队</strong>和MED产品设计团队设计、开发并维护的<em>设计系统</em>。作为一个全面、易用、优质的现代应用UI解决方案,Semi Design从字节跳动各业务线的复杂场景中提炼而来,目前已经支撑了近千个平台产品,服务了内外部超过10万用户,详情见https://semi.design/zh-CN/start/introduction。Semi Design的特点包括:
</p>
<ul>
  <li>
    设计简洁、现代化。
  </li>
  <li>
    提供主题方案,可深度样式定制。
  </li>
</ul>
<p>
  国际化,覆盖了简/繁体中文、英语、日语、韩语、葡萄牙语等20+种语言,日期时间组件提供全球时区支持,全部组件可自动适配阿拉伯文RTL布局。
</p>
<pre><code class="language-css">body {
  display: none;
}</code></pre>
<p>
  采用 Foundation 和 Adapter 跨框架技术方案,方便扩展。
</p>
<blockquote>
  Semi Design 是由抖音前端团队和MED产品设计团队设计、开发并维护的设计系统
  <br />
  — Semi Design
</blockquote>
<p>
  Semi Design 是由 <strong>抖音前端团队</strong>和MED产品设计团队设计、开发并维护的<em>设计系统</em>。作为一个全面、易用、优质的现代应用UI解决方案,Semi Design从字节跳动各业务线的复杂场景中提炼而来,目前已经支撑了近千个平台产品,服务了内外部超过10万用户,详情见https://semi.design/zh-CN/start/introduction。Semi Design的特点包括:
</p>
<ul>
  <li>
    设计简洁、现代化。
  </li>
  <li>
    提供主题方案,可深度样式定制。
  </li>
</ul>
<p>
  国际化,覆盖了简/繁体中文、英语、日语、韩语、葡萄牙语等20+种语言,日期时间组件提供全球时区支持,全部组件可自动适配阿拉伯文RTL布局。
</p>
<pre><code class="language-css">body {
  display: none;
}</code></pre>
<p>
  采用 Foundation 和 Adapter 跨框架技术方案,方便扩展。
</p>
<blockquote>
  Semi Design 是由抖音前端团队和MED产品设计团队设计、开发并维护的设计系统
  <br />
  — Semi Design
</blockquote>
<p>
  Semi Design 是由 <strong>抖音前端团队</strong>和MED产品设计团队设计、开发并维护的<em>设计系统</em>。作为一个全面、易用、优质的现代应用UI解决方案,Semi Design从字节跳动各业务线的复杂场景中提炼而来,目前已经支撑了近千个平台产品,服务了内外部超过10万用户,详情见https://semi.design/zh-CN/start/introduction。Semi Design的特点包括:
</p>
<ul>
  <li>
    设计简洁、现代化。
  </li>
  <li>
    提供主题方案,可深度样式定制。
  </li>
</ul>
<p>
  国际化,覆盖了简/繁体中文、英语、日语、韩语、葡萄牙语等20+种语言,日期时间组件提供全球时区支持,全部组件可自动适配阿拉伯文RTL布局。
</p>
<pre><code class="language-css">body {
  display: none;
}</code></pre>
<p>
  采用 Foundation 和 Adapter 跨框架技术方案,方便扩展。
</p>
<blockquote>
  Semi Design 是由抖音前端团队和MED产品设计团队设计、开发并维护的设计系统
  <br />
  — Semi Design
</blockquote>
`,
        },
        {
            key: 'file2',
            name: 'Semi Design DSM',
            content: `<h2>
  Semi Design DSM
</h2>
<p>Semi DSM is a design system management tool provided by Semi Design. It supports global and component-level style customization and keeps synchronization between Figma and front-end code. Suitable for teams of all sizes. Whether you need to simplify workflow, improve team collaboration, or increase productivity, we have features suitable for you.</p>
`,
        },
        {
            key: 'file3',
            name: 'React v19 Adaptation',
            content: `<h2>
  React v19 Adaptation
</h2>
<p>Since the release of React v19, React has introduced numerous underlying mechanism and API changes, including upgrades and adjustments to the render mechanism, ref, context, TypeScript types, and related deprecated APIs. To ensure that the Semi Design component library is smoothly compatible with both React v19 and lower versions, we provide the original component package @fibrous/semi-ui-react for React versions below v19, as well as a new package @fibrous/semi-ui-19 specifically adapted for React v19, so users can choose as needed. This guide will help you understand how to install, use, and the precautions to take.
Installation & Usage
If your project is using React v19, please use @fibrous/semi-ui-19. For React versions below v19, continue using @fibrous/semi-ui-react as before.</p>
`,
        },
    ];

    const activeKey = shallowRef<string | string[]>('file1');
</script>

<template>
    <div class="semi-sidebar-main">
        <FileContent v-model:activeKey="activeKey" :files="defaultFiles" :style="{ width: '600px' }" />
    </div>
</template>

侧边信息栏

侧边信息栏 Sidebar 有主视图(mode 为 main)和详情视图(mode 为 code、file 及其他)。

主视图可以通过 title 或 #title 插槽配置标题,通过 showClose 决定是否展示关闭按钮,通过 options 设置顶部的按钮组(每项为 { name, key }),v-model:activeKey 绑定当前选中的项。按钮图标使用 #optionIcon="{ item, index }" 插槽,需要替换整个按钮时使用 #optionItem,其参数 onClick 用于选中该项。

对于主视图的内容渲染,可通过 #mainContent="{ activeKey }" 插槽,根据当前选中项渲染。可使用 Annotation 中的 AnnotationContent 渲染参考来源,使用 Sidebar 中内置的 FileContent 渲染富文本, CodeContent 渲染代码。

对于详情视图,如果是富文本或者代码,分别设置 mode 为 code、file,通过 detailContent 设置显示内容,即可通过内置的代码显示组件, 富文本编辑器进行显示;detailContent 的 key 变化时会重新挂载。如果想要自定义详情视图的展示,则通过 #detailContent="{ mode }" 插槽自行渲染,详情头部通过 #detailHeader="{ mode, detailContent }" 自定义,两者内容为空时回退到内置内容。点击详情头部的返回按钮触发 backWard。

工作区占位
代码
<script setup lang="ts">
    import { shallowRef, type Component } from 'vue';
    import { Annotation, Sidebar, type AnnotationInfo, type ImageUploadNodeOptions, type SideBarDetailContent } from '@fibrous/semi-ai-vue';
    import { IconBriefStroked, IconCodeStroked, IconModalStroked, IconSearch } from '@fibrous/semi-icons-vue';

    const { FileContent, CodeContent } = Sidebar;
    const { AnnotationContent } = Annotation;

    const containerStyle = {
        display: 'flex',
        height: '800px',
        border: '1px solid var(--semi-color-border)',
        borderRadius: '8px',
        overflow: 'hidden',
        boxSizing: 'border-box',
    } as const;

    const optionList = [
        {
            name: '查看搜索',
            key: 'searchResult',
        },
        {
            name: '文件预览',
            key: 'filePreview',
        },
        {
            name: '代码预览',
            key: 'codePreview',
        },
        {
            name: '浏览器',
            key: 'network',
        },
    ];

    const optionIcons: Record<string, Component> = {
        searchResult: IconSearch,
        filePreview: IconBriefStroked,
        codePreview: IconCodeStroked,
        network: IconModalStroked,
    };

    const defaultCodes = [
        {
            name: 'Component.js',
            key: 'code1',
            language: 'javascript',
            content: `import React from 'react';
import { AutoComplete } from '@fibrous/semi-ui-react';
import { IconSearch } from '@fibrous/semi-icons-react';

() => {
    const [stringData, setStringData] = useState([]);
    const [value, setValue] = useState('');
    const handleStringSearch = (value) => {
        let result;
        if (value) {
            result = ['gmail.com', '163.com', 'qq.com'].map(domain => value+domain);
        } else {
            result = [];
        }
        setStringData(result);
    };

    const handleChange = (value) => {
        console.log('onChange', value);
        setValue(value);
    };
    return (
        <AutoComplete
            data={stringData}
            value={value}
            showClear
            prefix={<IconSearch />}
            placeholder="搜索... "
            onSearch={handleStringSearch}
            onChange={handleChange}
            style={{ width: 200 }}
        />
    );
};
`,
        },
        {
            name: 'Style.css',
            key: 'code2',
            language: 'css',
            content: `.semi-animation-react-demo-auto {
    button {
        height: 50px;
        border: 0;
        cursor: pointer !important;
        background: #777;
        color: white;
        outline: none;
        -webkit-appearance: none;
    }

    button:hover {
        background: #878787;
    }

    .auto-main {
        display: grid;
        grid-template-columns: repeat(3, 1fr);
        grid-template-rows: auto 1fr;
        background: #575757;
    }

    .content {
        grid-column: span 3;
    }

    .item {
        background: indianred;
        width: 100%;
        overflow: hidden;
        color: white;
    }

    .item p {
        margin: 0;
        padding: 10px;
    }
}
`,
        },
        {
            name: 'Chart.json',
            key: 'code3',
            isJson: true,
            language: 'html',
            content: `{
    "axisX": {
        "title": {
            "visible": false,
            "position": "center"
        },
        "label": {
            "visible": true,
            "style": {
                "fontSize": 12,
                "fontWeight": 400,
                "lineHeight": 16,
                "fontFamily": [
                    "Inter"
                ],
                "fill": "rgba(0, 0, 0, 0.47843137254901963)"
            },
            "space": 12
        },
        "domainLine": {
            "visible": true,
            "style": {
                "lineWidth": 1,
                "stroke": "rgba(0, 0, 0, 0.12156862745098039)",
                "lineDash": []
            }
        },
        "tick": {
            "visible": false,
            "style": {
                "lineWidth": 1,
                "stroke": "rgba(255, 255, 255, 0)"
            }
        },
        "subTick": {
            "visible": false
        },
        "grid": {
            "visible": false
        },
        "subGrid": {
            "visible": false
        }
    }
}`,
        },
    ];

    const defaultFiles = [
        {
            key: 'file1',
            name: 'Semi Design 介绍',
            content: `
<h2>
  Semi Design 介绍
</h2>
<p>
  Semi Design 是由 <strong>抖音前端团队</strong>和MED产品设计团队设计、开发并维护的<em>设计系统</em>。作为一个全面、易用、优质的现代应用UI解决方案,Semi Design从字节跳动各业务线的复杂场景中提炼而来,目前已经支撑了近千个平台产品,服务了内外部超过10万用户,详情见https://semi.design/zh-CN/start/introduction。Semi Design的特点包括:
</p>
<ul>
  <li>
    设计简洁、现代化。
  </li>
  <li>
    提供主题方案,可深度样式定制。
  </li>
</ul>
<p>
  国际化,覆盖了简/繁体中文、英语、日语、韩语、葡萄牙语等20+种语言,日期时间组件提供全球时区支持,全部组件可自动适配阿拉伯文RTL布局。
</p>
<pre><code class="language-css">body {
  display: none;
}</code></pre>
<p>
  采用 Foundation 和 Adapter 跨框架技术方案,方便扩展。
</p>
<blockquote>
  Semi Design 是由抖音前端团队和MED产品设计团队设计、开发并维护的设计系统
  <br />
  — Semi Design
</blockquote>
<p>
  Semi Design 是由 <strong>抖音前端团队</strong>和MED产品设计团队设计、开发并维护的<em>设计系统</em>。作为一个全面、易用、优质的现代应用UI解决方案,Semi Design从字节跳动各业务线的复杂场景中提炼而来,目前已经支撑了近千个平台产品,服务了内外部超过10万用户,详情见https://semi.design/zh-CN/start/introduction。Semi Design的特点包括:
</p>
<ul>
  <li>
    设计简洁、现代化。
  </li>
  <li>
    提供主题方案,可深度样式定制。
  </li>
</ul>
<p>
  国际化,覆盖了简/繁体中文、英语、日语、韩语、葡萄牙语等20+种语言,日期时间组件提供全球时区支持,全部组件可自动适配阿拉伯文RTL布局。
</p>
<pre><code class="language-css">body {
  display: none;
}</code></pre>
<p>
  采用 Foundation 和 Adapter 跨框架技术方案,方便扩展。
</p>
<blockquote>
  Semi Design 是由抖音前端团队和MED产品设计团队设计、开发并维护的设计系统
  <br />
  — Semi Design
</blockquote>
<p>
  Semi Design 是由 <strong>抖音前端团队</strong>和MED产品设计团队设计、开发并维护的<em>设计系统</em>。作为一个全面、易用、优质的现代应用UI解决方案,Semi Design从字节跳动各业务线的复杂场景中提炼而来,目前已经支撑了近千个平台产品,服务了内外部超过10万用户,详情见https://semi.design/zh-CN/start/introduction。Semi Design的特点包括:
</p>
<ul>
  <li>
    设计简洁、现代化。
  </li>
  <li>
    提供主题方案,可深度样式定制。
  </li>
</ul>
<p>
  国际化,覆盖了简/繁体中文、英语、日语、韩语、葡萄牙语等20+种语言,日期时间组件提供全球时区支持,全部组件可自动适配阿拉伯文RTL布局。
</p>
<pre><code class="language-css">body {
  display: none;
}</code></pre>
<p>
  采用 Foundation 和 Adapter 跨框架技术方案,方便扩展。
</p>
<blockquote>
  Semi Design 是由抖音前端团队和MED产品设计团队设计、开发并维护的设计系统
  <br />
  — Semi Design
</blockquote>
`,
        },
        {
            key: 'file2',
            name: 'Semi Design DSM',
            content: `<h2>
  Semi Design DSM
</h2>
<p>Semi DSM is a design system management tool provided by Semi Design. It supports global and component-level style customization and keeps synchronization between Figma and front-end code. Suitable for teams of all sizes. Whether you need to simplify workflow, improve team collaboration, or increase productivity, we have features suitable for you.</p>
`,
        },
        {
            key: 'file3',
            name: 'React v19 Adaptation',
            content: `<h2>
  React v19 Adaptation
</h2>
<p>Since the release of React v19, React has introduced numerous underlying mechanism and API changes, including upgrades and adjustments to the render mechanism, ref, context, TypeScript types, and related deprecated APIs. To ensure that the Semi Design component library is smoothly compatible with both React v19 and lower versions, we provide the original component package @fibrous/semi-ui-react for React versions below v19, as well as a new package @fibrous/semi-ui-19 specifically adapted for React v19, so users can choose as needed. This guide will help you understand how to install, use, and the precautions to take.
Installation & Usage
If your project is using React v19, please use @fibrous/semi-ui-19. For React versions below v19, continue using @fibrous/semi-ui-react as before.</p>
`,
        },
    ];

    const logo = '/assets/placeholder/avatar-a.svg';
    const img = '/assets/root-web-sites/abstract.jpg';

    const defaultInfoList: AnnotationInfo[] = [
        {
            header: 'Semi design introduction',
            key: '1',
            annotations: [
                {
                    order: 1,
                    type: 'video',
                    duration: 4432,
                    title: 'Semi Design is a design system designed',
                    url: 'https://semi.design/',
                    logo,
                    siteName: 'Semi Design',
                    detail: ' As a comprehensive, easy-to-use, and high-quality modern enterprise-level application UI solution',
                    img,
                },
                {
                    order: 2,
                    title: 'Quick start',
                    type: 'video',
                    duration: 56,
                    url: 'https://semi.design/',
                    detail: ' As a comprehensive, easy-to-use, and high-quality modern enterprise-level application UI solution',
                    logo,
                    siteName: 'Semi Design',
                    img,
                },
                {
                    order: 3,
                    title: 'Use components in a modular way',
                    url: 'https://semi.design/',
                    detail: `Semi provides esm format dist, and the css of the component is only imported by the corresponding js.
When used in Webpack, Rspack, create-react-app or Vite projects, there is no need to configure any compilation items.`,
                    logo,
                    siteName: 'Semi Design',
                    img,
                },
            ],
        },
        {
            header: 'Design resource',
            key: '2',
            annotations: [
                {
                    order: 2,
                    title: 'Semi Design resource',
                    url: 'https://semi.design/',
                    detail: 'Semi Design provides a wealth of design resources to help designers and developers collaborate efficiently. Whether you are a community user or a ByteDance internal designer, you can find UI Kit resource and Figma plug-ins that suit you here.',
                    logo,
                    siteName: 'Semi Design resource',
                    img,
                },
            ],
        },
    ];

    const imgUploadProps: ImageUploadNodeOptions = {
        action: 'https://api.semi.design/upload',
        // response is the action's result; real code reads the uploaded image URL from it
        getUploadImageSrc: () => logo,
    };

    const defaultSize = { width: '60%' };
    const mode = shallowRef('main');
    const activeKey = shallowRef('codePreview');
    const activeCodeKey = shallowRef<string | string[]>('code1');
    const activeFileKey = shallowRef<string | string[]>('file1');
    const activeReferKey = shallowRef<string | string[]>('1');
    const currentDetail = shallowRef<SideBarDetailContent>();

    const onExpand = (_event: MouseEvent, content: SideBarDetailContent, expandMode: string) => {
        mode.value = expandMode;
        currentDetail.value = content;
    };
</script>

<template>
    <div :style="containerStyle">
        <div :style="{ flexGrow: 1, flexShrink: 1, padding: '20px' }">工作区占位</div>
        <Sidebar v-model:activeKey="activeKey" :defaultSize="defaultSize" :detailContent="currentDetail" :imgUploadProps="imgUploadProps" :mode="mode" :motion="false" :options="optionList" :showClose="false" title="Agent 的工作空间" visible @backWard="(_event, backMode) => (mode = backMode)">
            <template #optionIcon="{ item }">
                <component :is="optionIcons[item.key]" />
            </template>
            <template #mainContent="{ activeKey: currentKey }">
                <AnnotationContent v-if="currentKey === 'searchResult'" v-model:activeKey="activeReferKey" :info="defaultInfoList" />
                <FileContent v-else-if="currentKey === 'filePreview'" v-model:activeKey="activeFileKey" :files="defaultFiles" @expand="onExpand" />
                <CodeContent v-else-if="currentKey === 'codePreview'" v-model:activeKey="activeCodeKey" :codes="defaultCodes" @expand="onExpand" />
                <img v-else-if="currentKey === 'network'" alt="network" src="/assets/root-web-sites/test.jpg" :style="{ width: '100%' }" />
            </template>
        </Sidebar>
    </div>
</template>

API 参考

Sidebar、Annotation、MCPConfigure 与 Container 的 class、style 和其他未声明的属性(如 aria-label)落在 .semi-sidebar-container 元素上;根元素被命名(aria-label 或 aria-labelledby)且没有指定 role 时,role 为 group。CodeContent、CodeItem、FileContent、FileItem、AnnotationContent 的未声明属性落在各自的根元素上。

Sidebar、Annotation、MCPConfigure 与 Sidebar.Container 的模板 ref 类型为 SidebarContainerHandle(从 @fibrous/semi-ai-vue 导出),成员 root 为 HTMLDivElement | null,容器隐藏时为 null。

Container

Props

属性说明类型默认值
visible是否显示容器,配合 v-model:visible 使用。booleanfalse
title纯文本标题;传入 title 插槽时以插槽为准。stringundefined
motion显示与隐藏时是否使用展开动画。booleantrue
resizable宽度是否可拖拽调整;为 true 时 minWidth、maxWidth 与 defaultSize 生效。booleantrue
minWidth可调整的最小宽度,仅在 resizable 为 true 时生效。string | number150
maxWidth可调整的最大宽度,仅在 resizable 为 true 时生效。string | numberundefined
defaultSize初始宽高,仅在 resizable 为 true 时生效。Type{ width?: string | number | undefined; height?: string | number | undefined; }undefined
showClose是否显示头部的关闭按钮。booleantrue
closeOnEsc按下 Esc 键时是否触发 cancel。booleanfalse

Events

事件说明回调参数
update:visible关闭按钮或 Esc 触发取消时先于 cancel 触发,值为 false,供 v-model:visible 回写。[visible: false]
cancel点击关闭按钮,或在 closeOnEsc 为 true 时按下 Esc 触发。[event: MouseEvent | KeyboardEvent]
afterVisibleChange显示或隐藏动画结束后触发,参数为当前是否可见。[visible: boolean]

Slots

插槽说明作用域参数
default容器的内容区域。any
title头部标题,优先于 title 属性。any
header替换整个头部;内容为空时回退到内置头部。any

Exposes

名称说明类型
root容器根元素 .semi-sidebar-container;隐藏时为 null。HTMLDivElement | null

MCPConfigure

Props

属性说明类型默认值
visible是否显示,配合 v-model:visible 使用。booleansemiGlobalDefault("MCPConfigure", "visible")
title纯文本标题,默认使用语言包中的 MCP 配置;传入 title 插槽时以插槽为准。stringsemiGlobalDefault("MCPConfigure", "title")
motion显示与隐藏时是否使用展开动画。booleansemiGlobalDefault("MCPConfigure", "motion")
resizable宽度是否可拖拽调整;为 true 时 minWidth、maxWidth 与 defaultSize 生效。booleansemiGlobalDefault("MCPConfigure", "resizable")
minWidth可调整的最小宽度,仅在 resizable 为 true 时生效。string | numbersemiGlobalDefault("MCPConfigure", "minWidth")
maxWidth可调整的最大宽度,仅在 resizable 为 true 时生效。string | numbersemiGlobalDefault("MCPConfigure", "maxWidth")
defaultSize初始宽高,仅在 resizable 为 true 时生效。Type{ width?: string | number | undefined; height?: string | number | undefined; }semiGlobalDefault("MCPConfigure", "defaultSize")
showClose是否显示头部的关闭按钮。booleansemiGlobalDefault("MCPConfigure", "showClose")
closeOnEsc按下 Esc 键时是否触发 cancel。booleansemiGlobalDefault("MCPConfigure", "closeOnEsc")
options内置 MCP 工具列表,配合 v-model:options 使用;每项的 value 必填且唯一。MCPConfigureOption[]semiGlobalDefault("MCPConfigure", "options")
customOptions自定义 MCP 工具列表,配合 v-model:customOptions 使用。MCPConfigureOption[]semiGlobalDefault("MCPConfigure", "customOptions")
filter自定义搜索过滤,参数为转为小写的输入值和选项;默认按 label 与 desc 匹配。Type((inputValue: string, option: MCPConfigureOption) => boolean)undefined
placeholder搜索框的占位文字,默认使用语言包文案。stringsemiGlobalDefault("MCPConfigure", "placeholder")

Events

事件说明回调参数
update:visible关闭按钮或 Esc 触发取消时先于 cancel 触发,值为 false,供 v-model:visible 回写。[visible: false]
cancel点击关闭按钮,或在 closeOnEsc 为 true 时按下 Esc 触发。[event: MouseEvent | KeyboardEvent]
afterVisibleChange显示或隐藏动画结束后触发,参数为当前是否可见。[visible: boolean]
update:options切换内置工具的启用状态时先于 statusChange 触发,供 v-model:options 回写。[options: MCPConfigureOption[]]
update:customOptions切换自定义工具的启用状态时先于 statusChange 触发,供 v-model:customOptions 回写。[options: MCPConfigureOption[]]
statusChange切换启用状态后触发,参数为 active 已更新的列表,以及它是否为自定义列表。[options: MCPConfigureOption[], custom: boolean]
search搜索输入变化时触发,参数为输入值,以及当前是否为自定义列表。[inputValue: string, custom: boolean]
addClick点击自定义页的新增按钮时触发。[event: MouseEvent]
configureClick点击内置工具的配置按钮时触发,参数为点击事件和对应选项。[event: MouseEvent, option: MCPConfigureOption]
editClick点击自定义工具的编辑按钮时触发,参数为点击事件和对应选项。[event: MouseEvent, option: MCPConfigureOption]

Slots

插槽说明作用域参数
title头部标题,优先于 title 属性。any
header替换整个头部;内容为空时回退到内置头部。any
icon选项的图标,作用域参数为 item、index 和 custom;提供后所有选项都使用它,icon 字段只在未提供时作为图片地址。MCPConfigureItemSlotProps
desc选项的描述,作用域参数为 item、index 和 custom;未提供时显示 desc 字段。MCPConfigureItemSlotProps
item替换整行内置选项,作用域参数为 item、index 和 custom。MCPConfigureItemSlotProps

Exposes

名称说明类型
root容器根元素 .semi-sidebar-container;隐藏时为 null。HTMLDivElement | null

MCPConfigureOption

属性说明类型默认值
active是否处于激活状态booleanfalse
configure是否显示配置按钮booleanfalse
desc描述文本,内置过滤会匹配它;其他内容使用 #desc 插槽string-
disabled是否禁用,为 true 时用户无法更改激活状态booleanfalse
icon图标的图片地址;其他内容使用 #icon 插槽string-
label标签文本string-
value对应的值,必填。在 statusChange 中标识选项,也作为列表项的 key,同一列表内需唯一string-

Annotation

Props

属性说明类型默认值
visible是否显示,配合 v-model:visible 使用。booleansemiGlobalDefault("Annotation", "visible")
title纯文本标题,默认使用语言包中的参考来源;传入 title 插槽时以插槽为准。stringsemiGlobalDefault("Annotation", "title")
motion显示与隐藏时是否使用展开动画。booleansemiGlobalDefault("Annotation", "motion")
resizable宽度是否可拖拽调整;为 true 时 minWidth、maxWidth 与 defaultSize 生效。booleansemiGlobalDefault("Annotation", "resizable")
minWidth可调整的最小宽度,仅在 resizable 为 true 时生效。string | numbersemiGlobalDefault("Annotation", "minWidth")
maxWidth可调整的最大宽度,仅在 resizable 为 true 时生效。string | numbersemiGlobalDefault("Annotation", "maxWidth")
defaultSize初始宽高,仅在 resizable 为 true 时生效。Type{ width?: string | number | undefined; height?: string | number | undefined; }semiGlobalDefault("Annotation", "defaultSize")
showClose是否显示头部的关闭按钮。booleansemiGlobalDefault("Annotation", "showClose")
closeOnEsc按下 Esc 键时是否触发 cancel。booleansemiGlobalDefault("Annotation", "closeOnEsc")
activeKey当前展开的分组 key,配合 v-model:activeKey 使用。string | string[]semiGlobalDefault("Annotation", "activeKey")
info参考来源分组列表,每组包含 header、key 与 annotations。AnnotationInfo[]semiGlobalDefault("Annotation", "info")

Events

事件说明回调参数
update:visible关闭按钮或 Esc 触发取消时先于 cancel 触发,值为 false,供 v-model:visible 回写。[visible: false]
cancel点击关闭按钮,或在 closeOnEsc 为 true 时按下 Esc 触发。[event: MouseEvent | KeyboardEvent]
afterVisibleChange显示或隐藏动画结束后触发,参数为当前是否可见。[visible: boolean]
update:activeKey展开或收起分组时先于 change 触发,供 v-model:activeKey 回写。[activeKey: string[]]
change展开或收起分组时触发,参数为当前展开的 key。[activeKey: string | string[]]
click点击某条参考来源时触发,参数为点击事件和对应条目;根元素的原生 click 不单独上报。[event: MouseEvent, item: AnnotationItem]

Slots

插槽说明作用域参数
title头部标题,优先于 title 属性。any
header替换整个容器头部;内容为空时回退到内置头部。any
infoHeader分组头部图标之后的内容,作用域参数为 item 与 index;未提供时显示 header 字段。AnnotationHeaderSlotProps
item替换内置的参考来源条目,作用域参数为 item 与 index(在分组内的位置)。AnnotationItemSlotProps

Exposes

名称说明类型
root容器根元素 .semi-sidebar-container;隐藏时为 null。HTMLDivElement | null

AnnotationContent

Props

属性说明类型默认值
activeKey当前展开的分组 key,配合 v-model:activeKey 使用。string | string[]undefined
info参考来源分组列表,每组包含 header、key 与 annotations。AnnotationInfo[][]

Events

事件说明回调参数
update:activeKey展开或收起分组时先于 change 触发,供 v-model:activeKey 回写。[activeKey: string[]]
change展开或收起分组时触发,参数为当前展开的 key。[activeKey: string | string[]]
click点击某条参考来源时触发,参数为点击事件和对应条目;根元素的原生 click 不单独上报。[event: MouseEvent, item: AnnotationItem]

Slots

插槽说明作用域参数
header分组头部图标之后的内容,作用域参数为 item 与 index;未提供时显示 header 字段。AnnotationHeaderSlotProps
item替换内置的参考来源条目,作用域参数为 item 与 index(在分组内的位置)。AnnotationItemSlotProps

Exposes

名称说明类型
无

AnnotationInfo

属性说明类型默认值
annotations该分组下的参考来源条目AnnotationItem[]-
header分组标题的纯文本,也可用 #infoHeader(Annotation)或 #header(AnnotationContent)插槽自定义string-
key分组的唯一标识string-

AnnotationItem

属性说明类型默认值
detail内容详情/补充说明(如视频简介、文本备注等)string-
duration时长(通常为视频时长,单位:秒)number-
img图片地址(如视频封面图、文本配图地址)string-
logo站点/内容所属平台的 logo 图片地址string-
order引用序号(用于内容排序/标注序号展示)number-
siteName内容所属的站点/平台名称string-
title内容标题string-
type内容类型'video' | 'text'-
url资源链接,在新标签页打开;没有 url 的条目渲染为无 href 的链接,只能用指针点击string-

Props

属性说明类型默认值
mode展示模式:main 为主视图,code 与 file 使用内置详情,其他字符串通过 detailContent 插槽自行渲染。stringsemiDefault("Sidebar", "mode", strings.MODE.MAIN)
activeKey主视图中当前选中的选项 key,配合 v-model:activeKey 使用。stringsemiGlobalDefault("Sidebar", "activeKey")
options主视图顶部的选项按钮,每项包含 name 与 key;图标使用 optionIcon 插槽。SideBarOption[]semiGlobalDefault("Sidebar", "options")
detailContentcode 与 file 模式显示的条目,为 CodeItem 或 FileItem 的属性加 key;key 变化时重新挂载该条目。file 模式下其中的 editable 与 imgUploadProps 不生效,由 fileEditable 与 imgUploadProps 决定。SideBarDetailContentsemiGlobalDefault("Sidebar", "detailContent")
fileEditablefile 模式的富文本是否可编辑。booleansemiDefault("Sidebar", "fileEditable", true)
imgUploadPropsfile 模式的图片上传配置,编辑器创建时读取,之后变化不生效。ImageUploadNodeOptionssemiGlobalDefault("Sidebar", "imgUploadProps")
visible是否显示,配合 v-model:visible 使用。booleansemiGlobalDefault("Sidebar", "visible")
title主视图的纯文本标题;传入 title 插槽时以插槽为准。详情视图使用内置的详情头部。stringsemiGlobalDefault("Sidebar", "title")
motion显示与隐藏时是否使用展开动画。booleansemiGlobalDefault("Sidebar", "motion")
resizable宽度是否可拖拽调整;为 true 时 minWidth、maxWidth 与 defaultSize 生效。booleansemiGlobalDefault("Sidebar", "resizable")
minWidth可调整的最小宽度,仅在 resizable 为 true 时生效。string | numbersemiGlobalDefault("Sidebar", "minWidth")
maxWidth可调整的最大宽度,仅在 resizable 为 true 时生效。string | numbersemiGlobalDefault("Sidebar", "maxWidth")
defaultSize初始宽高,仅在 resizable 为 true 时生效。Type{ width?: string | number | undefined; height?: string | number | undefined; }semiGlobalDefault("Sidebar", "defaultSize")
showClose是否显示头部的关闭按钮。booleansemiGlobalDefault("Sidebar", "showClose")
closeOnEsc按下 Esc 键时是否触发 cancel。booleansemiGlobalDefault("Sidebar", "closeOnEsc")

Events

事件说明回调参数
update:activeKey点击选项时先于 activeOptionChange 触发,供 v-model:activeKey 回写。[activeKey: string]
activeOptionChange点击选项时触发,参数为点击事件和该选项的 key。[event: MouseEvent, activeKey: string]
backWard点击详情头部的返回按钮时触发,参数为点击事件和 main。[event: MouseEvent, mode: string]
detailContentCopy复制按钮写入剪贴板后触发,参数为点击事件、复制的内容和是否成功。[event: MouseEvent, content: string, success: boolean]
fileContentChangefile 模式下编辑后触发,参数为 HTML 字符串。[content: string]
update:visible关闭按钮或 Esc 触发取消时先于 cancel 触发,值为 false,供 v-model:visible 回写。[visible: false]
cancel点击关闭按钮,或在 closeOnEsc 为 true 时按下 Esc 触发。[event: MouseEvent | KeyboardEvent]
afterVisibleChange显示或隐藏动画结束后触发,参数为当前是否可见。[visible: boolean]

Slots

插槽说明作用域参数
title主视图标题,优先于 title 属性。any
optionIcon内置选项按钮的图标,作用域参数为 item 与 index。SideBarOptionSlotProps
optionItem替换整个选项按钮,作用域参数为 item、index、active 与 onClick(选中该选项)。SideBarOptionItemSlotProps
mainContent主视图中选项下方的内容,作用域参数为 activeKey。SideBarMainContentSlotProps
detailHeader详情模式的头部,作用域参数为 mode 与 detailContent;内容为空时回退到内置头部。SideBarDetailHeaderSlotProps
detailContent详情模式的内容,作用域参数为 mode;内容为空时回退到内置的代码或富文本详情。SideBarDetailContentSlotProps
customRender转发给内置代码详情中 JsonViewer 的 customRender 插槽,用于渲染 customRenderRule 匹配的内容。JsonViewerCustomRenderSlotProps
searchButton转发给内置代码详情中 JsonViewer 的 searchButton 插槽,替换其搜索按钮。JsonViewerSearchButtonSlotProps

Exposes

名称说明类型
root容器根元素 .semi-sidebar-container;隐藏时为 null。HTMLDivElement | null

SideBarOption

属性说明类型默认值
key选项的唯一标识string-
name选项名称,图标使用 #optionIcon 插槽string-

CodeContent

codes 的每一项为 CodeItem 的属性加用于标识面板的 key。

Props

属性说明类型默认值
codes代码条目列表,每项为 CodeItem 的属性加用于标识面板的 key。CodeItemData[][]
activeKey当前展开的代码面板 key,配合 v-model:activeKey 使用。string | string[]undefined

Events

事件说明回调参数
update:activeKey展开或收起面板时先于 change 触发,供 v-model:activeKey 回写。[activeKey: string[]]
change通过箭头展开或收起面板时触发,参数为当前展开的 key。[activeKey: string | string[]]
expand点击面板头部旁的展开按钮时触发,参数为点击事件、对应条目和 code。仅在绑定了该事件时渲染展开按钮。[event: MouseEvent, item: CodeItemData, mode: string]

Slots

插槽说明作用域参数
customRender转发给每个 JSON 面板中 JsonViewer 的 customRender 插槽。JsonViewerCustomRenderSlotProps
searchButton转发给每个 JSON 面板中 JsonViewer 的 searchButton 插槽,替换其搜索按钮。JsonViewerSearchButtonSlotProps

Exposes

名称说明类型
无

CodeItem

Props

属性说明类型默认值
name代码项名称,由 CodeContent 的面板头部和 Sidebar 的详情头部显示,CodeItem 自身不渲染。stringundefined
language编程语言名称,同 CodeHighlight 的 language,需先通过 CodeHighlight.register 注册,未注册时显示纯文本。stringundefined
content代码或 JSON 字符串。stringundefined
isJson为 true 时用 JsonViewer 展示,否则用 CodeHighlight。booleanfalse
jsonViewerProps传给 JsonViewer 的其他属性,以及追加的 class 与 style。modelValue(content)、width 与 height(100%)、options(只读、自动换行)、showSearch(false)已有默认值,同名属性整体覆盖默认值。Type(Partial<JsonViewerProps> & ElementLook)undefined
codeHighlightProps传给 CodeHighlight 的其他属性,以及追加的 class 与 style。Type(Partial<CodeHighlightProps> & ElementLook)undefined

Events

事件说明回调参数
无

Slots

插槽说明作用域参数
customRenderJsonViewer 的 customRender 插槽,用于渲染 jsonViewerProps.options.customRenderRule 匹配的内容。JsonViewerCustomRenderSlotProps
searchButtonJsonViewer 的 searchButton 插槽,替换其搜索按钮。JsonViewerSearchButtonSlotProps

Exposes

名称说明类型
无

FileContent

files 的每一项为 FileItem 的属性加用于标识面板的 key,以只读方式渲染,extensions 与 imgUploadProps 会传给其预览。

Props

属性说明类型默认值
files文件条目列表,以只读方式渲染,每项的 extensions 与 imgUploadProps 会传给其预览。FileItemData[][]
activeKey当前展开的文件面板 key,配合 v-model:activeKey 使用。string | string[]undefined

Events

事件说明回调参数
update:activeKey展开或收起面板时先于 change 触发,供 v-model:activeKey 回写。[activeKey: string[]]
change通过箭头展开或收起面板时触发,参数为当前展开的 key。[activeKey: string | string[]]
expand点击面板头部旁的展开按钮时触发,参数为点击事件、对应条目和 file。仅在绑定了该事件时渲染展开按钮。[event: MouseEvent, item: FileItemData, mode: string]

Slots

插槽说明作用域参数
无

Exposes

名称说明类型
无

FileItem

Props

属性说明类型默认值
name文件名称,作为编辑区域的可访问名称,挂载后变化会同步到编辑器。stringundefined
content富文本 HTML。挂载后变化会同步到编辑器,与编辑器当前内容相同时不会重置,同步不触发 contentChange。stringundefined
editable是否可编辑,挂载后变化会同步到编辑器。booleantrue
extensions追加到内置扩展之后的 tiptap 扩展,编辑器创建时读取,之后变化不生效。Extensions[]
imgUploadProps图片上传配置,编辑器创建时读取,之后变化不生效。ImageUploadNodeOptionsundefined

Events

事件说明回调参数
contentChange编辑后触发,参数为 HTML 字符串。[content: string]

Slots

插槽说明作用域参数
无

Exposes

名称说明类型
无