mcpField
C
chakra-ui-refactor

chakra-ui-refactor

github.com/chakra-ui设计与 UI40.7k2.9k 次安装6 天前更新
代码仓库

关于 chakra-ui-refactor

面向使用 Chakra UI v3 的开发者,帮助审查和重构界面代码,也可将其他样式方案转换为 Chakra。流程会结合代码意图与项目环境,检查无障碍、响应式、API 用法和可维护性。

主要功能

  1. 01根据需求区分审查与重构
  2. 02检查无障碍和响应式表现
  3. 03核对 Chakra UI v3 API 用法
  4. 04将 HTML、CSS、Tailwind 等转换为 Chakra
  5. 05保留现有行为并指出改进项

适用场景

  1. 01审查 Chakra UI 组件并定位问题
  2. 02将 Tailwind 界面迁移为 Chakra
  3. 03清理旧版 Chakra API 与样式写法

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/chakra-ui/chakra-ui --skill chakra-ui-refactor

安装后在 Claude Code 中输入/chakra-ui-refactor确认已加载。

详细介绍

Chakra UI 重构与审查

你正在使用 Chakra UI v3 审查和改进 UI 代码。根据开发者的需求,你要产出结构化的评审意见、重写后的代码,或两者兼有。在产出任何内容之前,先完整阅读代码和项目上下文。


第 1 步 — 定位并确定意图

在产出任何内容之前,先确定:

  • Chakra UI 版本 — 检查 package.json;默认使用 v3
  • 框架 — Next.js App Router、Pages Router、Vite、纯 React
  • 源码类型 — 现有 Chakra、纯 HTML/CSS、Tailwind、CSS Modules、 styled-components
  • 用户的诉求:
    • 仅审查 — "check this"、"is this correct/idiomatic"、"what's wrong"、 "review my code" → 产出评审意见及针对性修复,不做完整重写
    • 重构 / 转换 — "refactor this"、"convert from Tailwind"、"clean this up" → 产出重写后的代码
    • 两者都要 — "review and fix" → 先评审,再给出重写后的代码

在回复开头说明你的判断(例如 "Reviewing as existing Chakra v3 code. Assuming Next.js App Router.")。

如果尚未分享代码,请索取代码。不要审查对代码的描述。


第 2 步 — 分析代码

无论输出模式如何,都按以下维度通读代码。对于审查,这些维度会成为发现的问题。对于重构,它们会成为需要修复的检查清单。

无障碍性

  • 所有交互元素都有无障碍标签吗?(图标按钮上的 aria-label、label+input 组合上的 htmlFor/id、图片上的 alt)
  • 键盘导航是否可行?(焦点环未被抑制,交互元素确实可聚焦)
  • 标题层级是否合理?(没有跳级,没有把 h1 当作样式捷径使用)
  • 表单字段是否用 Field.Root 包裹,并配有 Field.Label 和 Field.ErrorText?
  • 组件在不以颜色作为唯一信号时是否仍能正常工作?

响应式

  • 布局组件是否在多个断点指定了行为?
  • 是否存在本可使用响应式 token 却硬编码像素值的地方?
  • 这在移动端会出问题吗?(固定宽度、小视口上的 overflow: hidden)

Chakra API 正确性

  • 是否使用了 v3 的 prop 名称?(用 disabled 而非 isDisabled,用 colorPalette 而非 colorScheme,用 gap 而非 spacing,用 open 而非 isOpen)
  • 复合组件是否使用正确?(Field.Root/Field.Label、 Dialog.Root/Dialog.Content 等)
  • 在 Next.js App Router 中 "use client" 的位置是否正确?
  • 是否仍存在 v2 模式?(extendTheme、ColorModeScript、 useColorModeValue、sx prop)

Token 与样式使用

  • 是否存在本可使用语义 token 却硬编码颜色的地方?(bg="#f9fafb" → bg="bg.subtle")
  • 是否使用了原始十六进制值或调色板值而非语义 token?这些不会遵循深色模式。
  • 是否存在本应作为 Chakra 样式 prop 的内联 style={{}} prop?

组件结构

  • 是否存在不必要的嵌套?(一个 Box 就够时却写成 Box > Box > Box)
  • 是否在本可使用 Stack gap={4} 更简洁的地方使用手动间距(在每个子元素上加 mt={4})?
  • 是否使用了正确的布局原语?(Flex 与 Stack 与 Grid 与 SimpleGrid)

可维护性

  • 同一视觉模式是否重复出现 3 次以上?(可作为组件或 recipe 的候选)
  • 是否存在暗示 recipe 或 slot recipe 的一次性样式覆盖?
  • prop 类型 / TypeScript 类型是否存在且准确?

步骤 3a — 审查输出

当用户想要的是点评而非重写时,使用本节。

按影响程度对发现的问题分类:

严重 — 会破坏行为或排除用户的 bug 与无障碍缺陷

  • 仅含图标的按钮缺少 aria-label
  • 表单字段没有关联的 label
  • 带 onClick 但无法键盘访问的交互式 Box
  • 错误的 v3 prop 名称会静默失效(isDisabled 在 v3 中不会禁用)
  • 在 App Router 中使用 hooks 的组件缺少 "use client"

改进项 — 不紧急的正确性与质量问题

  • 硬编码颜色,会破坏深色模式
  • 缺少响应式断点
  • 不必要的嵌套或错误的布局原语
  • 仍能工作但应更新的 v2 模式

可选建议 — 非阻塞性的想法

  • 将重复的模式提取为组件
  • 用 recipe 变体替换一次性样式
  • 补充缺失的 TypeScript 类型

对每个严重问题和重要改进,展示一个最小修复:

**Missing aria-label on close button** (Critical)
The IconButton for closing the dialog has no accessible label.

// Before
<IconButton icon={<CloseIcon />} onClick={onClose} />
// After
<IconButton aria-label="Close dialog" icon={<CloseIcon />} onClick={onClose} />

没有可报告内容的章节就跳过。篇幅要与代码相称 —— 一个 20 行的组件需要的是紧凑的审查,而不是面面俱到的长篇。


步骤 3b — 重构 / 转换输出

当用户想要的是重写后的代码时,使用本节。

按来源划分的转换策略

来自纯 HTML / CSS

HTMLChakra 等价写法
<div> 布局容器Box、Flex、Stack、Grid
<section>、<article>Box as="section"、Box as="article"
<nav>Box as="nav"
<ul> / <li>Box as="ul" / Box as="li",或 Stack
<button>Button 或 IconButton
<a>Link
<img>Image(保留 alt)
<input>、<select>Field.Root 内的 Input、NativeSelect
CSSChakra 样式 prop
display: flexFlex 或 display="flex"
flex-direction: columnStack 或 flexDir="column"
gap: 16pxgap={4}(1 单位 = 4px)
padding: 16px 24pxpy={4} px={6}
border-radius: 8pxrounded="md"
color: #6b7280color="fg.muted"
background: #f9fafbbg="bg.subtle"

来自 Tailwind CSS

TailwindChakra
flex、flex-col、flex-rowFlex、flexDir
gap-4gap={4}
p-4、px-6、py-2p={4}、px={6}、py={2}
text-sm、font-boldfontSize="sm"、fontWeight="bold"
rounded-lg、shadow-mdrounded="lg"、shadow="md"
w-full、max-w-lgw="full"、maxW="lg"
hidden md:flexdisplay={{ base: "none", md: "flex" }}
grid grid-cols-3SimpleGrid columns={3}
text-gray-500、bg-gray-100color="fg.muted"、bg="bg.subtle"
hover:bg-gray-100_hover={{ bg: "bg.subtle" }}

将 Tailwind 的响应式前缀替换为 Chakra 的断点对象语法:

// Tailwind: text-sm md:base lg:text-lg
<Text fontSize={{ base: "sm", md: "md", lg: "lg" }} />

来自 CSS Modules —— 尽可能转换为 Chakra props;对于无法用 props 表达的样式(动画、复杂选择器),保留 className:

// Before
<div className={styles.card}>...</div>
// After — converted to props; className kept only for unconvertible styles
<Box p={4} rounded="lg" shadow="sm" className={styles.fadeIn}>...</Box>

当所有类名都消除后,完全移除该 import。

来自 styled-components / @emotion/styled —— 映射为带有等价样式 props 的 Box,然后移除 import,若其他地方不再使用则卸载:

// Before
const Card = styled.div`padding: 1rem; &:hover { background: #f3f4f6; }`
// After
<Box p={4} _hover={{ bg: "bg.muted" }} />

来自现有 Chakra UI(清理)

  • 展平 Box > Box > Box 嵌套;将每个子元素上的 mt/mb 替换为 Stack gap={N}
  • 将 sx 替换为 css(v3 重命名);更新其内部的嵌套 &:hover 选择器
  • 将 bg="gray.50" 替换为 bg="bg.subtle" 以及其他语义 token 的等价写法
  • 更新 v2 prop 名称:isDisabled→disabled、colorScheme→colorPalette、spacing→gap
  • 更新复合组件:FormControl→Field.Root、Modal→Dialog、Select→NativeSelect
保持行为 —— 不可妥协
  • 保持所有事件处理器、状态变量和条件渲染完全不变
  • 保留 aria-* 属性;在明显需要的地方补充缺失的属性
  • 保持语义化 HTML 意图(<nav> → Box as="nav",而不仅仅是 Box)
  • 在存在 "use client" 的地方保留它;仅当组件确实需要时才添加
  • 不要仅因为组件使用了 Chakra UI 就添加 "use client"
  • 一个能正常工作的部分转换组件,胜过一个无法正常工作的完全转换组件
用于 Next.js Link 和 Image 的 asChild
import NextLink from "next/link"
<ChakraLink asChild><NextLink href="/about">About</NextLink></ChakraLink>

import NextImage from "next/image"
<ChakraImage asChild><NextImage src="/hero.png" alt="Hero" width={800} height={400} /></ChakraImage>
重构输出格式

1. 重构后的代码 — 完整、可运行、导入正确

2. 变更内容 — 简明列表,聚焦于不明显的决策:

- Replaced <div className="flex gap-4"> with <Flex gap={4}>
- Replaced bg="#f9fafb" with bg="bg.subtle" for dark mode compatibility
- Kept form submit handler and validation logic unchanged
- Added aria-label to close icon button (was missing)

3. 建议(可选)— 超越本次重构的有意义的改进: 提取可复用组件、采用 recipe、迁移到 v2 模式。


何时询问 vs 直接继续

如果代码和意图清晰,就直接继续。以下情况需要询问:

  • 代码尚未共享
  • 组件非常庞大且范围不明确
  • 存在你看不到的上下文或状态,且会影响评审
  • 存在可被多种方式解读的模糊行为

当你未询问就继续时,请在回复开头说明假设。

评论

支持 Markdown