mcpField
A
add-hook

add-hook

github.com/debbl开发6148 次安装6 周前更新
代码仓库

关于 add-hook

面向 shadcn-hooks 贡献者的新增 Hook 指南,按步骤覆盖注册、实现、文档和测试。它明确区分源码与自动生成目录,并要求把同步留给用户处理。

主要功能

  1. 01创建 Hook 实现与依赖清单
  2. 02编写交互式演示和文档
  3. 03更新注册表与介绍页
  4. 04添加参考文档和函数表条目
  5. 05运行 lint 与测试验证
  6. 06禁止编辑生成目录或执行同步

适用场景

  1. 01为 shadcn-hooks 添加新 Hook
  2. 02按项目规范补齐 Hook 文件
  3. 03验证 Hook 文档与测试

安装

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

$npx skills add https://github.com/debbl/shadcn-hooks --skill add-hook

安装后在 Claude Code 中输入/add-hook确认已加载。

详细介绍

添加 Hook

向 shadcn-hooks 项目添加新 Hook 的指南。唯一可信来源是 src/registry/hooks/。packages/shadcn-hooks/ 目录是自动生成的,不应手动编辑。请勿在此技能中运行任何 sync 命令;用户会在需要时手动运行。

检查清单

复制此检查清单并跟踪进度:

Add Hook: use-<name>
- [ ] Step 1: Create registry entry (src/registry/hooks/use-<name>/)
- [ ] Step 2: Register in meta.json
- [ ] Step 3: Update introduction.mdx
- [ ] Step 4: Create skill reference doc
- [ ] Step 5: Update skill SKILL.md function table
- [ ] Step 6: Verify (lint + test)

第 1 步:创建注册表条目

创建目录 src/registry/hooks/use-<name>/,并在其中放置 5 个文件:

1a. index.ts — Hook 实现

规则:

  • 使用 @/registry/hooks/... 和 @/registry/lib/... 导入别名
  • 命名导出:export function use<Name>(...)
  • 在同一文件中导出所有公共类型
  • 使用严格的 TypeScript,不得使用 any
  • 尽可能复用现有 Hook(例如 useBoolean、useEventListener、useMemoizedFn)

参考示例——简单的 Hook:

// src/registry/hooks/use-previous/index.ts
import { useRef } from 'react'

export type ShouldUpdateFunc<T> = (prev?: T, next?: T) => boolean
const defaultShouldUpdate = <T>(a?: T, b?: T) => !Object.is(a, b)

export default function usePrevious<T>(
  state: T,
  shouldUpdate: ShouldUpdateFunc<T> = defaultShouldUpdate,
): T | undefined {
  const prevRef = useRef<T>()
  const curRef = useRef<T>()

  if (shouldUpdate(curRef.current, state)) {
    prevRef.current = curRef.current
    curRef.current = state
  }

  return prevRef.current
}

参考示例——组合其他 Hook 的 Hook:

// src/registry/hooks/use-hover/index.ts
import { useBoolean } from '@/registry/hooks/use-boolean'
import { useEventListener } from '@/registry/hooks/use-event-listener'
import type { BasicTarget } from '@/registry/lib/create-effect-with-target'

export interface UseHoverOptions {
  onEnter?: () => void
  onLeave?: () => void
  onChange?: (isHovering: boolean) => void
}

export function useHover(
  target: BasicTarget,
  options?: UseHoverOptions,
): boolean {
  const { onEnter, onLeave, onChange } = options || {}
  const [state, { setTrue, setFalse }] = useBoolean(false)
  useEventListener(
    'mouseenter',
    () => {
      onEnter?.()
      setTrue()
      onChange?.(true)
    },
    { target },
  )
  useEventListener(
    'mouseleave',
    () => {
      onLeave?.()
      setFalse()
      onChange?.(false)
    },
    { target },
  )
  return state
}
1b. registry-item.json — 依赖项
{
  "registryDependencies": [
    "@shadcnhooks/use-dependency-a",
    "@shadcnhooks/use-dependency-b"
  ]
}
  • 列出此 Hook 所依赖的所有 Hook/库,并为其添加 @shadcnhooks/ 前缀
  • 如果没有依赖项:{ "registryDependencies": [] }
1c. demo/demo-01.tsx — 演示组件
'use client'
import { use<Name> } from '..'

export function Demo01() {
  // Interactive demo showcasing the hook
}

规则:

  • 必须是客户端组件('use client')
  • 从 '..'(父目录)导入 Hook
  • 使用来自 ~/components/ui/... 的 shadcn UI 组件(例如 Button、Card、Input)
  • 演示应具有交互性,并清晰展示 Hook 的行为
1d. index.mdx — 文档页面
---
title: use<Name>
description: A hook to <description>
---

import { Demo01 } from './demo/demo-01'

<Demo01 />

## Installation

<Tabs items={['CLI', 'Manual']}>
  <Tab>
    <InstallCLI value='use-<name>' />
  </Tab>
  <Tab>
    Copy and paste the following code into your project.
    <RegistrySourceCode value='use-<name>' />
  </Tab>
</Tabs>

## API

\`\`\`ts
// Full type declarations here
\`\`\`

## Credits

- [use-<name>](credit-link)

注意:

  • 如果此 Hook 存在内部依赖项,请在 Manual 选项卡下添加多个 <RegistrySourceCode> 条目(参见包含 use-toggle 的 use-boolean)
  • API 部分应包含完整的 TypeScript 类型声明
1e. index.test.ts — 测试
import { act, renderHook } from '@testing-library/react'
import { describe, expect, it } from 'vitest'
import { use<Name> } from './index'

describe('use<Name>', () => {
  it('should ...', () => {
    const { result } = renderHook(() => use<Name>(...))
    expect(result.current).toBe(...)
  })
})

规则:

  • 使用 vitest 和 @testing-library/react
  • 从 './index' 导入
  • 覆盖:默认行为、状态变化、边缘情况、回调
  • 对于基于 DOM 的 Hook,在 beforeEach 中创建元素,并在 afterEach 中清理

第 2 步:在 meta.json 中注册

在 src/registry/hooks/meta.json 的相应类别下添加 "use-<name>":

  • ---State--- — 状态管理 Hook
  • ---Advanced--- — 记忆化、引用、高级模式
  • ---Lifecycle--- — Effect、计时器、挂载/卸载
  • ---Browser--- — DOM、事件、浏览器 API
  • ---Dev--- — 开发与调试工具
  • ---External--- — 外部库的封装

第 3 步:更新介绍页面

在 content/docs/introduction.mdx 的相应类别下添加新 Hook:

  • State Management — 状态管理 Hook
  • Advanced — 记忆化、引用、高级模式
  • Lifecycle & Effects — Effect、计时器、挂载/卸载
  • Browser — DOM、事件、浏览器 API
  • Dev — 开发与调试工具
  • External Libraries — 外部库的封装

在类别中按字母顺序添加一行:

- [`use<Name>`](/docs/hooks/use-<name>) - <Short description>

第 4 步:创建技能参考文档

创建 skills/shadcn-hooks/references/use<Name>.md:

# use<Name>

<One-line description>.

## Usage

\`\`\`tsx
import { use<Name> } from '@/hooks/use-<name>'

function Component() {
// Minimal usage example
}
\`\`\`

## Type Declarations

\`\`\`ts
// Full type signatures
\`\`\`

## Parameters

| Parameter | Type | Default | Description |
| --------- | ---- | ------- | ----------- |
| ...       | ...  | ...     | ...         |

## Returns

| Type | Description |
| ---- | ----------- |
| ...  | ...         |

第 5 步:更新技能函数表

在 skills/shadcn-hooks/SKILL.md 的相应类别表格中添加一项:

| [`use<Name>`](references/use<Name>.md) | <description> | AUTO |
  • 独立 Hook 使用 AUTO
  • 封装外部 npm 包的 Hook 使用 EXTERNAL

第 6 步:验证

  1. 运行代码检查工具:检查已编辑文件是否存在代码检查错误
  2. 运行测试:pnpm test run src/registry/hooks/use-<name>/index.test.ts
  3. 验证开发服务器是否能正确呈现文档页面(如果正在运行)
  4. 请勿修改 packages/shadcn-hooks/,也不要运行 pnpm run sync 或 pnpm --dir packages/shadcn-hooks sync;将此步骤留给用户

注意事项

  • packages/shadcn-hooks/ 是自动生成的。在此技能中,切勿手动编辑该目录中的文件。
  • 请勿在此技能中执行任何 sync 命令。用户会在检查更改后手动运行同步。
  • packages/shadcn-hooks/src/index.ts 中的导出也由自动流程管理,无需手动编辑。

评论

支持 Markdown