# @classmatejs/react 中文文档

规范地址：https://npmcn.com/package/%40classmatejs/react/

版本：0\.3\.0
npm 元数据更新时间：2026-07-28T05:46:37.353Z
中文译文更新时间：2026-11-09T23:52:08.484Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40classmatejs/react
原文对照：https://npmcn.com/package/%40classmatejs/react/?lang=original
项目主页：https://github.com/richard-unterberg/classmatejs/tree/master/packages/react#readme
源码仓库：https://github.com/richard-unterberg/classmatejs

弃用说明：Package no longer supported\. Contact Support at https://www\.npmjs\.com/support for more info\.

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：68.2 kB，6 个文件
- 模块格式：ESM + CJS
- TypeScript 类型：包内自带
- 运行依赖：1 个
- peer 依赖：react \>=16\.8\.0
- 首次发布：2025-11-25T10:42:50.543Z
- 最新版本发布：2026-06-28T11:20:47.732Z
- 近 30 天下载量：23257（2026-10-10 至 2026-11-08，npm 官方下载统计）
- 已发布版本数：10（近 12 个月 10 个）

## 中文简介

一个反应工具可以分出类名逻辑,创建变体并管理样式.

## 安装

```sh
npm install @classmatejs/react
```

也可以使用：`pnpm add @classmatejs/react`、`yarn add @classmatejs/react`、`bun add @classmatejs/react`

## README

# @ classmatejs/ 反应

一个管理 React 组件类名,变体和样式的工具.

## \# # 转换这个 # # Form this #

```jsx
const SomeButton = ({ isLoading, ...props }) => {
  const activeClass = isLoading
    ? "bg-blue-400 text-white"
    : "bg-blue-800 text-blue-200";

  return (
    <button
      {...props}
      className={`transition-all mt-5 border-1 md:text-lg text-normal ${someConfig.transitionDurationEaseClass} ${activeClass} ${
        props.className || ""
      }`}
    >
      {props.children}
    </button>
  );
};
```

## 进

```js
const SomeButton = cm.button`
  text-normal
  md:text-lg
  mt-5
  border-1
  transition-all
  ${someConfig.transitionDurationEaseClass}
  ${({ $isLoading }) => $isLoading && "opacity-90 pointer-events-none"}
`;
```

## 特征

-   以名称为重点的类别组件
-   备选案文
-   扩展组件
-   变形组件
-   动态样式
-   类型脚本支持
-   试用了安全部门改革框架
-   类名合并

## 目录

-   [特征](https://npmcn.com/package/%40classmatejs/react/#readme-features)
-   [开始](https://npmcn.com/package/%40classmatejs/react/#readme-getting-started)
-   [基本用途](https://npmcn.com/package/%40classmatejs/react/#readme-basic)
-   [道具的使用](https://npmcn.com/package/%40classmatejs/react/#readme-use-with-props)
-   [创建变量](https://npmcn.com/package/%40classmatejs/react/#readme-create-variants)
-   [扩展组件](https://npmcn.com/package/%40classmatejs/react/#readme-extend)
-   [变形组件](https://npmcn.com/package/%40classmatejs/react/#readme-transform)
-   [添加 CSS 样式](https://npmcn.com/package/%40classmatejs/react/#readme-add-css-styles)
-   [使用内部 React 组件](https://npmcn.com/package/%40classmatejs/react/#readme-use-inside-react-components)
-   [添加逻辑头](https://npmcn.com/package/%40classmatejs/react/#readme-add-logic-headers)
-   [食谱 `cm.extend`](https://npmcn.com/package/%40classmatejs/react/#readme-receipes-for-cmextend)
    -   [使用 cm 来创建基础组件](https://npmcn.com/package/%40classmatejs/react/#readme-use-cm-for-creating-base-component)
    -   [道具的自动推断类型](https://npmcn.com/package/%40classmatejs/react/#readme-auto-infer-types-for-props)
    -   [扩展其他 lib 组件 / `any` 作为输入](https://npmcn.com/package/%40classmatejs/react/#readme-extending-other-lib-components--any-as-input)

## 开始

确定您已经安装 [反应](https://react.dev/) ( > 16.8.0) 输入 项目.

```bash
npm i @classmatejs/react
# or
yarn add @classmatejs/react
```

对于捆绑的应用程序,您也可以将 ClassmateJS 安装为 dev 依赖:

```bash
npm i -D @classmatejs/react
# or
yarn add -D @classmatejs/react
```

对解决的软件包/图书馆或部署使用常规依赖 `node_modules` 仅安装生产依赖的运行时间.

## 基础

通过调用创建组件 `cm` 带有标签名称和模板文字 绳子.

```tsx
import cm from "@classmatejs/react";

const Container = cm.div`
  py-2
  px-5
  min-h-24
`;
// transforms to: <div className="py-2 px-5 min-h-24" />
```

### 使用道具

将道具传递到组件,并在模板字串和其中使用 组件道具验证.

```tsx
// hey typescript
interface ButtonProps {
  $isActive?: boolean;
  $isLoading?: boolean;
}
const SomeButton = cm.button<ButtonProps>`
  text-lg
  mt-5
  ${({ $isActive }) => ($isActive ? "bg-blue-400 text-white" : "bg-blue-400 text-blue-200")}
  ${({ $isLoading }) => $isLoading && "opacity-90 pointer-events-none"}
`;
// transforms to <button className="text-lg mt-5 bg-blue-400 text-white opacity-90 pointer-events-none" />
```

### 前置输入道具 `$`

**我们在道具上加注 `$` 签名**这很重要 将动态道具与我们传递给组件的道具区分开来.

_这种模式还应避免与保留道具名称相冲突._

## 创建变量

通过将对象传递到 `variants` 密钥类似 [简历](https://cva.style/docs/getting-started/variants)。键应匹配 道具名称和值应该是返回字符串的函数。 你会的 也重新使用函数中的道具.

```tsx
interface AlertProps {
  $severity: "info" | "warning" | "error";
  $isActive?: boolean;
}
const Alert = cm.div.variants<AlertProps>({
  // optional
  base: (p) => `
    ${p.isActive ? "custom-active" : "custom-inactive"}
    p-4
    rounded-md
  `,
  // required
  variants: {
    $severity: {
      warning: "bg-yellow-100 text-yellow-800",
      info: (p) =>
        `bg-blue-100 text-blue-800 ${p.$isActive ? "shadow-lg" : ""}`,
      error: (p) =>
        `bg-red-100 text-red-800 ${p.$isActive ? "ring ring-red-500" : ""}`,
    },
  },
  // optional - used if no variant was found
  defaultVariant: {
    $severity: "info",
  },
});

export default () => <Alert $severity="info" $isActive />;
// outputs: <div className="custom-active p-4 rounded-md bg-blue-100 text-blue-800 shadow-lg" />
```

### Typescript:具有第二种类型参数的分离基道具和变体

从上面看,我们也通过了 `AlertProps` 以各种变体为主 类型。 如果你想从变体中分离出基本道具,你可以通过一个 转到第二个类型 `variants` 函数,只允许在 这些变体.

```tsx
interface AlertProps {
  $isActive?: boolean;
}
interface AlertVariants {
  $severity: "info" | "warning" | "error";
}
const Alert = cm.div.variants<AlertProps, AlertVariants>({
  base: `p-4 rounded-md`,
  variants: {
    // in here there are only the keys from AlertVariants available
    $severity: {
      // you can use the props from AlertProps here again
      warning: "bg-yellow-100 text-yellow-800",
      info: (p) =>
        `bg-blue-100 text-blue-800 ${p.$isActive ? "shadow-lg" : ""}`,
      error: (p) =>
        `bg-red-100 text-red-800 ${p.$isActive ? "ring ring-red-500" : ""}`,
    },
  },
  // optional - used if no variant was found
  defaultVariant: {
    $severity: "info",
  },
});
```

## 扩展

直接通过传递组件和标签名来扩展组件.

```tsx
import MyOtherComponent from "./MyOtherComponent"; // () => <button className="text-lg mt-5" />
import cm from "@classmatejs/react";

const Container = cm.extend(MyOtherComponent)`
  py-2
  px-5
  min-h-24
`;
// transforms to: <button className="text-lg mt-5 py-2 px-5 min-h-24" />
```

## 变形

变形使已经存在的同龄人成分成为另一个内在元素. 它保持原有的阶级逻辑 `$` 道具, 但类型脚本验证道具 对新元素.

```tsx
import cm from "@classmatejs/react";

const MyButton = cm.button<{ $toggleCta?: boolean }>`
  absolute
  min-w-300
  ${({ $toggleCta }) => ($toggleCta ? "bg-red-500" : "bg-blue-500")}
`;

export default () => <MyButton $_as="span" $toggleCta />;
// outputs: <span className="absolute min-w-300 bg-red-500" />
```

需要重用已转换组件时使用构建器 API, 或者添加更多 带有标记模板的类.

```tsx
const SpanButton = cm.transform(MyButton).span;
const TextSpanButton = cm.transform(MyButton).span`
  text-neutral
  tracking-wide
`;

export default () => <TextSpanButton $toggleCta />;
// outputs: <span className="absolute min-w-300 bg-red-500 text-neutral tracking-wide" />
```

变形也与变相和扩展的同学组件相配合.

```tsx
const VariantDiv = cm.div.variants<{ $size: "sm" | "md" }>({
  base: "absolute min-w-300",
  variants: {
    $size: {
      sm: "w-10 h-10",
      md: "w-20 h-20",
    },
  },
  defaultVariants: {
    $size: "md",
  },
});

const Main = cm.transform(VariantDiv).main`
  text-neutral
  tracking-wide
`;

export default () => <Main $size="sm" role="main" />;
// outputs: <main className="absolute min-w-300 w-10 h-10 text-neutral tracking-wide" role="main" />
```

`cm.transform` 只接受 v1 中的同学组件 。 常规反应 组件不能变换,因为同学不知道在哪里 课程随附.

## 添加 CSS 样式

您可以在模板文字字符串中使用 CSS 样式 `style` 函数. 此函数取一个带有 CSS 属性的对象并返回字符串 。 我们可以 使用之前的道具.

```tsx
// Base:
const StyledButton = cm.button<{ $isDisabled: boolean }>`
  text-blue
  ${(p) =>
  p.style({
    boxShadow: "0 0 5px rgba(0, 0, 0, 0.1)",
    cursor: p.$isDisabled ? "not-allowed" : "pointer",
  })}
`;
export default () => <StyledButton $isDisabled />;
// outputs: <button className="text-blue" style="box-shadow: 0 0 5px rgba(0, 0, 0, 0.1); cursor: not-allowed;" />
```

```tsx
// Extended:
const BaseButton = cm.button<{ $isActive?: boolean }>`
  ${(p) =>
  p.style({
    backgroundColor: p.$isActive ? "green" : "red",
  })}
`;
const ExtendedButton = cm.extend(BaseButton)<{ $isLoading?: boolean }>`
  ${(p) =>
  p.style({
    opacity: p.$isLoading ? 0.5 : 1,
    pointerEvents: p.$isLoading ? "none" : "auto",
  })}
`;
export default () => <ExtendedButton $isActive $isLoading />;
// outputs: <button className="bg-red" style="opacity: 0.5; pointer-events: none;" />
```

### 使用 React 组件 - `useClassmate`

当您需要在另一个 React 组件内创建同学组件时 (例如,当配置依赖于只运行时间值时),将 工厂 `useClassmate`。这可以记住结果,避免产生 每一个渲染器都有全新的组件.

```tsx
import cm, { useClassmate } from "@classmatejs/react";

const WorkoutDay = ({ status }: { status: "completed" | "pending" }) => {
  const StyledDay = useClassmate(
    () =>
      cm.div.variants({
        base: "rounded border p-4 text-sm",
        variants: {
          $status: {
            completed: "border-green-400 bg-green-50",
            pending: "border-yellow-400 bg-yellow-50",
          },
        },
      }),
    [status], // recompute when dependencies change
  );

  return <StyledDay $status={status}>Workout details</StyledDay>;
};
```

> 依赖数组的行为 `React.useMemo`把工厂的东西都递过来 如果您期望组件在这些值变化时更新, 则关闭 .

### 添加逻辑头

使用 `.logic()` 在您的课前运行任意 JavaScript 一次 名称或变体是计算出来的。 返回值是浅浮回 道具,这样你就能得到 `$` 道具, DOM 属性, 或者其他什么 组件需要没有额外的钩子.

```tsx
type DayStatus = "completed" | "pending"

interface WorkoutProps {
  workouts: unknown[]
  allResolved: boolean
  hasCompleted: boolean
  hasSkipped: boolean
  $status?: DayStatus
}

const WorkoutDay = cm.div
  .logic<WorkoutProps>((props) => {
    const status = deriveDayStatus(props)
    return {
      $status: status,
      ["data-status"]: status,
    }
  })
  .variants<WorkoutProps, { $status: DayStatus }>({
    base: "rounded border p-4",
    variants: {
      $status: {
        completed: "bg-green-50 border-green-400",
        pending: "bg-white border-slate-200",
      },
    },
  })

// Consumers only pass raw workout data – the logic header derives $status for you.
<WorkoutDay workouts={workouts} allResolved hasCompleted hasSkipped={false} />
```

> 返回值从 `.logic()` 因此以后的逻辑调用可以 引用早先的结果或推翻它们.

## 食谱 `cm.extend`

与 `cm.extend`中,您可以在任何基底 React 组件上再加新样式 甚至支持额外的道具。 这样就容易再使用 组件变化而不重复逻辑.

```tsx
import { ArrowBigDown } from "lucide-react";
import cm from "@classmatejs/react";

const StyledLucideArrow = cm.extend(ArrowBigDown)`
  md:-right-4.5
  right-1
  slide-in-r-20
`;

// ts: we can pass only props which are accessible on a `lucid-react` Component
export default () => <StyledLucideArrow stroke="3" />;
```

⚠️由于扩展第三方组件而出现问题,见: [扩展其他 lib 组件](https://npmcn.com/package/%40classmatejs/react/#readme-extending-other-lib-components--juggling-with-components-that-are-any)

现在,我们可以定义一个基础组件, 扩展它的附加样式和 类,并传递属性。 你可以把类型传给 `extend` 函数改为 获得自动补全和类型检查.

```tsx
import cm from "@classmatejs/react";

interface StyledSliderItemBaseProps {
  $active: boolean;
}
const StyledSliderItemBase = cm.button<StyledSliderItemBaseProps>`
  absolute
  h-full
  w-full
  left-0
  top-0
  ${(p) => (p.$active ? "animate-in fade-in" : "animate-out fade-out")}
`;

interface NewStyledSliderItemProps extends StyledSliderItemBaseProps {
  $secondBool: boolean;
}
const NewStyledSliderItemWithNewProps = cm.extend(
  StyledSliderItemBase,
)<NewStyledSliderItemProps>`
  rounded-lg
  text-lg
  ${(p) => (p.$active ? "bg-blue" : "bg-red")}
  ${(p) => (p.$secondBool ? "text-underline" : "some-class-here")}
`;

export default () => (
  <NewStyledSliderItemWithNewProps $active $secondBool={false} />
);
// outputs: <button className="absolute h-full w-full left-0 top-0 animate-in fade-in rounded-lg text-lg bg-blue" />
```

### 从变量扩展

```tsx
interface ButtonProps extends InputHTMLAttributes<HTMLInputElement> {
  $severity: "info" | "warning" | "error";
  $isActive?: boolean;
}

const Alert = cm.input.variants<ButtonProps>({
  base: "p-4",
  variants: {
    $severity: {
      info: (p) =>
        `bg-blue-100 text-blue-800 ${p.$isActive ? "shadow-lg" : ""}`,
    },
  },
});

const ExtendedButton = cm.extend(Alert)<{ $test: boolean }>`
  ${(p) => (p.$test ? "bg-green-100 text-green-800" : "")}
`;

export default () => <ExtendedButton $severity="info" $test />;
// outputs: <input className="p-4 bg-blue-100 text-blue-800 shadow-lg bg-green-100 text-green-800" />
```

### 道具的自动推断类型

通过通过组件,我们可以验证组件以接受与标签相关的标记 道具来. 如果你想依靠道具来获取特定元素,这个就有用了 没有 `$` 前缀.

```tsx
// if you pass rc component it's types are validated
const ExtendedButton = cm.extend(cm.button``)`
  some-class
  ${(p) => (p.type === "submit" ? "font-normal" : "font-bold")}
`;

// infers the type of the input element + add new props
const MyInput = ({ ...props }: HTMLAttributes<HTMLInputElement>) => (
  <input {...props} />
);
const StyledDiv = cm.extend(MyInput)<{ $trigger?: boolean }>`
  bg-white
  ${(p) => (p.$trigger ? "!border-error" : "")}
  ${(p) => (p.type === "submit" ? "font-normal" : "font-bold")}
`;
```

### 扩展其他 lib 组件 / `any` 作为输入

不幸的是,我们无法直接推断 类型的组件,如果它是 `any` 或打字松动。 但我们可以用中间步骤 将类型传递到 `extend` 函数.

```tsx
import { ComponentProps } from 'react'
import { MapContainer } from 'react-leaflet'
import { Field, FieldConfig } from 'formik'
import cm, { CmBaseComponent } from 'react-classmate'

// we need to cast the type to ComponentProps
type StyledMapContainerType = ComponentProps<typeof MapContainer>
const StyledMapContainer: CmBaseComponent<StyledMapContainerType> = cm.extend(MapContainer)`
  absolute
  h-full
  w-full
  text-white
  outline-0
`

export const Component = () => <StyledMapContainer bounds={...} />

// or with Formik

import { Field, FieldConfig } from 'formik'

type FieldComponentProps = ComponentProps<'input'> & FieldConfig
const FieldComponent = ({ ...props }: FieldComponentProps) => <Field {...props} />

const StyledField = cm.extend(FieldComponent)<{ $error: boolean }>`
  theme-form-field
  w-full
  ....
  ${p => (p.$error ? '!border-error' : '')}
`

export const Component = () => <StyledField placeholder="placeholder" as="select" name="name" $error />
```

## 常见JS

如果您使用CommonJS, 您可以这样导入库 :

```js
const cm = require("@classmatejs/react").default;

// or

const { default: cm } = require("@classmatejs/react");
```

## 尾风合并

反应类同位素使用 [后风相接](https://github.com/dcastil/tailwind-merge) 在罩子下合并类名. 最后一个班的名字总能赢 所以你 可以使用它来覆盖类.

## 即将

-   错误/ 排除出错: 由 ref.current( use Ref) 设置的类名将被覆盖 一旦组件重新投递
    -   在文档中至少需要一条小文章
-   `cm.raw()` 财务报告和审定财务报表 `cm.raw.variants()` 仅用于使用 `rc` 类名的语法 (输出为字符串)
-   备选案文 `cm.extend`
-   名称为 commonJS 的 lib 导入( 目前仅是) `.default`) -- -- 意味着我们需要 删除 ts 文件内命名的导出以不重复 IDE 导入 建议: -- -- 更改构建后脚本以删除命名的 Esm 导出
-   纳入更多的测试、侧重于安全部门改革和反应的基准
-   高级 IDE 集成
    -   在徘徊时显示生成的默认类
    -   从已使用的 libs 执行自动补全和工具提示

## 灵感

-   [尾风型组件](https://github.com/MathiasGilson/tailwind-styled-component)
-   [简历](https://github.com/joe-bell/cva)
-   [双相宏](https://github.com/ben-rogerson/twin.macro)

## 常见问题

### @classmatejs/react 是什么？

一个反应工具可以分出类名逻辑,创建变体并管理样式\.注意：该包已被作者标记为弃用——Package no longer supported\. Contact Support at https://www\.npmjs\.com/support for more info\.

### 如何安装 @classmatejs/react？

在项目目录运行 npm install @classmatejs/react，或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖：react（\>=16\.8\.0）。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖，Yarn 需要手动安装。

### @classmatejs/react 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @classmatejs/react 支持 ESM 还是 CommonJS？

同时提供 ES Module 与 CommonJS 入口，import 和 require\(\) 都可以使用，打包工具会自动选择合适的版本。

### @classmatejs/react 可以商用吗？

@classmatejs/react 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @classmatejs/react 的下载量有多少？

根据 npm 官方下载统计，@classmatejs/react 在 2026/10/10 – 2026/11/08 这 30 天内被下载 23,257 次，日均约 775 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @classmatejs/react 还在维护吗？

最新版本 0\.3\.0 发布于 2026/06/28（4 个月前）；至今共发布 10 个版本，其中过去 12 个月发布了 10 个；首次发布于 2025/11/25。作者已将其标记为弃用，新项目建议寻找替代方案。

