メインコンテンツまでスキップ

商品グリッドリストブロック

ListProductsGridコンポーネントは、ReactとTypeScriptで構築された商品表示用の完全にカスタマイズ可能でアクセシブルなグリッドレイアウトです。モダンなデザインパターン、柔軟なカスタマイズオプション、タイトル、アイテム、カード用の構成可能なサブコンポーネントを備えた完全な商品リスティングインターフェースを提供します。


🚀 インストール

npm install @nodeblocks/frontend-list-products-grid-block@0.2.0

📖 使用法

import {ListProductsGrid} from '@nodeblocks/frontend-list-products-grid-block';
ライブエディター
function SimpleListProductsGrid() {
  const products = [
    {
      id: '1',
      title: 'ワイヤレスヘッドホン',
      description: 'プレミアムノイズキャンセリングヘッドホン',
      price: '¥19,999',
      imageUrl: 'https://placehold.co/600x400',
      badges: ['新着'],
    },
    {
      id: '2',
      title: 'スマートウォッチ',
      description: 'フィットネストラッキングと通知機能',
      price: '¥29,999',
      originalPrice: '¥34,999',
      imageUrl: 'https://placehold.co/600x400',
      badges: ['セール'],
    },
    {
      id: '3',
      title: 'ラップトップスタンド',
      description: 'エルゴノミックアルミニウムスタンド',
      price: '¥7,999',
      imageUrl: 'https://placehold.co/600x400',
    },
    {
      id: '4',
      title: 'メカニカルキーボード',
      description: 'RGBバックライト付きゲーミングキーボード',
      price: '¥14,999',
      imageUrl: 'https://placehold.co/600x400',
      badges: ['人気'],
    },
  ];

  const handleNavigate = (href) => console.log('ナビゲート:', href);

  return (
    <ListProductsGrid listProductsGridTitle="注目商品" subtitle="おすすめ商品をご覧ください">
      <ListProductsGrid.Title />
      <ListProductsGrid.Items>
        {products.map(product => (
          <ListProductsGrid.Items.GridCard
            key={product.id}
            title={product.title}
            imageUrl={product.imageUrl}
            summary={product.description}
            chips={product.badges?.map(b => ({label: b}))}
            linkProps={{href: `/products/${product.id}`, onNavigate: handleNavigate}}
            button={{children: product.price}}
          />
        ))}
      </ListProductsGrid.Items>
    </ListProductsGrid>
  );
}
結果
Loading...

🔧 プロパティリファレンス

メインコンポーネントのプロパティ

プロパティデフォルト説明
listProductsGridTitleReactNodeundefined商品リストのメインタイトル
subtitlestringundefinedメインタイトルの上に表示されるセカンダリタイトル
spacingnumber5子要素間のスペーシング
classNamestringundefinedグリッドコンテナスタイリング用の追加CSSクラス名
childrenBlocksOverrideundefinedデフォルトレンダリングをオーバーライドするカスタムブロックコンポーネント

注意: メインコンポーネントはMUI StackProps を拡張します。デフォルトスタイリングには px: 2py: 5 のパディングが含まれます。

サブコンポーネント

ListProductsGridコンポーネントは複数のサブコンポーネントを提供します。すべてのサブコンポーネントは、メインコンポーネントのコンテキストからデフォルト値を受け取り、プロパティを通じてこれらの値をオーバーライドできます。

ListProductsGrid.Title

サブタイトルとメインタイトルを持つグリッドタイトルセクションのコンテナ。

プロパティデフォルト説明
listProductsGridTitleReactNodeコンテキストからメインタイトルとして表示するコンテンツ
subtitlestringコンテキストからサブタイトルとして表示するコンテンツ(タイトルの上に表示)
spacingnumber0.5サブタイトルとタイトル間のスペーシング
childrenReactNodeデフォルトタイトルレイアウトデフォルトタイトルレイアウトをオーバーライドするカスタムコンテンツ
classNamestringundefinedスタイリング用の追加CSSクラス名

注意: このコンポーネントはMUI StackProps を拡張します。デフォルトスタイリングには alignItems: 'center' が含まれます。

ListProductsGrid.Items

商品グリッドカードのコンテナ。

プロパティデフォルト説明
spacingnumber2グリッドアイテム間のスペーシング
childrenReactNodeundefinedレンダリングするグリッドカードコンポーネント
classNamestringundefinedスタイリング用の追加CSSクラス名

注意: このコンポーネントはMUI StackProps を拡張します。

ListProductsGrid.Items.GridCard

リッチコンテンツオプションを持つ個別の商品カードコンポーネント。

プロパティデフォルト説明
titlestring必須カードに表示されるメインタイトル
subtitlestringundefinedタイトル下に表示されるセカンダリテキスト
subtitleImageUrlstringundefinedサブタイトル横に表示される小さな画像のURL
summarystringundefined簡潔な説明や要約テキスト
imageUrlstringundefinedカードに表示されるメイン画像のURL
tertiaryTextstringundefinedタイトルの上に表示される追加情報
contentstringundefinedカード用の制限なしテキストコンテンツ
chipsChipProps[]undefinedオプションの leftIconrightIcon を持つMUI Chipプロパティの配列
tagsArray<{icon?: ReactElement, label: string | string[]}>undefinedアイコンとラベルを持つタグオブジェクトの配列
titleIconReactElementundefinedタイトルの前に表示されるアイコン
titleActionIconButtonPropsundefinedタイトルの後に表示されるアクションボタン
buttonButtonPropsundefinedカードのメインコールトゥアクションボタン
statusStatusObjectundefinedラベルとオプションのアクションを持つステータスコールアウト
linkPropsLinkPropsundefinedカードをクリック可能にするナビゲーションプロパティ
hasDividerbooleanfalseカードコンテンツセクション間にディバイダーを追加
disabledbooleanfalseカードスタイルを無効状態に設定
classNamestringundefinedスタイリング用の追加CSSクラス名

注意: このコンポーネントはMUI CardProps を拡張します。


🎨 設定例

カスタムグリッドレイアウト:

<ListProductsGrid
listProductsGridTitle="注目商品"
subtitle="ベストセラー"
spacing={3}
sx={{ bgcolor: '#f5f5f5', borderRadius: 2 }}
>
<ListProductsGrid.Title sx={{ textAlign: 'left', alignItems: 'flex-start' }} />
<ListProductsGrid.Items
sx={{
display: 'grid',
gridTemplateColumns: 'repeat(auto-fill, minmax(280px, 1fr))',
gap: 3
}}
>
{products.map((product, i) => (
<ListProductsGrid.Items.GridCard key={i} {...product} />
))}
</ListProductsGrid.Items>
</ListProductsGrid>

ステータスとアクション付きカード:

<ListProductsGrid.Items.GridCard
title="プレミアムヘッドホン"
subtitle="ソニーエレクトロニクス"
imageUrl="/images/headphones.jpg"
chips={[{label: '新着', color: 'primary'}]}
status={{
label: '在庫あり',
color: 'primary',
action: {
children: '詳細を見る',
href: '/products/123',
onNavigate: href => router.push(href),
},
}}
button={{
children: 'カートに追加',
variant: 'contained',
color: 'primary',
}}
linkProps={{
href: '/products/123',
onNavigate: href => router.push(href),
}}
/>

ブロックオーバーライドパターン:

<ListProductsGrid
listProductsGridTitle="ショップコレクション"
subtitle="厳選アイテム"
>
{({defaultBlocks}) => ({
blocks: {
...defaultBlocks,
title: customTitle,
items: customItems,
pagination: customPagination,
},
blockOrder: ['title', 'items', 'pagination'],
})}
</ListProductsGrid>

🔧 TypeScriptサポート

包括的な型定義による完全なTypeScriptサポート:

import {ListProductsGrid} from '@nodeblocks/frontend-list-products-grid-block';
import {ReactElement} from 'react';
import {ChipProps, ButtonProps, IconButtonProps} from '@mui/material';

// Product grid item interface
interface ProductGridItem {
id: string;
title: string;
description?: string;
price: string;
originalPrice?: string;
imageUrl: string;
badges?: string[];
rating?: number;
reviewCount?: number;
isNew?: boolean;
isFeatured?: boolean;
}

// Link props for card navigation
interface LinkProps {
href?: string;
onClick?: (e: React.MouseEvent) => void;
onNavigate: ((href: string) => void) | 'standard-html-link';
openInNewTab?: boolean;
}

// Status object type
interface StatusObject {
label: string;
color?: 'default' | 'primary';
action?: Partial<ButtonProps> & {
href?: string;
onNavigate?: ((href: string) => void) | 'standard-html-link';
openInNewTab?: boolean;
};
}

// Grid card props type
interface GridCardProps {
title: string;
subtitle?: string;
subtitleImageUrl?: string;
summary?: string;
imageUrl?: string;
tertiaryText?: string;
content?: string;
chips?: (ChipProps & {
leftIcon?: ReactElement;
rightIcon?: ReactElement;
label: string;
})[];
tags?: {icon?: ReactElement; label: string | string[]}[];
titleIcon?: ReactElement;
titleAction?: Partial<IconButtonProps>;
button?: Partial<ButtonProps>;
status?: StatusObject;
linkProps?: LinkProps;
hasDivider?: boolean;
disabled?: boolean;
}

function TypedListProductsGrid() {
const productData: ProductGridItem[] = [
{
id: 'prod-1',
title: 'プレミアムラップトップ',
description: '15インチディスプレイ、16GB RAM、512GB SSD',
price: '¥179,999',
imageUrl: 'https://placehold.co/600x400',
badges: ['新着'],
rating: 4.8,
reviewCount: 256,
},
{
id: 'prod-2',
title: 'ワイヤレス充電器',
description: '急速充電、すべてのQiデバイス対応',
price: '¥5,999',
imageUrl: 'https://placehold.co/600x400',
rating: 4.5,
reviewCount: 1024,
},
];

const handleNavigate = (href: string): void => {
console.log('ナビゲート先:', href);
};

return (
<ListProductsGrid
listProductsGridTitle="商品一覧"
subtitle="厳選された電子機器"
sx={{
maxWidth: 1200,
mx: 'auto',
p: 3,
}}
>
<ListProductsGrid.Title />
<ListProductsGrid.Items>
{productData.map(product => (
<ListProductsGrid.Items.GridCard
key={product.id}
title={product.title}
imageUrl={product.imageUrl}
summary={product.description}
chips={product.badges?.map(b => ({label: b}))}
linkProps={{href: `/products/${product.id}`, onNavigate: handleNavigate}}
button={{children: product.price}}
/>
))}
</ListProductsGrid.Items>
</ListProductsGrid>
);
}

📝 注意事項

  • メインコンポーネントはデフォルト spacing={5} とパディング px: 2, py: 5 を持つMUI StackProps を拡張します
  • ListProductsGrid.TitleTypography コンポーネントを使用してメインタイトルの上にサブタイトルを表示します
  • ListProductsGrid.Items.GridCardtitle プロパティが必要です。その他のプロパティはすべてオプションです
  • linkProps が提供されると、CardActionArea を介してカード全体がクリック可能になります
  • onNavigate プロパティはネイティブブラウザナビゲーションのために 'standard-html-link' に設定できます
  • linkProps が存在する場合、status.action はボタンとしてレンダリングされます(ネストされた <a> タグを避けるため)
  • chips はMUI ChipProps に加えて、オプションの leftIconrightIcon 要素をサポートします
  • 配列ラベルを持つ tags は " / " セパレータで結合されます(例: ['A', 'B'] → "A / B")
  • カード画像は object-fit: cover で固定高さ 120px を持ちます
  • 無効化されたカードは不透明度が低下(0.6)し、ポインターイベントが無効化されます

React、TypeScript、MUIを使用して❤️で構築されました。