SKILL.md
readonlyread-only
name
migrate-radix-to-base
description
將 React 專案與元件從 Radix UI 遷移至 Base UI。當被要求從 radix 遷移、移至 base-ui、轉換 radix 基本元件,或切換 shadcn 專案的基礎函式庫時使用。可處理單一元件(如「遷移 accordion」)與整個專案。
Radix UI -> Base UI 遷移
你負責將 shadcn 包裝器、手寫的 radix 組合以及它們的使用者遷移至 @base-ui/react,並確保專案在每一步都能建置。請保持精確;切勿猜測對應關係。當某個 prop 或部分未出現在這些參考檔案中時,請在轉換前檢查 node_modules/@base-ui/react/**/*.d.ts,並在報告中記錄缺口。
前置檢查(務必執行)
- 執行
npx shadcn@latest info --json(或專案的執行器):取得目前的基礎、STYLE(例如radix-lyra)、tailwind 版本、別名、已安裝的元件以及套件管理器。請信任此資訊而非推測。 - 偵測套件管理器(packageManager 欄位 / 鎖定檔:pnpm-lock.yaml、bun.lock、yarn.lock、package-lock.json),並使用它進行所有安裝。切勿留下過時的鎖定檔。
- 要求乾淨的 git 樹狀結構;在分支上工作;每個元件一個提交。
- 在觸碰相依套件之前進行基線檢查:執行專案的型別檢查/建置,以便預先存在的失敗不會歸咎於你。
- 安裝
@base-ui/react並保留 radix。Radix 套件僅在最後一個元件遷移完成後才移除(兩者可以共存)。
策略:先建立黃金配對,再使用轉換引擎
- 透過 CLI 建立黃金配對(首選)。 如果專案是 shadcn 且使用已知樣式(
radix-<style>),則 shadcn CLI 本身就是黃金配對的執行者:- 首先對每個 ui 包裝器進行分類:將使用者的檔案與其原始來源進行比對,使用 components.json 中的樣式原樣放入 URL(
https://ui.shadcn.com/r/styles/<style>/<component>.json,files[0].content)。這適用於有前綴的樣式(radix-nova)以及舊版無前綴的樣式(new-york、new-york-v4、default),這些都仍然提供服務。 - 整個專案模式:立即將
components.json中的樣式從radix-<style>改為base-<style>。漸進模式:暫時不要更改(專案仍大部分使用 radix;更改僅在最後一個元件後進行一次);改為直接透過 URL 取得 base 變體(https://ui.shadcn.com/r/styles/base-<style>/<component>.json)。 - 未修改的包裝器,整個專案模式:執行
shadcn add <component> --overwrite會以專案確切的圖示/字型/預設解析度提供 base 變體。切勿使用--all --overwrite批次處理;應逐個元件進行,否則你會淹沒在不相關的 registry 版本漂移中。漸進模式:切勿使用--overwrite(它會破壞使用者仍在匯入的原始檔案);改為將取得的 base 變體內容寫入<component>-base.tsx。 - 自訂包裝器:取得 base 變體,並將使用者的差異重新套用上去(他們的自訂必須保留;
--overwrite會破壞它們)。可大規模運作的機械化實作:git merge-file user.tsx radix-golden.tsx base-golden.tsx(三方合併,以 radix golden 作為共同祖先)可自動解決大部分檔案;使用參考表格手動解決衝突。 - 對每個黃金配對檔案進行強制性的殘留掃描,包括那些合併「乾淨」的檔案:對每個檔案執行
grep -n "radix-ui\|@radix-ui\|IconPlaceholder"。Registry 有時會在變體之間重新排列函式,這會導致三方合併報告零衝突,但卻留下舊的 radix 程式碼片段。乾淨的合併並不代表檔案是乾淨的。
此方法比重建轉換更可靠;只要配對存在就使用它。消費者/應用程式碼沒有 CLI 機制:一律根據consumer-props.md手動遷移。
- 首先對每個 ui 包裝器進行分類:將使用者的檔案與其原始來源進行比對,使用 components.json 中的樣式原樣放入 URL(
- 舊版樣式(new-york、new-york-v4、default):僅分類,不重播。 這些樣式沒有對應的 base 版本(沒有 base-new-york),重新定位到 base-<style> 變體會改變使用者應用程式的樣式。僅使用 radix golden 來偵測自訂,然後在使用者自己的檔案上執行轉換引擎:重新連接基本元件,保留他們確切的 class,套用 class-mapping 重新命名。他們的外觀保持不變。在舊版整個專案遷移結束時,標記(不要修正):樣式名稱對 CLI 來說仍然是 radix,因此未來的
shadcn add會提供 radix 變體;由使用者決定是否切換樣式或手動新增。 - 轉換引擎(備用)。 手寫的 radix 程式碼、非 shadcn 專案、未知樣式:使用
universal-patterns.md(兩種形式的匯入:radix-ui和@radix-ui/react-*;asChild -> render 搭配範例;Portal>Positioner>Popup;positioner FORWARD 規則;部分重新命名)、各家族的 props 表格(overlays.md、menus.md、form-controls.md、disclosure.md、display-misc.md)、class-mapping.md用於 data-attribute/CSS-var 重寫,以及wrapper-shapes.md用於確切的目標形狀(tooltip arrow、SubContent 預設值、select 解剖結構)。
模式
漸進模式(預設)。「遷移 accordion」= 單一元件,絞殺藤模式:
- 首先偵測進行中的狀態:是否存在
<component>-base.tsx,消費者分散在舊/新匯入之間。檔案本身就是狀態;從中繼續,切勿重新開始。 - 如果該元件匯入其他仍使用 radix 的 ui 包裝器(select -> button),則停止並建議先從底層開始遷移這些元件。
- 將遷移後的版本寫入
<component>-base.tsx(原始檔案保持不變;黃金配對內容透過 URL 取得,或手動轉換,依上述策略);進行型別檢查。一次一個地重新指向消費者(匯入以及consumer-props.md中的呼叫端 props);每次進行型別檢查。當沒有消費者匯入原始檔案時:刪除它,將-base重新命名為原始名稱,將匯入改回,進行最終檢查,提交。當專案中最後一個 radix 包裝器完成時,將components.json改為base-<style>並移除 radix 相依套件。
整個專案模式(僅在明確要求時):按照相依順序進行相同的逐個元件工作(先處理葉子/共享包裝器,如 button 和 label)。包裝器完成後,根據 consumer-props.md 掃描所有應用程式碼——呼叫端的破壞面比 asChild 大得多。然後移除 radix 相依套件、安裝、完整建置。
嚴格規則
- 絕對不要觸碰非 radix 的函式庫或其包裝器:cmdk(command)、vaul(drawer)、sonner、input-otp、react-day-picker(calendar)、recharts(chart)。將它們報告為故意未觸碰。
- 無 Base UI 對應:AspectRatio -> CSS aspect-ratio div;Label -> 原生
<label>;VisuallyHidden ->sr-only;Direction -> Direction Provider(directionprop,而非dir)。Popover Anchor 和 NavigationMenu Indicator 沒有對應項目:直接傳遞 + 標記。 button.tsx遷移至真正的@base-ui/react/button基本元件,絕不使用手寫的 useRender 包裝器。- 行為差異會被標記,絕不默默修補(tabs 手動啟用、選單項目點擊後不關閉、nav-menu 50ms 延遲)。目標是符合 shadcn base registry 的慣用 Base UI。
- 誠實報告:跳過/還原的檔案被標記為已標記,絕不標記為已遷移。預先存在的失敗被標記為預先存在。
驗證與報告
每個檔案進行型別檢查,每批次進行建置,最後與基線進行完整建置比較。
報告存放在專案根目錄的 .migration/ 目錄中,每個元件一個檔案:.migration/<component>.md(例如 .migration/accordion.md)。規則:
- 每次執行會為其遷移的每個元件寫入(或完全覆蓋)該檔案。重新執行某個元件會取代其報告;絕不觸碰其他元件的檔案。
- 多元件執行(如「遷移 alert-dialog 和 dropdown-menu」)會為每個元件寫入一個檔案,每個檔案自包含;共享的消費者掃描備註會重複出現在每個受影響的檔案中。
- 整個專案模式會寫入每個元件的檔案,加上
.migration/project.md(相依套件交換、應用程式碼掃描摘要、最終建置結果)。 - 沒有索引檔案。遷移狀態從磁碟推斷,而非維護:當被問到「還剩下什麼」時,掃描專案的 ui 目錄(來自 shadcn info 的
ui別名,例如 components/ui 或 src/components/ui)以尋找剩餘的 radix 匯入。每次執行的摘要結尾都要包含這個推斷的計數(「還有 N 個包裝器使用 Radix」)。
每個 .migration/<component>.md 使用完全相同的結構(這是公開文件;報告必須符合):
# <component>
<日期,使用的策略(透過 CLI 的黃金配對 / 合併 / 引擎),一行結論>
## 已變更
<每個觸碰的檔案,說明變更內容與原因;對於任何值得注意的項目,包含檔案:行號。確認殘留掃描是乾淨的:
對此元件的檔案執行 grep -n "radix-ui\|@radix-ui">
## 未觸碰
<看似相關但故意未觸碰的檔案,附上原因(cmdk/vaul/sonner 不是 radix;無關的漂移;等等)>
## 行為變更
<編譯正常但行為不同的差異;標記,絕不修補(tabs 啟用、選單點擊關閉、延遲...)。如果沒有則留空>
## 手動驗證
<針對此基本元件家族的簡短手動 QA 檢查清單:對話框的焦點返回、選單/選擇的鍵盤導航 + 打字搜尋、tooltip 延遲感覺、slider 提交事件。具體步驟,約一分鐘的點擊操作>






