Files
simple-react-app-kit/packages/layout/README.md
T
2026-09-30 01:30:56 +08:00

4.1 KiB
Raw Blame History

Layout

@workspace/layout 提供路由无关的应用级布局。AppLayout 以内容区为核心,并按需组合 Header、Navigation Rail、Sidebar、Aside 和 Footer。

安装样式源

在应用的全局样式中导入:

@import "@workspace/layout/globals.css";

布局模型

+-------------------------------------+
| header                              |  headerStart="rail"
+------+---------+---------+----------+
|      | header                       |  headerStart="sidebar"
|      +---------+---------+----------+
|      |         | header             |  headerStart="content"
|      |         +---------+----------+
|      |         |         |          |
| rail | sidebar | content |          |
|      |         +---------+  aside   |
|      |         | footer  |          |  footerStart="content"
|      +---------+---------+          |
|      | footer            |          |  footerStart="sidebar"
+------+-------------------+----------+

图中的多个 Header 和 Footer 表示可选位置,不会同时渲染。children 是唯一必需的内容区,其他区域均为可选 slot:

  • rail:最外侧的一级导航,类似 Activity Bar。
  • sidebar:当前一级导航下的导航或工作区上下文。
  • aside:AI、文档、检查器等内容辅助区域。
  • header:右边界始终包含有效的 aside。
  • footer:始终属于中心工作区,不会延伸到 rail 或 aside 下方。

基本用法

Slot 可以接收已经创建的 React 节点,也可以接收无必需属性的组件定义。组件定义在 AppLayout 的 Provider 内创建,因此可以调用 useLayoutConfig。

import { AppLayout } from "@workspace/layout"

export function Application() {
  return (
    <AppLayout
      header={AppHeader}
      rail={ActivityRail}
      sidebar={<NavigationSidebar groups={navigationGroups} />}
      aside={AssistantPanel}
      footer={StatusBar}
      defaultLayout={{
        asideOpen: true,
        footerStart: "sidebar",
        headerStart: "sidebar",
      }}
    >
      <RouterOutlet />
    </AppLayout>
  )
}

LayoutConfig

LayoutConfig 是扁平、可序列化的完整快照;layout 和 defaultLayout 接收 Partial<LayoutConfig>。

interface LayoutConfig {
  asideEnabled: boolean
  asideOpen: boolean
  footerStart: "sidebar" | "content"
  headerStart: "rail" | "sidebar" | "content"
  sidebarCollapsible: boolean
  sidebarOpen: boolean
}

默认值:

const defaultLayoutConfig = {
  asideEnabled: true,
  asideOpen: false,
  footerStart: "content",
  headerStart: "rail",
  sidebarCollapsible: true,
  sidebarOpen: true,
}
  • 提供 layout 时采用受控模式,交互后通过 onLayoutChange 返回完整快照。
  • 未提供 layout 时采用非受控模式,以 defaultLayout 或默认配置初始化。
  • 区域暂时不可用只影响有效布局,不会覆盖配置中保存的用户偏好。

useLayoutConfig

区域组件可以读取布局状态并触发布局更新:

import { useLayoutConfig } from "@workspace/layout"

export function AppHeader() {
  const {
    layout,
    setAsideOpen,
    setSidebarOpen,
    toggleAside,
    toggleSidebar,
    updateLayout,
  } = useLayoutConfig()

  // Render application controls.
}

Hook 必须在 AppLayout 子树内调用。updateLayout 接收局部配置或根据当前完整配置生成局部配置的函数。

自动内移

headerStart 和 footerStart 表示期望位置。布局会根据当前实际可见的区域计算有效位置,但不会改写原配置:

  • headerStart="rail" 表示全局 Header;没有 Rail 时从第一个实际存在的区域开始。
  • 只有 Rail 与 Sidebar 同时可见时,headerStart="sidebar" 和 footerStart="sidebar" 才会生效。
  • 其他情况下,"sidebar" 自动内移为 "content"。
  • Aside 始终贯穿中心工作区高度,不参与 Footer 范围。

尺寸

可以通过 CSS 自定义属性调整三个辅助列:

.application-layout {
  --layout-rail-width: 4rem;
  --layout-sidebar-width: 18rem;
  --layout-aside-width: 22rem;
}