😎

日本発のReact UIコンポーネントライブラリ 『Yamada UI』

2023/12/24に公開
3

https://twitter.com/hirotomoyamada/status/1738868143949508785?s=61&t=auiH602hdgzxzwjE6w7HLA

初めまして、プログラマーを始めて3年目の山田です。今回、日本発のReact UIコンポーネントライブラリYamada UIをリリースしたので、その素晴らしい機能の数々を紹介していこうと思います。

ちなみに、Yamada UIYamadaは山田が名付けたわけではありません。気になる方は、山田に聞いてください。

Yamada UIとは

一言で言うならば、『すべてのUIコンポーネントライブラリを超えた(つもり)』のUIコンポーネントライブラリです。

現在のUIコンポーネントライブラリで代表的なものと言えば、Material UIChakra UIであり、フロントエンドエンジニアであれば、誰でも知っている知名度だと思います。

しかし、現在主流となっているUIコンポーネントライブラリは数年前に開発されたものであり、色々な面(カラーモード・アニメーション・CSSプロパティ・型安全など)において首が回らない状況になっているのは、ご存知の通りでしょう。

Yamada UIは、Material UI, Chakra UIMantineの良さを継承しつつ、1から再設計することで、問題を解消・改善しています。

なにが違うの?

今回は、Yamada UIの良さを感じてもらうため、他のUIコンポーネントライブラリと比較しています。ダメ出しみたいな感じになっていますが、ちゃんとリスペクトしています(はーと)。

CSSプロパティの強化

Yamada UIは、Chakra UIStyle Propsに深く感銘を受けました。その使いやすさをそのままに、Chakra UIより200以上のプロパティを追加し、さらに機能(アニメーションやCSS変数)を強化しています。

Yamada UI - Style Props

ダークモードの最適化

Material UIは、ダークモード時にリロードするとフラッシュすることがあります。これは、ダークモードが当たり前になっている現在では採用したくない方も多いことでしょう。また、Chakra UI, MantineNext UIは、オペレーションシステム(OS)のモードを計算し自動的にモードを切り替えるのに弱いのが印象です。Yamada UIは、ローカルストレージやクッキーを活用し、上記のすべてを改善しました。

またダークモードのスタイリングは、カスタムフックなどで設定するのが一般的ですが、Yamada UIStyle Propsに配列を渡すことでダークモードに対応します。この新しいアプローチで、記述量は従来のUIコンポーネントライブラリより、かなり削減できます。

Chakra UI
const bg = useColorModeValue('red.500', 'red.200')

return (
  <Box bg={bg} />
)
Yamada UI
return (
  <Box bg={['red.500', 'red.200']} />
)

Yamada UI - カラーモード

アニメーションの強化

UIコンポーネントライブラリは、『アニメーションに弱い』という印象を持つ方も多いのではないでしょうか。当然ですよね、UIですから。しかし、アニメーションつけたいですよね?そうですよね。

大丈夫です。Yamada UIは、アニメーションにとて強です。

アニメーションに特化したコンポーネントのMotionやCSSのkeyframesのように記述できるuseAnimationなど、多くのユーティリティを提供しています。

useAnimation
const animation = useAnimation({
  keyframes: {
    "0%": {
      bg: "red.500",
    },
    "20%": {
      bg: "green.500",
    },
    "40%": {
      bg: "purple.500",
    },
    "60%": {
      bg: "yellow.500",
    },
    "80%": {
      bg: "blue.500",
    },
    "100%": {
      bg: "red.500",
    },
  },
  duration: "10s",
  iterationCount: "infinite",
  timingFunction: "linear",
})

return <Box w="full" h="xs" animation={animation} />
useAnimation (複数)
const animation = useAnimation([
  {
    keyframes: {
      "0%": {
        bg: "red.500",
      },
      "20%": {
        bg: "green.500",
      },
      "40%": {
        bg: "purple.500",
      },
      "60%": {
        bg: "yellow.500",
      },
      "80%": {
        bg: "blue.500",
      },
      "100%": {
        bg: "red.500",
      },
    },
    duration: "10s",
    iterationCount: "infinite",
    timingFunction: "linear",
  },
  {
    keyframes: {
      "0%": {
        h: "xs",
      },
      "50%": {
        h: "md",
      },
      "100%": {
        h: "xs",
      },
    },
    duration: "10s",
    iterationCount: "infinite",
    timingFunction: "linear",
  },
  {
    keyframes: {
      "0%": {
        w: "full",
      },
      "50%": {
        w: "50%",
      },
      "100%": {
        w: "full",
      },
    },
    duration: "10s",
    iterationCount: "infinite",
    timingFunction: "linear",
  },
])

return (
  <Box w="full" h="xs" animation={animation} />
)

当然、レスポンシブ・ダークモードにも対応しています。

// レスポンシブ
<Box w="full" h="xs" animation={{ base: desktopAnimation, md: tabletAnimation }} />

// カラーモード
<Box w="full" h="xs" animation={[lightAnimation, darkAnimation]} />
useDynamicAnimation
const [animation, setAnimation] = useDynamicAnimation({
  moveLeft: {
    keyframes: {
      "0%": {
        transform: "translateX(400%)",
      },
      "100%": {
        transform: "translateX(0%)",
      },
    },
    duration: "slower",
    fillMode: "forwards",
    timingFunction: "ease-in-out",
  },
  moveRight: {
    keyframes: {
      "0%": {
        transform: "translateX(0%)",
      },
      "100%": {
        transform: "translateX(400%)",
      },
    },
    duration: "slower",
    fillMode: "forwards",
    timingFunction: "ease-in-out",
  },
})

return (
  <VStack alignItems="flex-start">
    <Button
      onClick={() =>
        setAnimation((prev) =>
          prev === "moveRight" ? "moveLeft" : "moveRight",
        )
      }
    >
      Click me!
    </Button>

    <Box bg="primary" p="md" rounded="md" color="white" animation={animation}>
      Box
    </Box>
  </VStack>
)

Motion

<Motion
  animate={{
    scale: [1, 2, 2, 1, 1],
    rotate: [0, 0, 180, 180, 0],
    borderRadius: ["0%", "0%", "50%", "50%", "0%"],
  }}
  transition={{
    duration: 2,
    ease: "easeInOut",
    times: [0, 0.2, 0.5, 0.8, 1],
    repeat: Infinity,
    repeatDelay: 1,
  }}
  w="3xs"
  h="3xs"
  bg="primary"
/>

他にも、whileTaponDrag、スクロールアニメーション、テーマからアニメーションを参照をサポートしています。

Yamada UI - アニメーション

型安全の強化

TypeScriptは10年ほど前から存在していましたが、広く使われるようになったのはつい最近のことです。他のUIコンポーネントライブラリの多くは、当初JavaScriptで開発していました(現在は、ほとんどTypeScript)。そのため、内部的にanyが多発していたり、propsの型が間違っていることがしばしばあります。

Yamada UIは、1からTypeScriptで開発しており、『型にうるさい山田』が監督していますので

『安心・安全』です。

柔軟な記述

UIコンポーネントライブラリには、それぞれ特徴があると思います。

  • 記述量が少ないが柔軟性がない Material UI, Mantineなど
  • 柔軟性はあるが記述量が多い Chakra UIなど

これは、個人の感想なので人によって違うと思いますが、コミッターをしてて感じたことです。

山田は悩みました。どうにかして両方を活かせないか。

辿り着いた答えは、これです。

<Dialog
  isOpen={isOpen}
  onClose={onClose}
  header="孫悟空"
  cancel="わけない"
  onCancel={onClose}
  success="わける"
  onSuccess={onClose}
>
  だ…大地よ海よ そして生きているすべての みんな…
  このオラにほんのちょっとずつだけ元気をわけてくれ…!!!
</Dialog>
<Dialog isOpen={isOpen} onClose={onClose}>
  <DialogHeader>孫悟空</DialogHeader>

  <DialogBody>
    だ…大地よ海よ そして生きているすべての みんな…
    このオラにほんのちょっとずつだけ元気をわけてくれ…!!!
  </DialogBody>

  <DialogFooter>
    <Button variant="ghost" onClick={onClose}>
      わけない
    </Button>
    
    <Button colorScheme="primary" onClick={onClose}>
      わける
    </Button>
  </DialogFooter>
</Dialog>

両方の書き方は、同じものが表示されます。

コンポーネントを呼び出さなければ、内部のコンポーネントを使います。当然、無効化も可能です。スタイリングをする必要があるとき・ないときで柔軟に記述することが可能です。

Yamada UIのコンポーネントの多くは、このように記述量も抑えて、柔軟性も担保する設計になっています。

テーマの切り替え

テーマを切り替えることは、現在のアプリケーションでは必須と言っても過言ではありません。しかし、多くのUIコンポーネントライブラリは実装していないのが現状です。Material UIは、テーマの切り替えが実装されていますが、ダークモードと同様にフラッシュすることがあります。

Yamada UIは、好きなテーマをユーザーが選択でき、最高のエクスペリエンスを提供します。

テーマの切り替えは、Yamada UIのドキュメントサイトで実装しているので体験してみてください。

Yamada UI - テーマを切り替える

ローディング・通知の標準化

アプリケーションには、通信が必須です。当然、ユーザーに通信中かどうか、結果がどうか、を認識してもらう必要があります。他のUIコンポーネントライブラリは、オプションというカタチで付随していますが、Yamada UIは、標準として搭載しています。

Yamada UI - ローディング
Yamada UI - 通知

コンポーネントの充実さ

コンポーネントは80以上あり、カスタムフックは20以上を提供しています。

リリース後も、多くのコンポーネントを提供します。予定では、年内に3つ以上追加します。

Yamada UI - コンポーネント

パッケージの細分化

Yamada UIは、プロジェクトの規模やケースに応じて、さまざまなコンポーネント・フック・テーマ・ユーティリティが細分化されています。

パフォーマンスを向上させたい、スタイルシステムだけ使いたい、テーマ運用だけ使いたい、など多くのニーズに応えています。

Yamada UI - はじめる

山田が作った

Yamada UIは、日本人の山田によって作られました。当然、山田は日本語が喋れます。コミュニティもドキュメントサイトも日本語に対応しています。

そして、今あるUIコンポーネントライブラリは、それを取り巻くツールがあまりありません。

Yamada UIは、テーマをリアルタイムでカスタマイズしてチームで共有できるYamada ThemeやテーマのカラーをよりよくカスタマイズできるYamada Colorsなど、現在設計中です。

今後のスケジュールは、こんな感じです。

2024年春頃、Yamada Colorsをリリース。App Routerに完全対応(現在も"use client"なしで使用できます)。
2024年中旬、Yamada Theme, Yamada Componentsをリリース。

他にもYamasaurus(仮), Yamadatron(仮)もあります。

そう、Yamada UIならね。

すべてを語り切れませんでしたが、気になる方は、ドキュメントサイトをご覧ください。まぁ、ドキュメントサイトもすべて語ってないんですがね。

ぜひ、多くの日本人に知ってもらいたいです!もし、少し気に入ってもらえたら『いいね』と『リツイート』をお願いしたいです😎

https://twitter.com/hirotomoyamada/status/1738868143949508785?s=61&t=auiH602hdgzxzwjE6w7HLA

https://github.com/hirotomoyamada

最後に、このYamada UIをプロジェクトやサービスで試験的に使っていただき、フィードバックまでもくれた数々のチームの方々、そしてYamada UIに貢献してくださった数々のエンジニアに深く感謝します。

Discussion