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

商品テーブルリストブロック

ListProductsTableコンポーネントは、ReactとTypeScriptで構築された完全にカスタマイズ可能でアクセシブルな商品テーブルインターフェースです。モダンなデザインパターン、ソート可能なカラム、アクションドロップダウン、タブ、公開ステータス管理、ページネーションサポート、ローディング状態、高度な商品管理アプリケーション用の柔軟なカスタマイズオプションを備えた完全な表形式商品リスティング体験を提供します。


🚀 インストール

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

📖 使用法

import {ListProductsTable} from '@nodeblocks/frontend-list-products-table-block';
ライブエディター
function BasicListProductsTable() {
  const [currentTab, setCurrentTab] = useState('published');
  const [isLoading] = useState(false);

    const productData = [
      {
        id: '1',
        title: 'プレミアムオフィスチェア',
        category: '家具',
        createdAt: '2024-01-15T10:30:00Z',
        updatedAt: '2024-01-16T14:20:00Z',
        numberOfApplicants: '5',
        publication: {
          since: '2024-01-15T00:00:00Z',
          until: '2024-03-15T23:59:59Z',
          status: 'ACTIVE',
        },
      },
      {
        id: '2',
        title: 'ワイヤレスヘッドホン',
        category: '電子機器',
        createdAt: '2024-01-14T09:15:00Z',
        updatedAt: '2024-01-14T09:15:00Z',
        numberOfApplicants: '12',
        publication: {
          since: '2024-01-20T00:00:00Z',
          until: '2024-04-20T23:59:59Z',
          status: 'INACTIVE',
        },
      },
    ];

    const tabs = [{label: '公開商品'}, {label: '下書き商品'}, {label: 'アーカイブ商品'}];

    const labels = {
      emptyStateMessage: '商品が見つかりません',
      actions: {
        createProduct: '商品を作成'
      },
      headerRow: {
        title: '商品タイトル',
        publicationPeriod: '公開期間',
        createdAt: '作成日',
        updatedAt: '更新日',
        numberOfApplicants: '申込者数'
      },
      rowActions: {
        public: '公開する',
        private: '非公開にする',
        edit: '商品を編集',
        archive: '商品をアーカイブ',
        unarchive: '商品をアーカイブ解除'
      },
      unsetData: {
        since: '未設定',
        until: '未設定',
        date: '公開期間なし',
      },
    };

    const handleProductPublic = (productId, title) => {
      console.log('商品を公開しました:', productId, title);
    };

    const handleProductPrivate = (productId, title) => {
      console.log('商品を非公開にしました:', productId, title);
    };

    const handleProductArchive = (productId, title) => {
      console.log('商品をアーカイブしました:', productId, title);
    };

    const handleProductUnarchive = (productId) => {
      console.log('商品をアーカイブ解除しました:', productId);
    };

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

    const getRowHref = (row) => `/products/${row.id}`;
    const getUpdateRowHref = (row) => `/products/${row.id}/edit`;

    return (
      <ListProductsTable
        listProductsTableTitle="商品管理"
        labels={labels}
        isLoading={isLoading}
        onNavigate={handleNavigate}
        onProductPublic={handleProductPublic}
        onProductPrivate={handleProductPrivate}
        onProductArchive={handleProductArchive}
        onProductUnarchive={handleProductUnarchive}
        data={productData}
        rowHref={getRowHref}
        updateRowHref={getUpdateRowHref}
        tabs={tabs}
        currentTab={currentTab}
        onTabChange={setCurrentTab}
        createHref="#products/new"
      >
        <ListProductsTable.Header style={{display: 'flex', justifyContent: 'space-between'}}>
          <ListProductsTable.Title />
          <ListProductsTable.Action />
        </ListProductsTable.Header>
        <ListProductsTable.Content>
          {isLoading ? (
            <ListProductsTable.Loader />
          ) : (
            <>
              <ListProductsTable.Tabs />
              <ListProductsTable.Table />
            </>
          )}
        </ListProductsTable.Content>
      </ListProductsTable>
    );
  }
結果
Loading...

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

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

プロパティデフォルト説明
listProductsTableTitleReactNode必須商品テーブルセクションのタイトル
labelsTableLabels必須テーブルヘッダー、アクション、メッセージ用のラベルオブジェクト
isLoadingbooleanundefinedテーブルが現在ローディング中かどうか
onNavigate(to: string) => void必須ナビゲーション用のコールバック関数
onProductPublic(id: string, title: string) => void必須商品が公開されたときのコールバック関数
onProductPrivate(id: string, title: string) => void必須商品が非公開にされたときのコールバック関数
onProductArchive(id: string, title: string) => void必須商品がアーカイブされたときのコールバック関数
onProductUnarchive(id: string) => void必須商品がアーカイブ解除されたときのコールバック関数
dataListProductsTableRowData[]必須商品データオブジェクトの配列
rowHref(row: ListProductsTableRowData) => string必須行リンクURLを生成する関数
updateRowHref(row: ListProductsTableRowData) => string必須編集ページURLを生成する関数
tabsTabData[]必須タブ設定オブジェクトの配列
currentTabstringundefined現在アクティブなタブラベル
onTabChange(tab: string) => voidundefinedタブが変更されたときのコールバック関数
createHrefstring必須新しい商品作成用のURL
paginationPaginationPropsundefinedページネーション設定オブジェクト
spacingnumber3子要素間のスペーシング
classNamestringundefinedコンテナスタイリング用の追加CSSクラス名
childrenBlocksOverrideundefinedデフォルトレンダリングをオーバーライドするカスタムブロックコンポーネント

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

サブコンポーネント

ListProductsTableコンポーネントは、独立して使用できる複数のサブコンポーネントを提供します:

ListProductsTable.Header

タイトルとアクションボタンのコンテナ。

プロパティデフォルト説明
childrenReactNodeデフォルトレイアウトデフォルトヘッダーレンダリングをオーバーライドするカスタムコンテンツ
classNamestringundefinedスタイリング用の追加CSSクラス名

注意: このコンポーネントはMUI StackProps を拡張します。デフォルトスタイリングには direction="row"justifyContent: 'space-between' が含まれます。

ListProductsTable.Title

タイトルタイポグラフィコンポーネント。

プロパティデフォルト説明
listProductsTableTitleReactNodeコンテキストからタイトルとして表示するコンテンツ
variantTypographyVariant"h4"MUI Typography バリアント
componentElementType"h1"レンダリングするHTML要素
childrenReactNodeundefinedタイトルをオーバーライドするカスタムコンテンツ
classNamestringundefined追加CSSクラス名

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

ListProductsTable.Action

アクションボタン(商品作成など)のコンテナ。

プロパティデフォルト説明
createHrefstringコンテキストから作成アクションボタンのURL
labelsTableLabelsコンテキストからアクションテキスト用のラベル
onNavigate(to: string) => voidコンテキストからナビゲーションコールバック
childrenReactNodeデフォルトボタンアクションレンダリングをオーバーライドするカスタムコンテンツ
classNamestringundefined追加CSSクラス名

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

ListProductsTable.Content

テーブルコンテンツエリアのコンテナ。

プロパティデフォルト説明
isLoadingbooleanコンテキストからローディング状態
childrenReactNodeデフォルトレイアウトレンダリングをオーバーライドするカスタムコンテンツ
classNamestringundefined追加CSSクラス名

注意: このコンポーネントはMUI BoxProps を拡張します。子要素が提供されない場合、Loader(ローディング中の場合)またはTabs + Tableをレンダリングします。

ListProductsTable.Loader

ローディングインジケーターコンポーネント。

プロパティデフォルト説明
childrenReactNodeCircularProgressカスタムローディングインジケーター
classNamestringundefined追加CSSクラス名

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

ListProductsTable.Tabs

タブナビゲーションコンポーネント。

プロパティデフォルト説明
tabsTabData[]コンテキストからタブ設定オブジェクトの配列
currentTabstringコンテキストから現在アクティブなタブラベル
onTabChange(tab: string) => voidコンテキストからタブ変更コールバック関数
classNamestringundefined追加CSSクラス名

注意: このコンポーネントはMUI TabsPropsvalueonChangevariant を除く)を拡張します。内部で variant="fullWidth" を使用します。

ListProductsTable.Table

行アクションとページネーション付きのデータテーブルコンポーネント。

プロパティデフォルト説明
labelsTableLabelsコンテキストからヘッダーとアクション用のラベル
dataListProductsTableRowData[]コンテキストからテーブルデータの配列
rowHref(row) => stringコンテキストから行リンクURLを生成する関数
updateRowHref(row) => stringコンテキストから編集ページURLを生成する関数
onNavigate(to: string) => voidコンテキストからナビゲーションコールバック関数
onProductPublic(id, title) => voidコンテキストから商品が公開されたときのコールバック
onProductPrivate(id, title) => voidコンテキストから商品が非公開にされたときのコールバック
onProductArchive(id, title) => voidコンテキストから商品がアーカイブされたときのコールバック
onProductUnarchive(id) => voidコンテキストから商品がアーカイブ解除されたときのコールバック
paginationPaginationPropsコンテキストからページネーション設定
spacingnumber3要素間のスペーシング
classNamestringundefined追加CSSクラス名

注意: このコンポーネントはMUI StackProps を拡張します。データが空の場合、空状態を表示します。


🎨 設定例

カスタムヘッダーレイアウト:

<ListProductsTable {...props}>
<ListProductsTable.Header sx={{ bgcolor: 'primary.main', p: 2, borderRadius: 2 }}>
<ListProductsTable.Title sx={{ color: 'white' }} />
<ListProductsTable.Action />
</ListProductsTable.Header>
<ListProductsTable.Content />
</ListProductsTable>

ページネーション付き:

const pagination = {
currentPage: currentPage,
totalPages: 10,
onPageChange: page => {
setCurrentPage(page);
console.log('ページを取得中:', page);
},
};

<ListProductsTable
{...props}
pagination={pagination}
>
<ListProductsTable.Header />
<ListProductsTable.Content />
</ListProductsTable>

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

<ListProductsTable {...props}>
{({defaultBlocks, defaultBlockOrder}) => ({
blocks: {
...defaultBlocks,
header: {
...defaultBlocks.header,
props: {
...defaultBlocks.header.props,
sx: {bgcolor: '#f5f5f5', p: 3, borderRadius: 2},
},
},
},
blockOrder: defaultBlockOrder,
})}
</ListProductsTable>

🔧 TypeScriptサポート

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

import {ListProductsTable} from '@nodeblocks/frontend-list-products-table-block';
import {useState} from 'react';

interface ListProductsTableRowData {
id: string;
title: string;
category: string;
createdAt: string;
updatedAt: string;
numberOfApplicants: string;
publication?: {
since?: string;
until?: string;
status?: string;
};
}

interface TabData {
key?: string;
label: string;
isDisabled?: boolean;
subtitle?: string;
}

interface TableLabels {
emptyStateMessage: string;
actions: {
createProduct: string;
};
headerRow: {
title: string;
publicationPeriod: string;
createdAt: string;
updatedAt: string;
numberOfApplicants: string;
};
rowActions: {
public: string;
private: string;
edit: string;
archive: string;
unarchive: string;
};
unsetData: {
since: string;
until: string;
date: string;
};
}

function TypedListProductsTableExample() {
const [currentTab, setCurrentTab] = useState('published');
const [isLoading] = useState(false);

const products: ListProductsTableRowData[] = [
{
id: '1',
title: '商品名',
category: '電子機器',
createdAt: '2024-01-15T10:30:00Z',
updatedAt: '2024-01-16T14:20:00Z',
numberOfApplicants: '5',
publication: {
since: '2024-01-15T00:00:00Z',
until: '2024-03-15T23:59:59Z',
status: 'ACTIVE',
},
},
];

const tabs: TabData[] = [
{ label: '公開済み', key: 'published' },
{ label: '下書き', key: 'draft' },
{ label: 'アーカイブ済み', key: 'archived', isDisabled: false }
];

const labels = {
emptyStateMessage: '利用可能な商品がありません',
actions: { createProduct: '新しい商品' },
headerRow: {
title: '商品名',
publicationPeriod: '公開期間',
createdAt: '作成日',
updatedAt: '更新日',
numberOfApplicants: '申込者数'
},
rowActions: {
public: '公開',
private: '非公開',
edit: '編集',
archive: 'アーカイブ',
unarchive: '復元'
},
unsetData: {
since: '未設定',
until: '未設定',
date: '公開期間なし'
}
};

return (
<ListProductsTable
listProductsTableTitle="商品ダッシュボード"
labels={labels}
isLoading={isLoading}
onNavigate={(path) => console.log('ナビゲート:', path)}
onProductPublic={(id, title) => console.log('公開:', id, title)}
onProductPrivate={(id, title) => console.log('非公開:', id, title)}
onProductArchive={(id, title) => console.log('アーカイブ:', id, title)}
onProductUnarchive={(id) => console.log('復元:', id)}
data={products}
rowHref={row => `/products/${row.id}`}
updateRowHref={row => `/products/${row.id}/edit`}
tabs={tabs}
currentTab={currentTab}
onTabChange={setCurrentTab}
createHref="#products/create"
>
<ListProductsTable.Header />
<ListProductsTable.Content />
</ListProductsTable>
);
}

📝 注意事項

  • メインコンポーネントはデフォルト spacing={3}p: 3 パディングを持つMUI StackProps を拡張します
  • ListProductsTable.Title はデフォルトで variant="h4"component="h1" を持つMUI Typography を使用します
  • ListProductsTable.Tabsvariant="fullWidth" を持つMUI Tabs を使用します - タブはコンテナを埋めるように伸びます
  • 日付は luxon ライブラリを使用してフォーマットされます: 公開日は yyyy/M/d、作成/更新日は yyyy/M/d HH:mm
  • 行ドロップダウンメニューは publication.status に基づいて異なるアクションを表示します:
    • ACTIVE ステータス: 「非公開にする」「編集」「アーカイブ」オプションを表示
    • INACTIVE ステータス: 「公開する」「編集」「アーカイブ」オプションを表示
    • ARCHIVED ステータス: 「アーカイブ解除」オプションのみを表示
  • 空状態は emptyStateMessage ラベルと「person」アイコンを表示します
  • rowHref がURLを返す場合、テーブル行全体がホバーエフェクト付きでクリック可能になります
  • ページネーションは variant="outlined"shape="rounded" を持つMUI Pagination コンポーネントを使用します

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