Usage Scenarios
The Sidebar is mainly used in AI scenarios for information display and feature configuration, including MCP configuration, reference sources, code preview, rich text preview and editing, etc.
Code Examples
How to import
<script setup lang="ts">
import { Annotation, MCPConfigure, Sidebar } from '@fibrous/semi-ai-vue';
const { Container, CodeContent, CodeItem, FileContent, FileItem } = Sidebar;
const { AnnotationContent } = Annotation;
</script>
Basic Container
The basic container of the Sidebar is the base container for MCP configuration, References and Sidebar.
v-model:visiblecontrols show/hide. Clicking the close button, or pressing Esc whencloseOnEscistrue, updates it tofalsefirst and then emitscanceltitlesets a plain-text title; use the#titleslot for custom contentmotionsets whether to enable the expand animationresizablesets whether the width is resizable. Whentrue, you can useminWidthandmaxWidthto control min and max width
Code
<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 Configuration
Use MCPConfigure to display, enable/disable, configure and search MCP tools.
- Bind
v-model:optionsandv-model:customOptionsto the built-in and custom MCP tools; switching a tool updates the bound value first and then emitsstatusChange - Use
v-model:visibleto control show and hide, andcancelto listen to user close behavior - Use
statusChangeto handle enabling/disabling of MCP tools - Use
addClickto handle actions after clicking the Add button in custom MCP page - Use
configureClickto listen to configuration of built-in MCP tools, andeditClickto listen to configuration of custom MCP tools - Use the
#iconand#descslots for the icon and description of an item, and#itemto replace the whole row; the slot parameters are{ item, index, custom }
For other APIs of MCPConfigure, see MCPConfigure.
The type of MCP tool item is as follows:
interface MCPConfigureOption {
icon?: string; // image URL; use the #icon slot for other content
label?: string;
value: string; // required, identifies the tool and must be unique
desc?: string; // plain text; use the #desc slot for other content
active?: boolean;
disabled?: boolean;
configure?: boolean; // whether to show configure button
}
Usage example:
Code
<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>References
Use the Annotation component to manage the display of reference sources.
- Use
v-model:activeKeyto manage the currently expanded item infosets the reference content listclickis emitted when a reference is clicked, with the event and the item- Use the
#infoHeaderslot for a group header and#itemto replace an item;#headeris the header of the whole container
Code
<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>Code Display
You can use CodeItem in Sidebar to display code. CodeItem is built based on JsonViewer and CodeHighlight.
content: content stringisJson: whether the content is jsonlanguage: programming language name, same aslanguageinCodeHighlight; register it withCodeHighlight.registerfirstjsonViewerProps: configure other JsonViewer propscodeHighlightProps: configure other CodeHighlight props
The value of JsonViewer is called modelValue in jsonViewerProps, and both jsonViewerProps and codeHighlightProps accept class and style. The custom rendering and search button of JsonViewer are available through the #customRender and #searchButton slots of CodeItem.
Code
<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>Code List
You can use CodeContent in Sidebar to display a list of code blocks.
- Use
v-model:activeKeyto manage the expanded panels - Use
expandto listen to the expand button in a panel header #customRenderand#searchButtonare forwarded to the JsonViewer of every JSON panel
Code
<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>Rich Text Editor
You can use FileItem in Sidebar to view and edit rich text content. FileItem is implemented based on tiptap.
content: rich text as HTML. A change after mount is synced to the editor; it is not applied when it equals what the editor already holds, so typing and the cursor are not interrupted. The sync does not emitcontentChangeeditable: whether the content is editable; a change after mount is synced to the editorimgUploadProps: configure image upload endpoint and how to set the src after upload. Useactionto set upload url andgetUploadImageSrc(response)to return the uploaded image url from the upload response (when omitted, a string response is used as the url, otherwiseresponse.src), which will be used as src of img node in rich text; theonlisteners of Upload (such asonSuccess) can be passed here too. The toolbar shows the image button only whenactionorcustomRequestis setextensionsandimgUploadPropsare read only when the editor is created; change thekeyto remount it with new valuescontentChangeis emitted after an edit, with the content as HTML
Code
<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>Rich Text List
You can use FileContent in Sidebar to display a list of rich text documents.
- Use
v-model:activeKeyto manage the expanded panels - Use
expandto listen to the expand button in a panel header
Code
<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
The Sidebar has a main view (mode is main) and detail views (mode is code, file and other custom values).
In the main view you can configure the title through title or the #title slot, decide whether to show close button through showClose, and configure the top button group through options (each item is { name, key }); v-model:activeKey binds the selected item. Use the #optionIcon="{ item, index }" slot for the button icon, or #optionItem to replace the whole button, whose onClick parameter selects the item.
For content rendering in the main view, use the #mainContent="{ activeKey }" slot and render by the selected item. You can use AnnotationContent in Annotation to render references, FileContent in Sidebar to render rich text, and CodeContent to render code.
For detail views, if the content is rich text or code, set mode to code or file and provide detailContent to display the content with built-in code display component / rich text editor; a new key in detailContent remounts it. If you want to customize how the detail view is rendered, use the #detailContent="{ mode }" slot, and customize the detail header through #detailHeader="{ mode, detailContent }"; with empty content, both fall back to the built-in ones. Clicking the back button of the detail header emits backWard.
Code
<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 Reference
The class, style and other undeclared attributes (such as aria-label) of Sidebar, Annotation, MCPConfigure and Container land on the .semi-sidebar-container element; when the root is named (aria-label or aria-labelledby) and no role is given, its role is group. Undeclared attributes of CodeContent, CodeItem, FileContent, FileItem and AnnotationContent land on their own root elements.
The template ref of Sidebar, Annotation, MCPConfigure and Sidebar.Container is typed SidebarContainerHandle (exported from @fibrous/semi-ai-vue); its root member is HTMLDivElement | null, and null while the container is hidden.
Container
Props
| Property | Description | Type | Default |
|---|---|---|---|
| visible | Whether the container is shown; bind it with v-model:visible. | boolean | false |
| title | Plain-text title; the title slot takes precedence. | string | undefined |
| motion | Whether showing and hiding use the expand animation. | boolean | true |
| resizable | Whether the width can be resized by dragging; minWidth, maxWidth and defaultSize apply only when true. | boolean | true |
| minWidth | Minimum width when resizing; applies only when resizable is true. | string | number | 150 |
| maxWidth | Maximum width when resizing; applies only when resizable is true. | string | number | undefined |
| defaultSize | Initial width and height; applies only when resizable is true. | Type{ width?: string | number | undefined; height?: string | number | undefined; } | undefined |
| showClose | Whether the header shows the close button. | boolean | true |
| closeOnEsc | Whether pressing Esc emits cancel. | boolean | false |
Events
| Event | Description | Callback parameters |
|---|---|---|
| update:visible | Emitted before cancel when the close button or Esc cancels, with false, so v-model:visible closes the container. | [visible: false] |
| cancel | Emitted when the close button is clicked, or when Esc is pressed while closeOnEsc is true. | [event: MouseEvent | KeyboardEvent] |
| afterVisibleChange | Emitted after the show or hide animation ends, with whether the container is visible. | [visible: boolean] |
Slots
| Slot | Description | Scope parameters |
|---|---|---|
| default | The content area of the container. | any |
| title | Header title; it takes precedence over the title prop. | any |
| header | Replaces the whole header; empty content falls back to the built-in header. | any |
Exposes
| Name | Description | Type |
|---|---|---|
| root | The .semi-sidebar-container root element; null while hidden. | HTMLDivElement | null |
MCPConfigure
Props
| Property | Description | Type | Default |
|---|---|---|---|
| visible | Whether it is shown; bind it with v-model:visible. | boolean | semiGlobalDefault("MCPConfigure", "visible") |
| title | Plain-text title, the locale's MCP configure text by default; the title slot takes precedence. | string | semiGlobalDefault("MCPConfigure", "title") |
| motion | Whether showing and hiding use the expand animation. | boolean | semiGlobalDefault("MCPConfigure", "motion") |
| resizable | Whether the width can be resized by dragging; minWidth, maxWidth and defaultSize apply only when true. | boolean | semiGlobalDefault("MCPConfigure", "resizable") |
| minWidth | Minimum width when resizing; applies only when resizable is true. | string | number | semiGlobalDefault("MCPConfigure", "minWidth") |
| maxWidth | Maximum width when resizing; applies only when resizable is true. | string | number | semiGlobalDefault("MCPConfigure", "maxWidth") |
| defaultSize | Initial width and height; applies only when resizable is true. | Type{ width?: string | number | undefined; height?: string | number | undefined; } | semiGlobalDefault("MCPConfigure", "defaultSize") |
| showClose | Whether the header shows the close button. | boolean | semiGlobalDefault("MCPConfigure", "showClose") |
| closeOnEsc | Whether pressing Esc emits cancel. | boolean | semiGlobalDefault("MCPConfigure", "closeOnEsc") |
| options | Built-in MCP tools; bind it with v-model:options. Each item needs a unique value. | MCPConfigureOption[] | semiGlobalDefault("MCPConfigure", "options") |
| customOptions | Custom MCP tools; bind it with v-model:customOptions. | MCPConfigureOption[] | semiGlobalDefault("MCPConfigure", "customOptions") |
| filter | Custom search filter, called with the lower-cased input and an option; the label and desc are matched by default. | Type((inputValue: string, option: MCPConfigureOption) => boolean) | undefined |
| placeholder | Placeholder of the search input, the locale text by default. | string | semiGlobalDefault("MCPConfigure", "placeholder") |
Events
| Event | Description | Callback parameters |
|---|---|---|
| update:visible | Emitted before cancel when the close button or Esc cancels, with false, so v-model:visible closes it. | [visible: false] |
| cancel | Emitted when the close button is clicked, or when Esc is pressed while closeOnEsc is true. | [event: MouseEvent | KeyboardEvent] |
| afterVisibleChange | Emitted after the show or hide animation ends, with whether it is visible. | [visible: boolean] |
| update:options | Emitted before statusChange when a built-in tool is switched, so v-model:options follows. | [options: MCPConfigureOption[]] |
| update:customOptions | Emitted before statusChange when a custom tool is switched, so v-model:customOptions follows. | [options: MCPConfigureOption[]] |
| statusChange | Emitted after a tool is switched, with the list whose active flag changed and whether it is the custom list. | [options: MCPConfigureOption[], custom: boolean] |
| search | Emitted when the search input changes, with the input value and whether the custom list is shown. | [inputValue: string, custom: boolean] |
| addClick | Emitted when the add button of the custom page is clicked. | [event: MouseEvent] |
| configureClick | Emitted when the configure button is clicked, with the event and its option. | [event: MouseEvent, option: MCPConfigureOption] |
| editClick | Emitted when the edit button of a custom tool is clicked, with the event and its option. | [event: MouseEvent, option: MCPConfigureOption] |
Slots
| Slot | Description | Scope parameters |
|---|---|---|
| title | Header title; it takes precedence over the title prop. | any |
| header | Replaces the whole header; empty content falls back to the built-in header. | any |
| icon | Icon of an option, with item, index and custom. When provided it is used for every option; the icon field is an image URL only when it is absent. | MCPConfigureItemSlotProps |
| desc | Description of an option, with item, index and custom; the desc field is shown when absent. | MCPConfigureItemSlotProps |
| item | Replaces the whole built-in row, with item, index and custom. | MCPConfigureItemSlotProps |
Exposes
| Name | Description | Type |
|---|---|---|
| root | The .semi-sidebar-container root element; null while hidden. | HTMLDivElement | null |
MCPConfigureOption
| Property | Description | Type | Default |
|---|---|---|---|
| active | Whether this MCP is active | boolean | false |
| configure | Whether to show the configure button | boolean | false |
| desc | Description text, matched by the built-in filter; use the #desc slot for other content | string | - |
| disabled | Whether this MCP is disabled. When true, users cannot toggle its active state | boolean | false |
| icon | Image URL of the icon; use the #icon slot for other content | string | - |
| label | Label text | string | - |
| value | Value, required. Identifies the option in statusChange and is used as the item key, so it must be unique in a list | string | - |
Annotation
Props
| Property | Description | Type | Default |
|---|---|---|---|
| visible | Whether it is shown; bind it with v-model:visible. | boolean | semiGlobalDefault("Annotation", "visible") |
| title | Plain-text title, the locale's references text by default; the title slot takes precedence. | string | semiGlobalDefault("Annotation", "title") |
| motion | Whether showing and hiding use the expand animation. | boolean | semiGlobalDefault("Annotation", "motion") |
| resizable | Whether the width can be resized by dragging; minWidth, maxWidth and defaultSize apply only when true. | boolean | semiGlobalDefault("Annotation", "resizable") |
| minWidth | Minimum width when resizing; applies only when resizable is true. | string | number | semiGlobalDefault("Annotation", "minWidth") |
| maxWidth | Maximum width when resizing; applies only when resizable is true. | string | number | semiGlobalDefault("Annotation", "maxWidth") |
| defaultSize | Initial width and height; applies only when resizable is true. | Type{ width?: string | number | undefined; height?: string | number | undefined; } | semiGlobalDefault("Annotation", "defaultSize") |
| showClose | Whether the header shows the close button. | boolean | semiGlobalDefault("Annotation", "showClose") |
| closeOnEsc | Whether pressing Esc emits cancel. | boolean | semiGlobalDefault("Annotation", "closeOnEsc") |
| activeKey | Keys of the expanded groups; bind it with v-model:activeKey. | string | string[] | semiGlobalDefault("Annotation", "activeKey") |
| info | Groups of references; each has a header, a key and its annotations. | AnnotationInfo[] | semiGlobalDefault("Annotation", "info") |
Events
| Event | Description | Callback parameters |
|---|---|---|
| update:visible | Emitted before cancel when the close button or Esc cancels, with false, so v-model:visible closes it. | [visible: false] |
| cancel | Emitted when the close button is clicked, or when Esc is pressed while closeOnEsc is true. | [event: MouseEvent | KeyboardEvent] |
| afterVisibleChange | Emitted after the show or hide animation ends, with whether it is visible. | [visible: boolean] |
| update:activeKey | Emitted before change when a group opens or closes, so v-model:activeKey follows. | [activeKey: string[]] |
| change | Emitted when a group opens or closes, with the expanded keys. | [activeKey: string | string[]] |
| click | Emitted when a reference is clicked, with the event and its item; the native click of the root is not reported apart from it. | [event: MouseEvent, item: AnnotationItem] |
Slots
| Slot | Description | Scope parameters |
|---|---|---|
| title | Header title; it takes precedence over the title prop. | any |
| header | Replaces the whole container header; empty content falls back to the built-in header. | any |
| infoHeader | Content of a group header after its icon, with item and index; the header field is shown when absent. | AnnotationHeaderSlotProps |
| item | Replaces the built-in reference item, with item and index (its position in the group). | AnnotationItemSlotProps |
Exposes
| Name | Description | Type |
|---|---|---|
| root | The .semi-sidebar-container root element; null while hidden. | HTMLDivElement | null |
AnnotationContent
Props
| Property | Description | Type | Default |
|---|---|---|---|
| activeKey | Keys of the expanded groups; bind it with v-model:activeKey. | string | string[] | undefined |
| info | Groups of references; each has a header, a key and its annotations. | AnnotationInfo[] | [] |
Events
| Event | Description | Callback parameters |
|---|---|---|
| update:activeKey | Emitted before change when a group opens or closes, so v-model:activeKey follows. | [activeKey: string[]] |
| change | Emitted when a group opens or closes, with the expanded keys. | [activeKey: string | string[]] |
| click | Emitted when a reference is clicked, with the event and its item; the native click of the root is not reported apart from it. | [event: MouseEvent, item: AnnotationItem] |
Slots
| Slot | Description | Scope parameters |
|---|---|---|
| header | Content of a group header after its icon, with item and index; the header field is shown when absent. | AnnotationHeaderSlotProps |
| item | Replaces the built-in reference item, with item and index (its position in the group). | AnnotationItemSlotProps |
Exposes
| Name | Description | Type |
|---|---|---|
| None |
AnnotationInfo
| Property | Description | Type | Default |
|---|---|---|---|
| annotations | Reference items of the group | AnnotationItem[] | - |
| header | Plain text of the group header; customize it with the #infoHeader slot (Annotation) or the #header slot (AnnotationContent) | string | - |
| key | Unique key of the group | string | - |
AnnotationItem
| Property | Description | Type | Default |
|---|---|---|---|
| detail | Extra detail text such as video description or text note | string | - |
| duration | Duration, usually used for videos, in seconds | number | - |
| img | Image url, such as video cover or illustration | string | - |
| logo | Logo url of the site/platform to which the content belongs | string | - |
| order | Order/index number | number | - |
| siteName | Name of the site/platform where the content belongs | string | - |
| title | Title | string | - |
| type | Content type | 'video' | 'text' | - |
| url | Resource url, opened in a new tab. An item without it renders a link without href that only the pointer can activate | string | - |
Sidebar
Props
| Property | Description | Type | Default |
|---|---|---|---|
| mode | Display mode: main is the main view, code and file use the built-in details, and any other string is rendered by the detailContent slot. | string | semiDefault("Sidebar", "mode", strings.MODE.MAIN) |
| activeKey | Key of the selected option in the main view; bind it with v-model:activeKey. | string | semiGlobalDefault("Sidebar", "activeKey") |
| options | Option buttons at the top of the main view, each with a name and a key; icons use the optionIcon slot. | SideBarOption[] | semiGlobalDefault("Sidebar", "options") |
| detailContent | The item shown in code and file modes: the CodeItem or FileItem props plus a key; a new key remounts it. In file mode its editable and imgUploadProps have no effect, as fileEditable and imgUploadProps decide them. | SideBarDetailContent | semiGlobalDefault("Sidebar", "detailContent") |
| fileEditable | Whether the rich text in file mode is editable. | boolean | semiDefault("Sidebar", "fileEditable", true) |
| imgUploadProps | Image upload options of file mode, read when the editor is created; later changes have no effect. | ImageUploadNodeOptions | semiGlobalDefault("Sidebar", "imgUploadProps") |
| visible | Whether it is shown; bind it with v-model:visible. | boolean | semiGlobalDefault("Sidebar", "visible") |
| title | Plain-text title of the main view; the title slot takes precedence. Detail views use the detail header. | string | semiGlobalDefault("Sidebar", "title") |
| motion | Whether showing and hiding use the expand animation. | boolean | semiGlobalDefault("Sidebar", "motion") |
| resizable | Whether the width can be resized by dragging; minWidth, maxWidth and defaultSize apply only when true. | boolean | semiGlobalDefault("Sidebar", "resizable") |
| minWidth | Minimum width when resizing; applies only when resizable is true. | string | number | semiGlobalDefault("Sidebar", "minWidth") |
| maxWidth | Maximum width when resizing; applies only when resizable is true. | string | number | semiGlobalDefault("Sidebar", "maxWidth") |
| defaultSize | Initial width and height; applies only when resizable is true. | Type{ width?: string | number | undefined; height?: string | number | undefined; } | semiGlobalDefault("Sidebar", "defaultSize") |
| showClose | Whether the header shows the close button. | boolean | semiGlobalDefault("Sidebar", "showClose") |
| closeOnEsc | Whether pressing Esc emits cancel. | boolean | semiGlobalDefault("Sidebar", "closeOnEsc") |
Events
| Event | Description | Callback parameters |
|---|---|---|
| update:activeKey | Emitted before activeOptionChange when an option is clicked, so v-model:activeKey follows. | [activeKey: string] |
| activeOptionChange | Emitted when an option is clicked, with the event and the option's key. | [event: MouseEvent, activeKey: string] |
| backWard | Emitted when the back button of the detail header is clicked, with the event and main. | [event: MouseEvent, mode: string] |
| detailContentCopy | Emitted after the copy button wrote to the clipboard, with the event, the content and whether it succeeded. | [event: MouseEvent, content: string, success: boolean] |
| fileContentChange | Emitted after an edit in file mode, with the content as HTML. | [content: string] |
| update:visible | Emitted before cancel when the close button or Esc cancels, with false, so v-model:visible closes it. | [visible: false] |
| cancel | Emitted when the close button is clicked, or when Esc is pressed while closeOnEsc is true. | [event: MouseEvent | KeyboardEvent] |
| afterVisibleChange | Emitted after the show or hide animation ends, with whether it is visible. | [visible: boolean] |
Slots
| Slot | Description | Scope parameters |
|---|---|---|
| title | Title of the main view; it takes precedence over the title prop. | any |
| optionIcon | Icon of the built-in option button, with item and index. | SideBarOptionSlotProps |
| optionItem | Replaces the whole option button, with item, index, active and onClick (which selects the option). | SideBarOptionItemSlotProps |
| mainContent | Content below the options in the main view, with activeKey. | SideBarMainContentSlotProps |
| detailHeader | Header in detail modes, with mode and detailContent; empty content falls back to the built-in header. | SideBarDetailHeaderSlotProps |
| detailContent | Content in detail modes, with mode; empty content falls back to the built-in code or file detail. | SideBarDetailContentSlotProps |
| customRender | Forwarded to the customRender slot of the JsonViewer in the built-in code detail, for the content matched by customRenderRule. | JsonViewerCustomRenderSlotProps |
| searchButton | Forwarded to the searchButton slot of the JsonViewer in the built-in code detail, replacing its search button. | JsonViewerSearchButtonSlotProps |
Exposes
| Name | Description | Type |
|---|---|---|
| root | The .semi-sidebar-container root element; null while hidden. | HTMLDivElement | null |
SideBarOption
| Property | Description | Type | Default |
|---|---|---|---|
| key | Unique key of the option | string | - |
| name | Option name; use the #optionIcon slot for the icon | string | - |
CodeContent
Each item of codes is the props of CodeItem plus a key that identifies its panel.
Props
| Property | Description | Type | Default |
|---|---|---|---|
| codes | The code entries, each with the CodeItem props and a key identifying its panel. | CodeItemData[] | [] |
| activeKey | Keys of the expanded code panels; bind it with v-model:activeKey. | string | string[] | undefined |
Events
| Event | Description | Callback parameters |
|---|---|---|
| update:activeKey | Emitted before change when a panel opens or closes, so v-model:activeKey follows. | [activeKey: string[]] |
| change | Emitted when a panel opens or closes through its arrow, with the expanded keys. | [activeKey: string | string[]] |
| expand | Emitted when the expand button beside a panel header is clicked, with the event, its entry and code. The button is only rendered when this event is bound. | [event: MouseEvent, item: CodeItemData, mode: string] |
Slots
| Slot | Description | Scope parameters |
|---|---|---|
| customRender | Forwarded to the customRender slot of the JsonViewer in every JSON panel. | JsonViewerCustomRenderSlotProps |
| searchButton | Forwarded to the searchButton slot of the JsonViewer in every JSON panel, replacing its search button. | JsonViewerSearchButtonSlotProps |
Exposes
| Name | Description | Type |
|---|---|---|
| None |
CodeItem
Props
| Property | Description | Type | Default |
|---|---|---|---|
| name | Name of the code item, shown by the CodeContent panel header and the Sidebar detail header; CodeItem itself does not render it. | string | undefined |
| language | Language name as in the CodeHighlight language prop; register it with CodeHighlight.register first, otherwise plain text is shown. | string | undefined |
| content | The code or JSON string. | string | undefined |
| isJson | When true the content is shown by JsonViewer, otherwise by CodeHighlight. | boolean | false |
| jsonViewerProps | Other props for JsonViewer, plus an extra class and style. modelValue (the content), width and height (100%), options (read-only, auto wrap) and showSearch (false) have defaults; a prop given here replaces its default as a whole. | Type(Partial<JsonViewerProps> & ElementLook) | undefined |
| codeHighlightProps | Other props for CodeHighlight, plus an extra class and style. | Type(Partial<CodeHighlightProps> & ElementLook) | undefined |
Events
| Event | Description | Callback parameters |
|---|---|---|
| None |
Slots
| Slot | Description | Scope parameters |
|---|---|---|
| customRender | The customRender slot of JsonViewer, for the content matched by jsonViewerProps.options.customRenderRule. | JsonViewerCustomRenderSlotProps |
| searchButton | The searchButton slot of JsonViewer, replacing its search button. | JsonViewerSearchButtonSlotProps |
Exposes
| Name | Description | Type |
|---|---|---|
| None |
FileContent
Each item of files is the props of FileItem plus a key that identifies its panel. It is rendered read-only: each entry's extensions and imgUploadProps reach its preview.
Props
| Property | Description | Type | Default |
|---|---|---|---|
| files | The file entries, rendered read-only: each entry's extensions and imgUploadProps reach its preview. | FileItemData[] | [] |
| activeKey | Keys of the expanded file panels; bind it with v-model:activeKey. | string | string[] | undefined |
Events
| Event | Description | Callback parameters |
|---|---|---|
| update:activeKey | Emitted before change when a panel opens or closes, so v-model:activeKey follows. | [activeKey: string[]] |
| change | Emitted when a panel opens or closes through its arrow, with the expanded keys. | [activeKey: string | string[]] |
| expand | Emitted when the expand button beside a panel header is clicked, with the event, its entry and file. The button is only rendered when this event is bound. | [event: MouseEvent, item: FileItemData, mode: string] |
Slots
| Slot | Description | Scope parameters |
|---|---|---|
| None |
Exposes
| Name | Description | Type |
|---|---|---|
| None |
FileItem
Props
| Property | Description | Type | Default |
|---|---|---|---|
| name | File name, used as the accessible name of the editing area; later changes are synced to the editor. | string | undefined |
| content | Rich text as HTML. Later changes are synced to the editor; content equal to the editor's is not reset, and syncing does not emit contentChange. | string | undefined |
| editable | Whether it is editable; later changes are synced to the editor. | boolean | true |
| extensions | tiptap extensions appended to the built-in ones, read when the editor is created; later changes have no effect. | Extensions | [] |
| imgUploadProps | Image upload options, read when the editor is created; later changes have no effect. | ImageUploadNodeOptions | undefined |
Events
| Event | Description | Callback parameters |
|---|---|---|
| contentChange | Emitted after an edit, with the content as HTML. | [content: string] |
Slots
| Slot | Description | Scope parameters |
|---|---|---|
| None |
Exposes
| Name | Description | Type |
|---|---|---|
| None |
