-
- Section {{ section }}
- 普通内容区也可以把滚动容器交给 Layout.ProxyScrollbar。
-
+
+
+
+ Section {{ section }}
+ 普通内容区也可以把滚动容器交给 Layout.ProxyScrollbar。
+
+
@@ -28,16 +29,17 @@ const sections = Array.from({ length: 12 }, (_, index) => index + 1)
diff --git a/docs/demos/layout/aside-toggle.vue b/docs/demos/layout/aside-toggle.vue
new file mode 100644
index 000000000..84fe58e45
--- /dev/null
+++ b/docs/demos/layout/aside-toggle.vue
@@ -0,0 +1,104 @@
+
+
+
+
+
+
+
+
+
+
+ {{ isOpen ? '收起' : '展开' }}
+
+
+
+
+
+
+
+ 按钮文案和形态直接使用 `isOpen` 插槽状态切换。
+
+
+
+
+
+
diff --git a/docs/demos/layout/mode.vue b/docs/demos/layout/mode.vue
new file mode 100644
index 000000000..e2e3a7700
--- /dev/null
+++ b/docs/demos/layout/mode.vue
@@ -0,0 +1,73 @@
+
+
+
+
+
+ normal
+ floating
+
+
+
+
+
+
+
+
+
+
+ {{ mode === 'normal' ? '参与页面布局' : '挂载到 body 并悬浮显示' }}
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/src/components/layout.md b/docs/src/components/layout.md
index 4ff96ce6d..6f4addfaf 100644
--- a/docs/src/components/layout.md
+++ b/docs/src/components/layout.md
@@ -28,6 +28,8 @@ outline: [1, 3]
普通页面不需要显式传 `mode`。需要临时面板、悬浮工作台或可拖拽窗口时,再使用 `mode="floating"`。
+
+
## 侧栏
侧栏由 `leftAside` / `rightAside` 控制,类型为 [`LayoutAsideProps`](#layout-aside-props)。
@@ -36,6 +38,8 @@ outline: [1, 3]
### 展示形态
+`LayoutAsideProps.mode` 控制侧栏展示形态。
+
- `dock`:占据页面空间
- `drawer`:覆盖在内容上方
@@ -64,15 +68,15 @@ outline: [1, 3]
-### 侧栏受控状态
+### 侧栏受控
`open` 和 `expandedWidth` 是受控值,状态变化后需要通过事件同步外部状态。
`defaultOpen` 和 `defaultExpandedWidth` 只提供初始值,适合不需要外部持续控制的场景。
@@ -145,12 +149,14 @@ outline: [1, 3]
description="内容区居中后,滚动条仍固定在主区右侧。"
/>
-## Layout.AsideToggle
+## 侧栏内控制
`Layout.AsideToggle` 是内置侧栏开关按钮,只能在 `Layout` 内部使用,通常放在 `left-aside` / `right-aside` 插槽中。
它适合让侧栏内容自己控制展开和收起,默认插槽提供 `{ isOpen }`。自定义按钮内容时,应保留可读文本或补充 `aria-label`。
+
+
## Props
### Layout {#layout-props}
From 19b48e1fc70ffc365f818c0a2f06b3171951ab4d Mon Sep 17 00:00:00 2001
From: SonyLeo <746591437@qq.com>
Date: Wed, 8 Jul 2026 00:51:57 -0700
Subject: [PATCH 06/12] feat(docs): enhance layout mode demo and update
documentation for clarity
---
docs/demos/layout/mode.vue | 28 +++++++++++++++++++++-------
docs/src/components/layout.md | 12 ++++++------
2 files changed, 27 insertions(+), 13 deletions(-)
diff --git a/docs/demos/layout/mode.vue b/docs/demos/layout/mode.vue
index e2e3a7700..2b2f786c9 100644
--- a/docs/demos/layout/mode.vue
+++ b/docs/demos/layout/mode.vue
@@ -1,10 +1,29 @@
@@ -15,12 +34,7 @@ const mode = ref('normal')
-
+
diff --git a/docs/src/components/layout.md b/docs/src/components/layout.md
index 6f4addfaf..cec4e7c2d 100644
--- a/docs/src/components/layout.md
+++ b/docs/src/components/layout.md
@@ -119,9 +119,9 @@ outline: [1, 3]
description="在浮层里组合左右 drawer,适合临时工作区、对话面板或侧边操作台。"
/>
-## 主区滚动
+## 代理滚动条
-`Layout.ProxyScrollbar` 用来代理主区滚动条,适合消息流、长内容阅读流和工作台主区。
+`Layout.ProxyScrollbar` 是代理滚动条,适合消息流、长内容阅读流和工作台主区。
常见于内容列居中或限宽后,原生滚动条偏离主区右边界的场景。
@@ -145,17 +145,17 @@ outline: [1, 3]
'../../demos/layout/main-scroll-bubble.vue',
'../../demos/layout/main-scroll-div.vue'
]"
- title="主区滚动"
+ title="代理滚动条"
description="内容区居中后,滚动条仍固定在主区右侧。"
/>
-## 侧栏内控制
+## 侧栏开关
-`Layout.AsideToggle` 是内置侧栏开关按钮,只能在 `Layout` 内部使用,通常放在 `left-aside` / `right-aside` 插槽中。
+`Layout.AsideToggle` 是内置侧栏开关按钮,可以在 `Layout` 内部任意区域使用。
它适合让侧栏内容自己控制展开和收起,默认插槽提供 `{ isOpen }`。自定义按钮内容时,应保留可读文本或补充 `aria-label`。
-
+
## Props
From 9133b1816e4771dba620ab01fc451a9d2e140ddc Mon Sep 17 00:00:00 2001
From: SonyLeo <746591437@qq.com>
Date: Wed, 8 Jul 2026 04:11:45 -0700
Subject: [PATCH 07/12] feat(docs): update layout documentation and types to
use LayoutAsideOptions
---
docs/demos/layout/aside-collapse-effect.vue | 4 +-
docs/demos/layout/aside-controlled.vue | 6 +-
docs/demos/layout/aside-resizable.vue | 4 +-
docs/demos/layout/floating-controlled.vue | 86 +++++++++++++++-
docs/demos/layout/floating-panels.vue | 34 +++----
docs/demos/layout/floating.vue | 98 +++----------------
docs/src/components/layout.md | 66 ++++++-------
.../composables/useLayoutAsideStates.ts | 8 +-
packages/components/src/layout/index.type.ts | 6 +-
9 files changed, 155 insertions(+), 157 deletions(-)
diff --git a/docs/demos/layout/aside-collapse-effect.vue b/docs/demos/layout/aside-collapse-effect.vue
index 14ff3f606..42ae11658 100644
--- a/docs/demos/layout/aside-collapse-effect.vue
+++ b/docs/demos/layout/aside-collapse-effect.vue
@@ -2,13 +2,13 @@
import { computed, ref } from 'vue'
import { TrLayout } from '@opentiny/tiny-robot'
import { TinyRadio, TinyRadioGroup, TinySlider, TinySwitch } from '@opentiny/vue'
-import type { LayoutAsideCollapseEffect, LayoutAsideProps } from '@opentiny/tiny-robot'
+import type { LayoutAsideCollapseEffect, LayoutAsideOptions } from '@opentiny/tiny-robot'
const collapseEffect = ref('overlay')
const collapsedWidth = ref(72)
const open = ref(true)
-const leftAside = computed(() => ({
+const leftAside = computed(() => ({
open: open.value,
expandedWidth: 176,
collapsedWidth: collapsedWidth.value,
diff --git a/docs/demos/layout/aside-controlled.vue b/docs/demos/layout/aside-controlled.vue
index f506f2e80..22f5babbc 100644
--- a/docs/demos/layout/aside-controlled.vue
+++ b/docs/demos/layout/aside-controlled.vue
@@ -2,7 +2,7 @@
import { computed, ref } from 'vue'
import { TrLayout } from '@opentiny/tiny-robot'
import { TinyButton, TinySlider } from '@opentiny/vue'
-import type { LayoutAsideProps, LayoutAsideOpenValue, LayoutAsideResizeValue } from '@opentiny/tiny-robot'
+import type { LayoutAsideOptions, LayoutAsideOpenValue, LayoutAsideResizeValue } from '@opentiny/tiny-robot'
const leftOpen = ref(true)
const leftExpandedWidth = ref(220)
@@ -10,7 +10,7 @@ const leftWidthMin = 160
const leftWidthMax = 320
const rightOpen = ref(false)
-const leftAside = computed(() => ({
+const leftAside = computed(() => ({
open: leftOpen.value,
expandedWidth: leftExpandedWidth.value,
collapsedWidth: 0,
@@ -19,7 +19,7 @@ const leftAside = computed(() => ({
resizable: true,
}))
-const rightAside = computed(() => ({
+const rightAside = computed(() => ({
mode: 'drawer',
open: rightOpen.value,
}))
diff --git a/docs/demos/layout/aside-resizable.vue b/docs/demos/layout/aside-resizable.vue
index 06c8c38d9..cadcca616 100644
--- a/docs/demos/layout/aside-resizable.vue
+++ b/docs/demos/layout/aside-resizable.vue
@@ -1,13 +1,13 @@
@@ -39,41 +29,10 @@ const floatingOptions = computed(() => ({
{{ open ? '关闭浮层' : '打开浮层' }}
- 非受控浮层会在内部维护拖拽和缩放后的状态。
-
-
-
-
-
-
-
-
-
-
-
-
(() => ({
>
-
`defaultFloatingState` 只设置初始位置和大小。
-
拖动顶部横条可移动浮层,拖动边缘手柄可调整大小。
-
切换 placement 或 offset 后,浮层会按新的初始状态重新定位。
+
当前示例只设置初始位置和尺寸。
+
拖拽或缩放后,位置和尺寸由组件内部维护。
@@ -116,32 +74,6 @@ const floatingOptions = computed(() => ({
gap: 8px;
}
-.layout-floating-demo__controls {
- display: flex;
- align-items: center;
- flex-wrap: wrap;
- gap: 8px;
-}
-
-.layout-floating-demo__tip {
- color: var(--vp-c-text-2, var(--tr-text-secondary, #4e5969));
-}
-
-.layout-floating-demo__field {
- display: inline-flex;
- align-items: center;
- gap: 6px;
- color: var(--vp-c-text-2, var(--tr-text-secondary, #4e5969));
-}
-
-.layout-floating-demo__select {
- width: 148px;
-}
-
-.layout-floating-demo__numeric {
- width: 104px;
-}
-
.layout-floating-demo__main {
display: grid;
gap: 12px;
diff --git a/docs/src/components/layout.md b/docs/src/components/layout.md
index cec4e7c2d..e89c6e02b 100644
--- a/docs/src/components/layout.md
+++ b/docs/src/components/layout.md
@@ -4,41 +4,39 @@ outline: [1, 3]
# Layout 布局
-`Layout` 用来组织带有头部、主内容区、底部和左右侧栏的页面。
+`Layout` 是面向 AI 应用页面的通用布局组件,适合搭建聊天页、工作台和多面板操作界面。
-它主要解决这些布局问题:
+它提供以下能力:
-- 页面结构分散,头部、主区、底部和左右侧栏需要反复拼装
-- 侧栏展开、收起、拖拽改宽和抽屉覆盖逻辑容易重复实现
-- 临时面板需要脱离文档流,并支持定位、拖拽和缩放
-- 主区内容很长时,原生滚动条位置不稳定,容易影响阅读和操作
+- 页面骨架:统一组织头部、主区、底部与左右侧栏
+- 侧栏交互:支持展开、收起、拖拽改宽和 `drawer` 覆盖
+- 浮层布局:支持定位、拖拽和缩放
+- 主区滚动代理:适用于内容列居中或限宽后,原生滚动条偏离主区右边界的场景
## 基础布局
-`Layout` 用于定义页面结构,各区域的具体内容通过插槽提供。
+`Layout` 提供 `left-aside`、`header`、`main`、`footer` 和 `right-aside` 五个区域插槽,用于编排页面结构。
## 布局模式
-`mode` 控制 `Layout` 的整体形态。
+`mode` 控制 `Layout` 的整体形态,默认值为 `normal`。
-- `normal`:普通页面骨架,参与原始页面布局
-- `floating`:悬浮工作区,脱离原始页面布局并挂载到 `body`
-
-普通页面不需要显式传 `mode`。需要临时面板、悬浮工作台或可拖拽窗口时,再使用 `mode="floating"`。
+- `normal`:普通页面骨架,参与文档流布局
+- `floating`:悬浮布局,脱离文档流,支持用作悬浮工作区或可拖拽窗口
## 侧栏
-侧栏由 `leftAside` / `rightAside` 控制,类型为 [`LayoutAsideProps`](#layout-aside-props)。
+侧栏由 `leftAside` / `rightAside` 控制,类型为 [`LayoutAsideOptions`](#layout-aside-options)。
侧栏内容通过 `left-aside` / `right-aside` 插槽提供。配置和内容分开后,可以只调整行为配置,而不影响插槽里的渲染结构。
### 展示形态
-`LayoutAsideProps.mode` 控制侧栏展示形态。
+`LayoutAsideOptions.mode` 控制侧栏展示形态,默认值为 `dock`。
- `dock`:占据页面空间
- `drawer`:覆盖在内容上方
@@ -82,41 +80,44 @@ outline: [1, 3]
## 浮层
-浮层只在 `mode="floating"` 时生效,适合临时面板、悬浮工作区或对话面板。
-
-`defaultFloatingState` 和 `floatingState` 不要同时传入:
+浮层相关配置和交互只在浮层模式下生效。
- `defaultFloatingState`:非受控初始状态,只在首次挂载时读取
- `floatingState`:受控状态,由外部维护当前位置和尺寸
+- `floatingOptions`:浮层行为配置,用于拖拽、缩放和尺寸约束,不参与状态控制
+
+> `defaultFloatingState` 和 `floatingState` 不要同时传入
### 非受控浮层
-非受控浮层通过 `defaultFloatingState` 设置初始位置和尺寸。拖动或缩放后,状态由组件内部维护。
+非受控浮层通过 `defaultFloatingState` 设置初始位置和尺寸。
### 受控浮层
-受控浮层以 `floatingState` 作为唯一状态源,组件按传入状态渲染;内部交互产生变化时,通过 `update:floatingState` 通知外部同步。
+受控浮层以 `floatingState` 作为唯一状态源,组件始终按外部状态渲染;
+
+后续通过 `update:floatingState` 通知外部同步。
-### 浮层工作区
+### 浮层模式下的侧栏
-浮层里同样可以放入侧栏、头部和主区。常见用法是把左右两侧都做成按需展开的 drawer。
+浮层里同样可以放入侧栏、头部和主区。
## 代理滚动条
@@ -125,9 +126,8 @@ outline: [1, 3]
常见于内容列居中或限宽后,原生滚动条偏离主区右边界的场景。
-- 外层作为真实滚动宿主,负责尺寸、`box-sizing` 和滚动样式
-- 内层负责内容居中、限宽和留白
-- `scrollTarget` 传真实滚动元素,`Layout.ProxyScrollbar` 会隐藏其原生滚动条
+- 将实际承担滚动的元素传给 `scrollTarget`。
+- 为使代理滚动条正确生效,该滚动元素需要具备以下基础样式。
```css
.scroll-host {
@@ -153,7 +153,7 @@ outline: [1, 3]
`Layout.AsideToggle` 是内置侧栏开关按钮,可以在 `Layout` 内部任意区域使用。
-它适合让侧栏内容自己控制展开和收起,默认插槽提供 `{ isOpen }`。自定义按钮内容时,应保留可读文本或补充 `aria-label`。
+它给侧栏内容提供控制展开和收起的能力,默认插槽提供 `{ isOpen }`。
@@ -164,11 +164,11 @@ outline: [1, 3]
| 属性名 | 说明 | 类型 | 默认值 |
| ------ | ---- | ---- | ------ |
| `mode` | 布局模式;`normal` 参与普通布局,`floating` 会脱离普通布局,不占原来的位置空间 | `'normal' \| 'floating'` | `'normal'` |
-| `leftAside` | 左侧栏配置 | [`LayoutAsideProps`](#layout-aside-props) | `-` |
-| `rightAside` | 右侧栏配置 | [`LayoutAsideProps`](#layout-aside-props) | `-` |
+| `leftAside` | 左侧栏配置 | [`LayoutAsideOptions`](#layout-aside-options) | `-` |
+| `rightAside` | 右侧栏配置 | [`LayoutAsideOptions`](#layout-aside-options) | `-` |
| `floatingState` | 受控浮层状态,需配合 `update:floatingState` 同步外部状态;不要和 `defaultFloatingState` 同时传入 | [`LayoutFloatingState`](#layout-floating-state) | `-` |
| `defaultFloatingState` | 非受控浮层初始状态,仅首次挂载读取一次;不要和 `floatingState` 同时传入 | [`LayoutFloatingState`](#layout-floating-state) | `-` |
-| `floatingOptions` | 浮层拖拽、缩放和尺寸约束配置 | [`LayoutFloatingOptions`](#layout-floating-options) | `-` |
+| `floatingOptions` | 浮层行为配置,包括拖拽、缩放和尺寸约束;不参与状态控制 | [`LayoutFloatingOptions`](#layout-floating-options) | `-` |
### Layout.ProxyScrollbar {#layout-proxy-scrollbar-props}
@@ -255,7 +255,7 @@ function trackAsideChange(detail: { side: 'left' | 'right'; open: boolean }) {
## Types {#types}
-### LayoutAsideProps {#layout-aside-props}
+### LayoutAsideOptions {#layout-aside-options}
| 字段 | 说明 | 类型 | 默认值 |
| ---- | ---- | ---- | ------ |
diff --git a/packages/components/src/layout/composables/useLayoutAsideStates.ts b/packages/components/src/layout/composables/useLayoutAsideStates.ts
index 7b7deeb2f..98bcfcac3 100644
--- a/packages/components/src/layout/composables/useLayoutAsideStates.ts
+++ b/packages/components/src/layout/composables/useLayoutAsideStates.ts
@@ -1,6 +1,6 @@
import type { MaybeRefOrGetter } from '@vueuse/core'
import { computed, toValue } from 'vue'
-import type { LayoutAsideOpenDetail, LayoutAsideProps, LayoutAsideResizeDetail, LayoutSide } from '../index.type'
+import type { LayoutAsideOpenDetail, LayoutAsideOptions, LayoutAsideResizeDetail, LayoutSide } from '../index.type'
import type { LayoutAsideState } from '../internal.type'
import { clamp } from '../utils/number'
import {
@@ -13,14 +13,14 @@ import { useControllableState } from '../../shared/composables/useControllableSt
interface UseLayoutAsideStateOptions {
side: LayoutSide
- config: MaybeRefOrGetter
+ config: MaybeRefOrGetter
onOpenChange?: (detail: LayoutAsideOpenDetail) => void
onExpandedWidthChange?: (detail: LayoutAsideResizeDetail) => void
}
interface UseLayoutAsideStatesOptions {
- leftConfig: MaybeRefOrGetter
- rightConfig: MaybeRefOrGetter
+ leftConfig: MaybeRefOrGetter
+ rightConfig: MaybeRefOrGetter
onOpenChange?: (detail: LayoutAsideOpenDetail) => void
onExpandedWidthChange?: (detail: LayoutAsideResizeDetail) => void
}
diff --git a/packages/components/src/layout/index.type.ts b/packages/components/src/layout/index.type.ts
index 65e21ec2d..0f08f2b00 100644
--- a/packages/components/src/layout/index.type.ts
+++ b/packages/components/src/layout/index.type.ts
@@ -49,7 +49,7 @@ export type LayoutFloatingResizeDetail = LayoutFloatingState & {
handle: LayoutFloatingResizeHandle
}
-export interface LayoutAsideProps {
+export interface LayoutAsideOptions {
mode?: LayoutAsideMode
open?: boolean
defaultOpen?: boolean
@@ -63,8 +63,8 @@ export interface LayoutAsideProps {
}
export interface LayoutAsidePanelsProps {
- leftAside?: LayoutAsideProps
- rightAside?: LayoutAsideProps
+ leftAside?: LayoutAsideOptions
+ rightAside?: LayoutAsideOptions
}
export interface LayoutNormalProps extends LayoutAsidePanelsProps {
From 3cda7373a1679ec8ab6c63c7b6a1a1dd875f0019 Mon Sep 17 00:00:00 2001
From: SonyLeo <746591437@qq.com>
Date: Wed, 8 Jul 2026 19:05:54 -0700
Subject: [PATCH 08/12] feat(docs): update layout documentation and demo labels
for consistency
---
docs/demos/layout/aside-controlled.vue | 4 ++--
docs/demos/layout/aside-modes.vue | 2 +-
docs/demos/layout/basic.vue | 4 ++--
docs/demos/layout/floating-panels.vue | 8 ++++----
docs/src/components/layout.md | 16 ++++++++--------
5 files changed, 17 insertions(+), 17 deletions(-)
diff --git a/docs/demos/layout/aside-controlled.vue b/docs/demos/layout/aside-controlled.vue
index 22f5babbc..8f5cc0b5c 100644
--- a/docs/demos/layout/aside-controlled.vue
+++ b/docs/demos/layout/aside-controlled.vue
@@ -62,7 +62,7 @@ function updateRightAsideOpen(detail: LayoutAsideOpenValue) {
右侧栏
- {{ rightOpen ? '关闭抽屉' : '打开抽屉' }}
+ {{ rightOpen ? '关闭 Drawer' : '打开 Drawer' }}
@@ -92,7 +92,7 @@ function updateRightAsideOpen(detail: LayoutAsideOpenValue) {