ListProductsGridブロック
ListProductsGrid は、MUI の Stack と Card アイテム上に構築されたレスポンシブなカードグリッドおよびリスト表示で、横スクロール可能なチップフィルター、行数制限(line clamping)、完全な複合レイアウトのカスタマイズをサポートします。
インストール
- npm
- yarn
- pnpm
- bun
npm install @nodeblocks/frontend-list-products-grid-block
yarn add @nodeblocks/frontend-list-products-grid-block
pnpm add @nodeblocks/frontend-list-products-grid-block
bun add @nodeblocks/frontend-list-products-grid-block
必要なもの
| 項目 | 用途 |
|---|---|
items (任意) | ListProductsGrid.Items.GridCard 用の商品カード設定の配列 |
layout (任意) | プリセットレイアウト: レスポンシブな複数列グリッド('grid')または単一列リスト('list') |
listProductsGridTitle (任意) | メインのスーパータイトルテキストまたはカスタム React ノード |
subtitle (任意) | メインタイトルの上に表示されるセカンダリタイトル |
ListProductsGrid はプレゼンテーション用のリストブロックとして動作します。items でカードデータを渡すか、children 要素を渡してカスタムカタログアイテムをレンダリングします(複合コンポーネントを参照)。
コード例
- クイックスタート
- グリッドとリストレイアウト
- 複合コンポーネント
- ブロックのオーバーライド
function Example() { const products = [ { title: '手作りオーク製コンソール', subtitle: 'プレミアム職人コレクション', summary: 'ケーブル管理とソフトクローズ引き出し付きの手作り無垢材オーク製メディアコンソール。', imageUrl: 'https://images.unsplash.com/photo-1540555700478-4be289fbecef?auto=format&fit=crop&w=640&q=80', chips: [{ label: '新着', color: 'warning' }], tags: [{ label: '在庫あり' }], }, { title: 'エルゴノミックデスクチェア', subtitle: 'オフィス快適コレクション', summary: '調整可能なランバーサポート、3D アームレスト、通気性メッシュバック付きのタスクチェア。', imageUrl: 'https://images.unsplash.com/photo-1505797149-43b0069ec26b?auto=format&fit=crop&w=640&q=80', chips: [{ label: 'セール', color: 'primary' }], tags: [{ label: '送料無料' }], } ]; return ( <div style={{ minHeight: 400 }}> <ListProductsGrid listProductsGridTitle="注目商品" subtitle="最新コレクション" items={products} layout="grid" /> </div> ); }
状態コントロールを使って、アクティブなレイアウトプリセット(grid または list)を動的に切り替えます。
function Example() { const [layout, setLayout] = React.useState('grid'); const products = [ { title: '手作りオーク製コンソール', subtitle: 'プレミアム職人コレクション · 地元倉庫から発送', summary: 'ケーブル管理とソフトクローズ引き出し付きの無垢材オーク製メディアコンソール。リビングルームに最適。', imageUrl: 'https://images.unsplash.com/photo-1540555700478-4be289fbecef?auto=format&fit=crop&w=640&q=80', chips: [{ label: '新着', color: 'warning' }, { label: '送料無料', color: 'success' }], tags: [{ label: '家具' }], }, { title: 'エルゴノミックデスクチェア', subtitle: 'オフィス快適コレクション · エルゴノミクス基準認証', summary: '調整可能なランバーサポート、3D アームレスト、通気性メッシュバック付きのタスクチェア。長時間の作業に最適。', imageUrl: 'https://images.unsplash.com/photo-1505797149-43b0069ec26b?auto=format&fit=crop&w=640&q=80', chips: [{ label: 'セール', color: 'primary' }], tags: [{ label: 'オフィス' }], } ]; return ( <div style={{ minHeight: 400 }}> <div style={{ marginBottom: 16, display: 'flex', gap: 8 }}> <button onClick={() => setLayout('grid')} style={{ padding: '6px 12px', cursor: 'pointer' }}>グリッド表示</button> <button onClick={() => setLayout('list')} style={{ padding: '6px 12px', cursor: 'pointer' }}>リスト表示</button> </div> <ListProductsGrid listProductsGridTitle="利用可能なカタログ" subtitle="ショールーム" items={products.map(p => ({ ...p, direction: layout === 'list' ? { xs: 'column', md: 'row' } : 'column' }))} layout={layout} /> </div> ); }
'grid' レイアウトはデスクトップで3列のレスポンシブ行にアイテムを配置し、モバイルビューポートでは1列に折り返します。'list' レイアウトは単一の全幅列にアイテムを縦に並べます。direction カードプロパティでメディアブロックのレイアウトを横方向または縦方向に切り替えられます。
子ブロックを使ってレイアウトを明示的に構成します。<ListProductsGrid.Title> と <ListProductsGrid.Items> に設定プロパティを直接渡します。
function Example() { const products = [ { title: '手作りオーク製コンソール', subtitle: 'プレミアム職人コレクション', summary: 'ケーブル管理とソフトクローズ引き出し付きの手作り無垢材オーク製メディアコンソール。', imageUrl: 'https://images.unsplash.com/photo-1540555700478-4be289fbecef?auto=format&fit=crop&w=640&q=80', chips: [{ label: '新着', color: 'warning' }], tags: [{ label: '在庫あり' }], }, { title: 'エルゴノミックデスクチェア', subtitle: 'オフィス快適コレクション', summary: '調整可能なランバーサポート、3D アームレスト、通気性メッシュバック付きのタスクチェア。', imageUrl: 'https://images.unsplash.com/photo-1505797149-43b0069ec26b?auto=format&fit=crop&w=640&q=80', chips: [{ label: 'セール', color: 'primary' }], tags: [{ label: '送料無料' }], } ]; return ( <div style={{ minHeight: 400 }}> <ListProductsGrid layout="grid"> <ListProductsGrid.Title listProductsGridTitle="職人コレクション" subtitle="最新リリース" /> <ListProductsGrid.Items layout="grid"> {products.map((item, idx) => ( <ListProductsGrid.Items.GridCard key={idx} {...item} /> ))} </ListProductsGrid.Items> </ListProductsGrid> </div> ); }
標準のグリッドカードマッピングを維持しながら、関数子でブロックを前置したりヘルパー通知を注入したりできます。
function Example() { const products = [ { title: '手作りオーク製コンソール', subtitle: 'プレミアム職人コレクション', summary: 'ケーブル管理とソフトクローズ引き出し付きの手作り無垢材オーク製メディアコンソール。', imageUrl: 'https://images.unsplash.com/photo-1540555700478-4be289fbecef?auto=format&fit=crop&w=640&q=80', chips: [{ label: '新着', color: 'warning' }], tags: [{ label: '在庫あり' }], } ]; return ( <div style={{ minHeight: 400 }}> <ListProductsGrid listProductsGridTitle="職人カタログ" subtitle="限定セール" layout="grid" items={products} > {({ defaultBlocks, defaultBlockOrder }) => ({ blocks: { ...defaultBlocks, customNotice: ( <div style={{ background: '#eef4ff', border: '1px solid #cddcff', borderRadius: '8px', padding: '12px', fontSize: '14px', textAlign: 'center', }} > 会員はチェックアウト時に追加 10% 割引が適用されます。 </div> ), }, blockOrder: ['title', 'customNotice', 'items'], })} </ListProductsGrid> </div> ); }
ブロックのオーバーライドを使うタイミング
Title とメインの Items グリッドの間に通知、セカンダリフィルター、バナーを挿入する場合にオーバーライドを使用します。標準の defaultBlockOrder は ['title', 'items'] です。
主要プロパティ
コアプロパティ
| プロパティ | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
items | ComponentProps<typeof ListProductsGrid.Items.GridCard>[] | いいえ | undefined | デフォルト Items レイアウトでレンダリングされる商品カード設定の配列(任意) |
layout | 'grid' | 'list' | いいえ | 'grid' | リストアイテムのレイアウトプリセット(grid: 3列レスポンシブ行; list: 縦方向の単一列) |
コンテンツプロパティ
| プロパティ | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
listProductsGridTitle | ReactNode | いいえ | undefined | Title ブロックに表示されるメインのスーパータイトルテキストまたはカスタム React 要素 |
subtitle | string | いいえ | undefined | メインタイトルの上に表示されるセカンダリカテゴリラベル |
GridCard プロパティ
items 内の商品カード、または <ListProductsGrid.Items.GridCard /> サブコンポーネントに直接プロパティを設定します:
| プロパティ | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
title | string | はい | - | 商品カードのプライマリタイトル |
subtitle | string | いいえ | undefined | タイトル下に表示されるセカンダリテキストまたはメタカテゴリ |
summary | ReactNode | いいえ | undefined | カードのメイン説明; xs では3行、sm 以上では2行に省略表示 |
imageUrl | string | いいえ | undefined | カード上部中央に表示されるメイン画像 URL |
subtitleImageUrl | string | いいえ | undefined | サブタイトルテキスト横に表示される小さなアイコンまたはアバター URL |
chips | (ChipProps & { label: string })[] | いいえ | undefined | 横スクロール可能なコンテナ内にマッピングされるステータスタグとバッジ |
tags | { icon?: ReactElement; label: string | string[] }[] | いいえ | undefined | カード区切り線の下に表示されるアイコンタグ(label が配列の場合は / で結合) |
linkProps | { href?: string; onClick?: (e: React.MouseEvent) => void; onNavigate: ((href: string) => void) | 'standard-html-link'; openInNewTab?: boolean } | いいえ | undefined | カードナビゲーションのクリック設定 |
disabled | boolean | いいえ | false | true のとき、操作を無効化しカードの不透明度を下げる |
direction | StackProps['direction'] | いいえ | grid レイアウトでは column、list レイアウトではレスポンシブ column/row | フレックス整列レイアウト(レイアウトベースのデフォルトを上書き) |
actionArea | ReactNode | いいえ | undefined | タイトル行の末尾に配置する任意のノード(お気に入りやオプションアイコンボタンなど) |
cardContentProps | Partial<Omit<CardContentProps, 'children'>> | いいえ | undefined | 内部 MUI CardContent コンポーネントに直接渡される上書き |
mainStackProps | Partial<StackProps> | いいえ | undefined | カードレイアウトスタック用のカスタムスタイル上書き |
colInnerProps | Partial<StackProps> | いいえ | undefined | 内部列レイアウトスタック用のカスタム上書き |
titleStackProps | Partial<StackProps> | いいえ | undefined | タイトル/サブタイトルテキストコンテナに渡される上書き |
レイアウトと構成プロパティ
| プロパティ | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
children | BlocksOverride | ReactNode | いいえ | undefined | 複合 JSX の子、または blocks と blockOrder を返す関数オーバーライド |
spacing | StackProps['spacing'] | いいえ | 5 | タイトルとカタログアイテム間のレイアウト間隔(テーマ単位) |
className | string | いいえ | undefined | ルートコンテナに適用されるカスタムクラス名 |
sx | SxProps | いいえ | undefined | ルート Stack コンテナ用の MUI システムスタイル |
ListProductsGrid は StackProps(children を除く)を継承します。オーバーライドなしのデフォルトブロック順は ['title', 'items'](defaultBlockOrder)です。
デフォルト UI ブロック
| ブロック | ベース | 備考 |
|---|---|---|
ListProductsGrid (ルート) | Stack | 制御されたフレックスラッパー(direction="column"、spacing={5}) |
ListProductsGrid.Title | Stack + Typography | サブタイトルのスーパーヘッダー(variant h4)とタイトルヘッダー(variant h1)をレンダリング |
ListProductsGrid.Items | Box | CSS Grid コンテナ。layout プロパティに応じて列を展開: 'grid'(3列)または 'list'(1列) |
ListProductsGrid.Items.GridCard | Card | メインの商品レイアウトカード; CardMedia、HorizontalScrollEdgeArrows、メタデータ列をネスト |
TypeScript
import { ListProductsGrid } from '@nodeblocks/frontend-list-products-grid-block';
import type { ComponentProps } from 'react';
type GridCardConfig = ComponentProps<typeof ListProductsGrid.Items.GridCard>;
const products: GridCardConfig[] = [
{
title: '無垢材オーク製コンソールテーブル',
subtitle: '限定職人リリース',
summary: 'プレミアムホワイトオークから手作りされた美しいコンソール。',
imageUrl: 'https://example.com/oak-table.jpg',
chips: [{ label: '新着', color: 'warning' }],
linkProps: {
href: '/products/oak-table',
onNavigate: 'standard-html-link',
}
}
];
<ListProductsGrid
listProductsGridTitle="ショールーム"
subtitle="手作り家具"
items={products}
layout="grid"
/>;