🍳

【Panda CSS】Atomic Recipe記法を使ってVueコンポーネントを実装する

2023/10/23に公開

はじめに

前回の記事ではcss()を利用しましたが例的にはcva()でもいけそうでした。前回記事は下記によりご覧ください。

https://zenn.dev/gangannikki/articles/2fc54416899fcb

本記事では Atomic Recipe 記法を利用して Vue コンポーネントを実装してみます。

Panda CSS の Atomic Recipe とは

Atomic Recipe はClass Variance Authorityにインスパイアされた実装方法です。

https://panda-css.com/docs/concepts/recipes#atomic-recipe-or-cva

実際に使ってみる

共通スキーマ

/schemas/stickyNote.ts
import { z } from "zod";

export const stickyNoteSchema = z.enum(["alert", "warning", "success", "info"]);

export const dummyStickyNotes: z.infer<typeof stickyNoteSchema>[] = [
  "alert",
  "warning",
  "success",
  "info",
];

コンポーネント(/components)

/components/stickyNote.vue
<script setup lang="ts">
import { cva } from "styled-system/css";
import { stickyNoteSchema } from "@/schemas/stickyNote";

const { color } = defineProps<{
  color: z.infer<typeof stickyNoteSchema>;
}>();

const stickyNoteRecipe = cva({
  /** 共通スタイル */
  base: {
    width: "200px",
    height: "200px",
    textDecoration: "none",
    padding: "0.5rem",
    boxShadow: "5px 5px 5px rgba(0, 0, 0, 0.22)",
    zIndex: 5,
  },
  /** 可変させるスタイル */
  variants: {
    color: {
      alert: {
        color: "red.500",
        bgColor: "red.100",
      },
      warning: {
        color: "yellow.500",
        bgColor: "yellow.100",
      },
      success: {
        color: "green.500",
        bgColor: "green.100",
      },
      info: {
        color: "sky.500",
        bgColor: "sky.100",
      },
    },
  },
});
</script>

<template>
  <div :class="stickyNoteRecipe({ color })">
    <slot></slot>
  </div>
</template>

呼び出し元(/pages)

/pages/index.vue
<script setup lang="ts">
import { grid } from "styled-system/patterns/grid";
import { stickyNoteSchema, dummyStickyNotes } from "@/schemas/stickyNote";
</script>

<template>
  <div :class="grid({ columns: '4', gap: '1' })">
    <!-- NOTE: Nuxt3のAuto-imports利用 -->
    <StickyNote v-for="sn in dummyStickyNotes" :key="sn" :color="sn">
      This is {{ sn }} sticky note.
    </StickyNote>
  </div>
</template>

表示結果

npm run devコマンドを実行し表示した結果は以下の通りです。grid()もきちんと効いています。

おわりに

今回はcva()(defineRecipe)を利用しましたが、より複雑になる場合はsva()(defineSlotRecipe)を利用した方が便利です。

https://panda-css.com/docs/concepts/slot-recipes

Panda CSS は今回紹介したcva()、前回紹介したcss()、今回紹介していないsva()など、様々な形で実装できます。
実装者に合った形で実装できるのはありがたい限りです。

Vue・Nuxt 情報が集まる広場 / Plaza for Vue・Nuxt.

Discussion