アイコンコンポーネントを作る時、propsで色に関する属性を取得してclassNameに追加したかった。
アイコンはSVGで構成されており、fillとstrokeの値を直接指定するのではなく、classNameにTailwind CSSのオートコンプリートを利用して色を指定したかった。
例えば、次のようなコードを書きたいと思いました。
interface IconProps { fill: string
fill: string;
stroke: string;
}
const Icon = ({fill, stroke}: IconProps) => { {
<svg className={`${fill} ${stroke}`} /> }
}
tailwindのオートコンプリートの力を借りるためにはfillと
strokeの
タイプにstringの
代わりに他のタイプを入れる必要があります。 つまり、tailwindに設定されているcolor classesの名前を取得する必要があります。
タイプを抽出する
まず、tailwindの基本的なcolor情報を取得します。
import defaultColors from "tailwindcss/colors";
export type DefaultColors = keyof typeof defaultColors;
const color: DefaultColors = 'blue'
しかし、カラーキーだけが自動補完されるだけで、その後ろの属性は提供されません。(blueは
できますが、blue-500などの
自動補完はされません)
次のステップとして、tailwindのconfig全体を取得してみましょう。
import resolveConfig from "tailwindcss/resolveConfig";
import tailwindConfig from "web/tailwind.config.ts"; // tailwind 設定ファイル
const fullConfig = resolveConfig(tailwindConfig);
すると、fullConfig
では次のような情報を取得することができます。
上記の情報を組み合わせてColorShadeという
新しいタイプを作成してみましょう。
type ColorShade<T extends DefaultColors> = keyof ColorConfig[T] extends
| string
| number
? keyof ColorConfig[T]
: never;
const shade: ColorShade<'blue'> = '500'
これで色の後ろの属性も取得できるようになりました。
これらを組み合わせて、色と明るさを組み合わせた名前を抽出することができるようになりました。
type TailwindColorClass = { {...
[P in DefaultColors]:ColorShade<P> extends never ? P :`${P}-${ColorShade<P>}`;
}[DefaultColors];
適用
次は、私が欲しかった機能であるfillにはfillに入れるclassName、strokeにはstrokeだけ入れるclassNameを作りましょう。
interface IconProps {
fill:`fill-${TailwindColorClass}`;
stroke:`storke-${TailwindColorClass}`;
}
カスタムカラー適用
上のコードの問題点はtailwindの基本的な色だけ取ってきて、ユーザーが定義した色は取れないです。
カスタムカラーの分離
まず、カスタムで適用したcolorsを一つの変数で分離してみましょう。
const color = { .
...formalColors、
...keyColors、
...accentColors、
...grayColor、
...theme.colors、
}
そして上で使ってたDefaultColorsの
代わりに下記のタイプを作りましょう。
type CustomColors = typeof color;
type DefaultColors = typeof defaultColors;
export type Colors = CustomColors & DefaultColors;
最終コード
tailwin.config.ts
type CustomColors = typeof color;
export type DefaultColors = typeof defaultColors;
export type Colors = CustomColors & DefaultColors;
Component.tsx
const fullConfig = resolveConfig(tailwindConfig);
const colorTheme = fullConfig.theme.colors as Colors;
type ColorConfig = typeof colorTheme;
type ColorKeys = keyof Colors;
type ColorShade<T extends ColorKeys> = keyof ColorConfig[T] extends
| string
| number
keyof ColorConfig[T] ?
: never;
type TailwindColorClass = { {...
[P in ColorKeys]:ColorShade<P> never extends ? P :`${P}-${ColorShade<P>}`;
}[ColorKeys];
interface IconProps {
塗りつぶしを行います:`fill-${TailwindColorClass}`;
ストローク:`storke-${TailwindColorClass}`;
}