Agent Skills by ALSEL
Anthropic Claudeソフトウェア開発⭐ リポ 0品質スコア 50/100

tamagui

WebとネイティブアプリをまたいでUIを構築できるユニバーサルReactフレームワーク「Tamagui」に関するスキルです。`styled()`によるスタイル付きコンポーネントの作成、デザイントークンやテーマの設定、`XStack`/`YStack`などのUIコンポーネントの利用、アニメーションの実装など、Tamaguiを用いたクロスプラットフォーム開発全般で活用できます。`@tamagui/*`のimportや`useTheme`、`createStyledContext`、`variants`などをコードで使用する際にトリガーされます。

description の原文を見る

| Universal React UI framework for web and native. Use when building cross-platform apps with Tamagui, creating styled components with `styled()`, configuring design tokens/themes, using Tamagui UI components, or working with animations. Triggers: "tamagui", "styled()", "$token", "XStack/YStack", "useTheme", "@tamagui/*" imports, "createStyledContext", "variants".

SKILL.md 本文

Tamagui スキル

最適化コンパイラを備えた、ウェブとネイティブ向けのユニバーサル React UI フレームワーク。

プロジェクト固有の設定を取得する

Tamagui コードを書く前に、プロジェクトの実際の設定を取得してください:

npx tamagui generate-prompt

このコマンドは tamagui-prompt.md を出力します。以下の項目が含まれます:

  • デザイントークン (space, size, radius, color, zIndex)
  • テーマ名と階層
  • 利用可能なコンポーネント
  • メディアクエリのブレークポイント
  • ショートハンドプロパティ
  • フォントファミリー

デフォルト値を推測するのではなく、トークン/テーマ/メディアクエリ名について必ずこのファイルを参照してください


コアコンセプト

styled() 関数

既存のコンポーネントを拡張して新しいコンポーネントを作成します:

import { View, Text, styled } from '@tamagui/core'

const Card = styled(View, {
  padding: '$4',           // トークンは $ で使用
  backgroundColor: '$background',
  borderRadius: '$4',

  variants: {
    size: {
      small: { padding: '$2' },
      large: { padding: '$6' },
    },
    elevated: {
      true: {
        shadowColor: '$shadowColor',
        shadowRadius: 10,
      },
    },
  } as const,  // 型推論に必須

  defaultVariants: {
    size: 'small',
  },
})

// 使用方法
<Card size="large" elevated />

重要なルール:

  • variants オブジェクトには必ず as const を使用
  • トークンは $ プレフィックスを使用: $4, $background, $color11
  • プロップの順序が重要 - 後のプロップが前のプロップをオーバーライド
  • 後で定義されたバリアントが前に定義されたバリアントをオーバーライド

Stack コンポーネント

import { XStack, YStack, ZStack } from 'tamagui'

// XStack = flexDirection: 'row'
// YStack = flexDirection: 'column'
// ZStack = position: 'relative' with absolute children

<YStack gap="$4" padding="$4">
  <XStack justifyContent="space-between" alignItems="center">
    <Text>Label</Text>
    <Button>Action</Button>
  </XStack>
</YStack>

テーマ

テーマは階層的にネストして組み合わせます:

import { Theme } from 'tamagui'

// ベーステーマ
<Theme name="dark">
  {/* サブテーマ */}
  <Theme name="blue">
    {/* dark_blue テーマを使用 */}
    <Button>Blue button on dark</Button>
  </Theme>
</Theme>

// テーマ値にアクセス
const theme = useTheme()
console.log(theme.background.val)  // 実際のカラー値
console.log(theme.color11.val)     // 高コントラストテキスト

12段階のカラースケール規約:

  • $color1-4: 背景 (微妙から強調)
  • $color5-6: ボーダー、セパレータ
  • $color7-8: ホバー/アクティブ状態
  • $color9-10: 単色背景
  • $color11-12: テキスト (低から高コントラスト)

レスポンシブスタイル

メディアクエリプロップを使用します (tamagui-prompt.md で実際のブレークポイント名を確認):

<YStack
  padding="$4"
  $gtSm={{ padding: '$6' }}   // 設定ファイルで実際の名前を確認
  $gtMd={{ padding: '$8' }}
  flexDirection="column"
  $gtLg={{ flexDirection: 'row' }}
/>

// またはフックで
const media = useMedia()
if (media.gtMd) {
  // 中サイズ以上の画面で描画
}

アニメーション

import { AnimatePresence } from 'tamagui'

<AnimatePresence>
  {show && (
    <YStack
      key="modal"  // 終了アニメーションに必須のキー
      animation="quick"
      enterStyle={{ opacity: 0, y: -20 }}
      exitStyle={{ opacity: 0, y: 20 }}
      opacity={1}
      y={0}
    />
  )}
</AnimatePresence>

アニメーションドライバ:

  • @tamagui/animations-css - ウェブのみ、CSS トランジション
  • @tamagui/animations-react-native - ネイティブ Animated API
  • @tamagui/animations-reanimated - ネイティブの最高のパフォーマンス
  • @tamagui/animations-motion - スプリング物理演算

CSS ドライバはイージング文字列を使用し、他のドライバはスプリング物理演算をサポートします。


複合コンポーネント

状態を共有するコンポーネントには createStyledContext を使用:

import { createStyledContext, styled, View, Text } from '@tamagui/core'
import { withStaticProperties } from '@tamagui/helpers'

const CardContext = createStyledContext({ size: 'medium' as 'small' | 'medium' | 'large' })

const CardFrame = styled(View, {
  context: CardContext,
  padding: '$4',
  backgroundColor: '$background',

  variants: {
    size: {
      small: { padding: '$2' },
      medium: { padding: '$4' },
      large: { padding: '$6' },
    },
  } as const,
})

const CardTitle = styled(Text, {
  context: CardContext,  // 親から size を継承
  fontWeight: 'bold',

  variants: {
    size: {
      small: { fontSize: '$4' },
      medium: { fontSize: '$5' },
      large: { fontSize: '$6' },
    },
  } as const,
})

export const Card = withStaticProperties(CardFrame, {
  Title: CardTitle,
})

// 使用方法 - size が子にカスケード
<Card size="large">
  <Card.Title>Large Title</Card.Title>
</Card>

よくあるパターン

Adapt を使った Dialog (モバイルでは Sheet)

import { Dialog, Sheet, Adapt, Button } from 'tamagui'

<Dialog>
  <Dialog.Trigger asChild>
    <Button>Open</Button>
  </Dialog.Trigger>

  <Adapt when="sm" platform="touch">
    <Sheet modal dismissOnSnapToBottom>
      <Sheet.Frame padding="$4">
        <Adapt.Contents />
      </Sheet.Frame>
      <Sheet.Overlay />
    </Sheet>
  </Adapt>

  <Dialog.Portal>
    <Dialog.Overlay
      key="overlay"
      animation="quick"
      opacity={0.5}
      enterStyle={{ opacity: 0 }}
      exitStyle={{ opacity: 0 }}
    />
    <Dialog.Content
      key="content"
      animation="quick"
      enterStyle={{ opacity: 0, scale: 0.95 }}
      exitStyle={{ opacity: 0, scale: 0.95 }}
    >
      <Dialog.Title>Title</Dialog.Title>
      <Dialog.Description>Description</Dialog.Description>
      <Dialog.Close asChild>
        <Button>Close</Button>
      </Dialog.Close>
    </Dialog.Content>
  </Dialog.Portal>
</Dialog>

Input/Label を使ったフォーム

import { Input, Label, YStack, XStack, Button } from 'tamagui'

<YStack gap="$4" padding="$4">
  <YStack gap="$2">
    <Label htmlFor="email">Email</Label>
    <Input
      id="email"
      placeholder="email@example.com"
      autoCapitalize="none"
      keyboardType="email-address"
    />
  </YStack>

  <XStack gap="$2" justifyContent="flex-end">
    <Button variant="outlined">Cancel</Button>
    <Button theme="blue">Submit</Button>
  </XStack>
</YStack>

アンチパターン

❌ トークンの代わりにハードコードされた値

// 悪い例
<View padding={16} backgroundColor="#fff" />

// 良い例 - デザイントークンを使用
<View padding="$4" backgroundColor="$background" />

❌ variants に as const がない

// 悪い例 - TypeScript がバリアント型を推論できない
variants: {
  size: { small: {...}, large: {...} }
}

// 良い例
variants: {
  size: { small: {...}, large: {...} }
} as const

❌ styled() 内でのプラットフォーム検出

// 悪い例 - コンパイラで抽出されない
const Box = styled(View, {
  padding: Platform.OS === 'web' ? 10 : 20,
})

// 良い例 - プラットフォームモディファイアを使用
const Box = styled(View, {
  padding: 20,
  '$platform-web': { padding: 10 },
})

❌ AnimatePresence なしの exitStyle

// 悪い例 - 終了アニメーションが動作しない
{show && <View exitStyle={{ opacity: 0 }} />}

// 良い例
<AnimatePresence>
  {show && <View key="box" exitStyle={{ opacity: 0 }} />}
</AnimatePresence>

❌ 抽出を防ぐ動的な値

// 悪い例 - ランタイム変数がコンパイラ抽出を防ぐ
const dynamicPadding = isPremium ? '$6' : '$4'
<View padding={dynamicPadding} />

// 良い例 - インライン三項演算子は抽出可能
<View padding={isPremium ? '$6' : '$4'} />

❌ 間違ったメディアクエリ順序

// 悪い例 - ベース値がレスポンシブをオーバーライド
<View $gtMd={{ padding: '$8' }} padding="$4" />

// 良い例 - ベースが最初、その次にレスポンシブがオーバーライド
<View padding="$4" $gtMd={{ padding: '$8' }} />

❌ CSS ドライバでのスプリングアニメーション

// 悪い例 - CSS ドライバはスプリング物理演算をサポートしない
import { createAnimations } from '@tamagui/animations-css'
const anims = createAnimations({
  bouncy: { type: 'spring', damping: 10 }  // 動作しない
})

// CSS ドライバ向けの良い例 - イージング文字列を使用
const anims = createAnimations({
  bouncy: 'cubic-bezier(0.68, -0.55, 0.265, 1.55) 300ms'
})

コンパイラの最適化

Tamagui コンパイラはビルド時に静的スタイルを CSS に抽出します。スタイルが抽出されるには:

  1. トークンを使用 - $4 は抽出される、16 は抽出されない場合がある
  2. インライン三項演算子 - padding={x ? '$4' : '$2'} は抽出される
  3. ランタイム変数を避ける - 計算された値は抽出されない
  4. バリアントを使用 - 条件付きプロップより優れている

抽出が機能しているかを確認:

  • 開発モードで data-tamagui 属性を探す
  • コンパイラが有効になっているとバンドルサイズが小さくなる
  • スタイルは CSS クラスとして表示される、インラインではない

TypeScript

import { GetProps, styled, View } from '@tamagui/core'

const MyComponent = styled(View, {
  variants: {
    size: { small: {}, large: {} }
  } as const,
})

// プロップ型を抽出
type MyComponentProps = GetProps<typeof MyComponent>

// カスタムプロップで拡張
interface ExtendedProps extends MyComponentProps {
  onCustomEvent?: () => void
}

クイックリファレンス

パターン
トークンpadding="$4"
テーマ値backgroundColor="$background"
カラースケールcolor="$color11" (高コントラストテキスト)
レスポンシブ$gtSm={{ padding: '$6' }}
バリアント<Button size="large" variant="outlined" />
アニメーションanimation="quick" enterStyle={{ opacity: 0 }}
テーマ切り替え<Theme name="dark"><Theme name="blue">
複合<Card><Card.Title> with createStyledContext

リソース

ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ

詳細情報

作者
tamagui
リポジトリ
tamagui/tamagui
ライセンス
MIT
最終更新
不明

Source: https://github.com/tamagui/tamagui / ライセンス: MIT

関連スキル

汎用ソフトウェア開発⭐ リポ 39,967

doubt-driven-development

重要な判断はすべて、本番環境への展開前に新しい視点から対抗的レビューを実施します。速度より正確性が重要な場合、不慣れなコードを扱う場合、本番環境・セキュリティに関わるロジック・取り消し不可の操作など影響度が高い場合、または後でバグを修正するよりも今検証する方が効率的な場合に活用してください。

by addyosmani
汎用ソフトウェア開発⭐ リポ 1,175

apprun-skills

TypeScriptを使用したAppRunアプリケーションのMVU設計に関する総合的なガイダンスが得られます。コンポーネントパターン、イベントハンドリング、状態管理(非同期ジェネレータを含む)、パラメータと保護機能を備えたルーティング・ナビゲーション、vistestを使用したテストに対応しています。AppRunコンポーネントの設計・レビュー、ルートの配線、状態フローの管理、AppRunテストの作成時に活用してください。

by yysun
OpenAIソフトウェア開発⭐ リポ 797

desloppify

コードベースのヘルスチェックと技術負債の追跡ツールです。コード品質、技術負債、デッドコード、大規模ファイル、ゴッドクラス、重複関数、コードスメル、命名規則の問題、インポートサイクル、結合度の問題についてユーザーが質問した場合に使用してください。また、ヘルススコアの確認、次の改善項目の提案、クリーンアップ計画の作成をリクエストされた際にも対応します。29言語に対応しています。

by Git-on-my-level
汎用ソフトウェア開発⭐ リポ 39,967

debugging-and-error-recovery

テストが失敗したり、ビルドが壊れたり、動作が期待と異なったり、予期しないエラーが発生したりした場合に、体系的な根本原因デバッグをガイドします。推測ではなく、根本原因を見つけて修正するための体系的なアプローチが必要な場合に使用してください。

by addyosmani
汎用ソフトウェア開発⭐ リポ 39,967

test-driven-development

テスト駆動開発により実装を進めます。ロジックの実装、バグの修正、動作の変更など、あらゆる場面で活用できます。コードが正常に動作することを証明する必要がある場合、バグ報告を受けた場合、既存機能を修正する予定がある場合に使用してください。

by addyosmani
汎用ソフトウェア開発⭐ リポ 39,967

incremental-implementation

変更を段階的に実施します。複数のファイルに影響する機能や変更を実装する場合に使用してください。大量のコードを一度に書こうとしている場合や、タスクが一度では完結できないほど大きい場合に活用します。

by addyosmani
本サイトは GitHub 上で公開されているオープンソースの SKILL.md ファイルをクロール・インデックス化したものです。 各スキルの著作権は原作者に帰属します。掲載に問題がある場合は info@alsel.co.jp または /takedown フォームよりご連絡ください。
原作者: tamagui · tamagui/tamagui · ライセンス: MIT