mcpField
M
mantine-custom-components

mantine-custom-components

github.com/mantinedev開発643.7k 回インストール3 週間前に更新
リポジトリ

mantine-custom-components について

Mantine 9.xでカスタムコンポーネントを作る開発者向けのスキルです。コンポーネント構造、スタイル、バリアント、テーマ連携を扱い、適切なファクトリーパターンの選択も説明します。

主な機能

  1. 01Mantine 9.xのコンポーネントテンプレート
  2. 02Styles APIのプロパティとクラス
  3. 03バリアント、サイズ、CSS変数
  4. 04テーマの色とサイズのヘルパー
  5. 05ファクトリーパターンと型
  6. 06テーマ拡張とプロパティのプリセット

活用シーン

  1. 01カスタムMantineコンポーネントの作成
  2. 02バリアントとサイズスタイルの追加
  3. 03コンポーネントの既定値のテーマ連携
  4. 04ポリモーフィックまたはジェネリックなプロパティ向けファクトリー選択

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/mantinedev/skills --skill mantine-custom-components

インストール後、Claude Code で/mantine-custom-componentsを入力して読み込まれたか確認します。

同梱ファイルreferences/api.mdreferences/patterns.md

詳細

Mantine カスタムコンポーネントのスキル

Mantine 9.x 向けに作成されています。

コンポーネントのテンプレート

import {
  Box, BoxProps, createVarsResolver, ElementProps,
  factory, Factory, getRadius, MantineRadius,
  StylesApiProps, useProps, useStyles,
} from '@mantine/core';
import classes from './MyComponent.module.css';

export type MyComponentStylesNames = 'root' | 'inner';
export type MyComponentVariant = 'filled' | 'outline';
export type MyComponentCssVariables = { root: '--my-radius' };

export interface MyComponentProps
  extends BoxProps, StylesApiProps<MyComponentFactory>, ElementProps<'div'> {
  radius?: MantineRadius;
}

export type MyComponentFactory = Factory<{
  props: MyComponentProps;
  ref: HTMLDivElement;
  stylesNames: MyComponentStylesNames;
  vars: MyComponentCssVariables;
  variant: MyComponentVariant;
}>;

const defaultProps = {} satisfies Partial<MyComponentProps>;

const varsResolver = createVarsResolver<MyComponentFactory>((_theme, { radius }) => ({
  // undefined leaves the variable unset, so the CSS fallback (theme default radius) applies
  root: { '--my-radius': radius === undefined ? undefined : getRadius(radius) },
}));

export const MyComponent = factory<MyComponentFactory>((_props) => {
  const props = useProps('MyComponent', defaultProps, _props);
  const { classNames, className, style, styles, unstyled, vars, attributes, radius, ...others } = props;

  const getStyles = useStyles<MyComponentFactory>({
    name: 'MyComponent', classes, props,
    className, style, classNames, styles, unstyled, vars, attributes, varsResolver,
  });

  return <Box {...getStyles('root')} {...others} />;
});

MyComponent.displayName = 'MyComponent';
MyComponent.classes = classes;
MyComponent.varsResolver = varsResolver;
/* MyComponent.module.css */
.root {
  border-radius: var(--my-radius, var(--mantine-radius-default));
}

React 19 では ref は通常のプロップです。props に渡され、...others を通じてルート要素に届きます。

追加のコードなしで利用できるもの:

  • getStyles('selector') でレンダリングされるすべての要素に、静的クラス mantine-MyComponent-selector が付与されます。
  • classNames、styles、vars、attributes プロップと、テーマ内の MyComponent.extend() における同じキー。
  • unstyled は CSS モジュールのクラスを削除します。静的クラスとルートの CSS 変数は残ります。
  • MyComponent.extend() と MyComponent.withProps() の静的関数。withProps は実行時にプロップをプリセットしますが、型は変更しません。必須プロップは TypeScript では引き続き必須となるため、プリセットするプロップは任意にしてください。

バリアントとサイズ

variant と size を Box に渡すと、CSS でスタイルを指定するための data-variant 属性と data-size 属性が設定されます。 variant を getStyles に渡すと、CSS モジュールに定義されている場合は root--{variant} クラスも適用されます。

const { variant, size, ...others } = props;

<Box variant={variant} size={size} {...getStyles('root', { variant })} {...others} />
.root {
  &[data-variant='outline'] { border: 1px solid var(--my-color); }
  &[data-size='lg'] { height: 50px; }
}

1 つの size プロップでサイズを指定する場合:トークン値を CSS で定義し、getSize で選択します。size に渡された数値または任意の CSS 値はそのまま使用されます(getSize(60, 'x') は calc(3.75rem * var(--mantine-scale)) を返します)。

root: { '--card-padding': getSize(size, 'card-padding'), '--card-fz': getFontSize(size) },
.root {
  --card-padding-sm: 12px;
  --card-padding-md: 16px;
  --card-padding-lg: 24px;

  padding: var(--card-padding, var(--card-padding-md));
}

テーマに連動する色は、vars リゾルバーで theme.variantColorResolver({ color: color || theme.primaryColor, theme, variant: variant || 'filled', autoContrast }) を使って解決します。これは background、hover、color を色として、border を完全な border の省略記法の値(1px solid transparent)として返します。filled、light、outline、subtle、transparent、white、default の各バリアントに対応しています。autoContrast: undefined の場合は theme.autoContrast が使われます。単一の色には getThemeColor(color, theme) を使います。'blue'、'teal.7'、CSS の色を受け付けます。

.root {
  background-color: var(--my-bg);
  color: var(--my-color);
  border: var(--my-bd); /* the whole shorthand, not border-color */
}

リゾルバーはテーマから取得されるため、アプリではコンポーネントに手を加えることなく、独自のバリアント(variant="danger")を追加したり、既存のバリアントの色を変更したりできます。プロップのインターフェースで variant を再宣言しないでください。StylesApiProps ですでに、独自のバリアントと任意の文字列が型付けされています。

Factory のバリアント — どれを使うか

シナリオFactory 関数型
標準コンポーネントfactory()Factory<{}>
component プロップに対応(ポリモーフィック)polymorphicFactory()PolymorphicFactory<{}> — defaultComponent と defaultRef を追加
ジェネリックに応じてプロップが変化する(例:multiple)genericFactory()Factory<{ signature: ... }>

polymorphicFactory は必要な場合に限って使用してください。TypeScript の負荷が増え、IDE のオートコンプリートが遅くなります。 すべての Factory コンポーネントは、component の代わりに renderRoot={(props) => <a {...props} />} も受け付けます。

Factory の型フィールド

Factory<{
  props: MyComponentProps;       // required
  ref: HTMLDivElement;           // element type for the forwarded ref
  stylesNames: 'root' | 'inner'; // union of Styles API selectors
  vars: { root: '--my-var' };    // CSS variable map per selector
  variant: 'filled' | 'outline'; // accepted variant strings
  staticComponents: {            // sub-components (compound pattern)
    Item: typeof MyComponentItem;
  };
  compound: true;                // only for sub-components; disables theme classNames/styles/vars
  ctx: { stepsCount: number };   // only if needed; passed to classNames/styles/vars functions as third arg
  signature?: (...) => JSX.Element; // only for genericFactory
}>

テーマとの統合

ユーザーとテーマは、Component.extend() を通じてデフォルトを上書きできます。

const theme = createTheme({
  components: {
    MyComponent: MyComponent.extend({
      defaultProps: { radius: 'xl' },
      classNames: { root: 'my-root' },
      styles: { root: { color: 'red' } },
      vars: (_theme, props) => ({ root: { '--my-radius': getRadius(props.radius) } }),
    }),
  },
});

theme.components では、サブコンポーネントはドットを付けずに登録します。MyCardSection: MyCard.Section.extend({ defaultProps }) のようにします。

参考資料

コードを書く前に、作業内容に該当する箇所を読んでください。

  • references/patterns.md — 完全な実例が記載されています。サブコンポーネント(Card.Section)を持つコンポーネントについては「Compound component with context」、既存の Mantine の入力コンポーネントやコンポーネントを内部でレンダリングし、classNames / styles を転送する必要があるコンポーネントについては「Wrapping a Mantine component」、共通のベースを持つコンポーネント群については「Components that share theme configuration」、インラインスタイルを持つ forwardRef コンポーネントを移行する場合は「Converting an existing component」、component プロパティについては「Polymorphic component」、型パラメーターに依存するプロパティについては「Generic component」、extend と withProps については「Theme integration」を読んでください。
  • references/api.md — 上記のテンプレート以外のコンポーネントでは、このファイルを読んでください。getStyles のオプション(focusable)、mod プロパティ、テーマヘルパーの戻り値、MantineThemeProvider とテーマ関数が受け取る値について記載されているのはここだけです。すべての関数と型を確認してください。factory のバリエーション、useProps、useStyles と getStyles のオプション、createVarsResolver、createSafeContext、StylesApiProps、CompoundStylesApiProps、BoxProps(mod を含む)、ElementProps、テーマヘルパー(getSize、getRadius、getThemeColor など)が含まれます。

調べ方

参考資料に必要な情報がない場合は、推測しないでください。

  • Mantine MCP サーバー(@mantine/mcp-server)が接続されている場合は、search_docs、get_item_doc、get_api を使用してください。
  • それ以外の場合は、https://mantine.dev/llms.txt を取得し、Styles API、variants and sizes、custom components の各ページを開いてください。

コメント