WebberUI

Ornament Toolbar

懸浮於內容面板邊緣之外的 visionOS 風格裝飾工具列,捲動時自動縮合為膠囊、停下時展開完整控制,並帶有 Z 軸抬升與跟隨視差。

載入預覽⋯

Playground

即時調整 props、程式碼片段同步更新——直接試出你要的樣子再複製。

20
360
<OrnamentToolbar />

安裝

npx shadcn@latest add https://webberui.com/r/ornament-toolbar.json

或在 components.json 設定 registries 後,改用 @webberui/ornament-toolbar 安裝。

安裝依賴後,從 registry JSON(/r/ornament-toolbar.jsonfiles[0].content)複製 ornament-toolbar.tsx 原始碼到你的 components/ui/ 目錄:

npm install motion clsx tailwind-merge lucide-react

使用

OrnamentToolbar 包住一個可捲動的內容面板(OrnamentContent)與一個懸浮工具列(Ornament)。工具列停靠在面板邊緣之外,捲動 OrnamentContent 時自動縮合為膠囊、停下時展開;滑鼠移入或鍵盤聚焦也會強制展開。各控制項用 OrnamentItem,群組間可插入 OrnamentSeparator

import {
  Ornament,
  OrnamentContent,
  OrnamentItem,
  OrnamentSeparator,
  OrnamentToolbar,
} from "@/components/ui/ornament-toolbar";
import { Bookmark, Minus, Plus, Share2 } from "lucide-react";

export function Example() {
  return (
    <OrnamentToolbar side="bottom" className="h-[280px]">
      <OrnamentContent className="p-5">{/* 可捲動內容 */}</OrnamentContent>

      <Ornament aria-label="文件工具列">
        <OrnamentItem icon={<Minus />} aria-label="縮小" />
        <OrnamentItem icon={<Plus />} label="100%" aria-label="放大" />
        <OrnamentSeparator />
        <OrnamentItem icon={<Bookmark />} aria-label="書籤" />
        <OrnamentItem icon={<Share2 />} aria-label="分享" />
      </Ornament>
    </OrnamentToolbar>
  );
}

受控模式:傳入 collapsedonCollapsedChange 自行掌握縮合狀態(此時捲動不再自動縮合)。

元件組成

元件說明
OrnamentToolbar最外層容器,提供捲動偵測與縮合狀態;在此以 className 指定尺寸
OrnamentContent內容面板,本身即捲動容器,工具列依此容器的捲動而縮合/展開
Ornament懸浮於面板邊緣之外的工具列本體,role="toolbar"
OrnamentItem單一控制項;有 label 時展開為藥丸,縮合時只留圖示
OrnamentSeparator控制項群組間的垂直分隔線

Props

OrnamentToolbar

Prop型別預設值說明
side"top" | "bottom""bottom"工具列懸浮於面板哪一側邊緣之外
offsetnumber20工具列與面板邊緣的距離(px)
collapsedboolean受控的縮合狀態;傳入後捲動不再自動縮合
defaultCollapsedbooleanfalse非受控模式的初始縮合狀態
onCollapsedChange(collapsed: boolean) => void縮合狀態變更回呼
collapseOnScrollbooleantrue是否在捲動時自動縮合、停下時展開
idleDelaynumber360停止捲動後判定為靜止並展開的延遲(ms)
classNamestring追加至容器;建議在此指定尺寸

Ornament

Prop型別預設值說明
aria-labelstring"工具列"工具列的無障礙名稱
classNamestring追加至膠囊容器

OrnamentItem

Prop型別預設值說明
iconReact.ReactNode控制項圖示(建議使用 lucide-react)
labelReact.ReactNode文字標籤;縮合為膠囊時平順收合
activebooleanfalse作用中狀態,以 aria-pressed 標記並反白
aria-labelstringlabel 時必填,作為圖示按鈕的無障礙名稱

其餘原生 <button> 屬性(onClickdisabled 等)皆會透傳。

細節

  • 懸浮於邊緣之外Ornament 以絕對定位貼齊面板的 topbottom 邊緣之外並水平置中,offset 控制與面板的距離。最外層容器不裁切,記得在其下方(或上方)預留空間。
  • 捲動縮合、停下展開:偵測 OrnamentContent 的捲動事件,捲動時縮合為膠囊、idleDelay 內無捲動即展開。收合時各控制項的標籤以 spring 平順收合成純圖示膠囊。
  • Z 軸抬升與跟隨視差:縮合時陰影加深、整體微縮,模擬向使用者抬升的高度;捲動速度經 spring 平滑後映射為輕微的垂直跟隨位移,形成漂浮般的視差。
  • hover/focus 強制展開:滑鼠移入或鍵盤焦點落在工具列內時一律展開,確保指標與鍵盤使用者都能看到完整控制項。

可及性

  • Ornamentrole="toolbar" 並帶 aria-orientation;方向鍵在控制項間移動焦點,HomeEnd 跳至首尾。
  • OrnamentItemactivearia-pressed 表達;無文字標籤時必須提供 aria-label,有 label 時自動採用其文字作為無障礙名稱。
  • 鍵盤聚焦工具列時強制展開並顯示標籤,縮合狀態不會妨礙鍵盤操作。
  • 使用者系統開啟「減少動態效果」時,停用自動縮合與跟隨視差,工具列維持展開,標籤與縮放改為即時切換。

On this page