ユーザーリストブロック
ListUsersコンポーネントは、React、TypeScript、MUIで構築された完全にカスタマイズ可能でアクセシブルなユーザーテーブルインターフェースです。モダンなデザインパターン、ソート可能なカラム、タブ、ステータス管理、ページネーションサポート、ローディング状態、高度なユーザー管理アプリケーション用の柔軟なカスタマイズオプションを備えた完全な表形式ユーザーリスティング体験を提供します。
🚀 インストール
npm install @nodeblocks/frontend-list-users-block@0.2.0
📖 使用法
import {ListUsers} from '@nodeblocks/frontend-list-users-block';
- 基本的な使用法
- 高度な使用法
ライブエディター
function SimpleListUsers() { const users = [ { id: '1', name: '田中太郎', status: 'in_use', createdAt: '2023-01-15', }, { id: '2', name: '佐藤花子', status: 'in_use', createdAt: '2023-02-20', }, { id: '3', name: '山田次郎', status: 'not_in_use', createdAt: '2023-03-10', }, ]; const pagination = { currentPage: 1, totalPages: 1, onPageChange: newPage => console.log('ページ:', newPage), }; const labels = { emptyStateMessage: 'ユーザーが見つかりません', headerRow: { createdAt: '作成日', name: '名前', status: 'ステータス', }, cellData: { statusInUse: 'アクティブ', statusNotInUse: '非アクティブ', }, }; return ( <ListUsers listUsersTitle="チームメンバー" data={users} isLoading={false} pagination={pagination} onNavigate={href => console.log('ナビゲート:', href)} rowHref={row => `/users/${row.id}`} labels={labels} > <ListUsers.Header /> <ListUsers.Table /> </ListUsers> ); }
結果
Loading...
ライブエディター
function AdvancedListUsers() { const [currentTab, setCurrentTab] = useState('All'); const [currentPage, setCurrentPage] = useState(1); const [isLoading] = useState(false); const allUsers = [ { id: '1', name: '田中太郎', status: 'in_use', createdAt: '2023-01-15', }, { id: '2', name: '佐藤花子', status: 'in_use', createdAt: '2023-02-20', }, { id: '3', name: '山田次郎', status: 'not_in_use', createdAt: '2023-03-10', }, { id: '4', name: '鈴木美咲', status: 'not_in_use', createdAt: '2023-04-05', }, { id: '5', name: '高橋健太', status: 'in_use', createdAt: '2023-05-12', }, ]; const filteredUsers = currentTab === 'All' ? allUsers : currentTab === 'Active' ? allUsers.filter(user => user.status === 'in_use') : allUsers.filter(user => user.status === 'not_in_use'); const tabs = [ {key: 'all', label: 'すべて', subtitle: `${allUsers.length} ユーザー`}, { key: 'active', label: 'アクティブ', subtitle: `${allUsers.filter(u => u.status === 'in_use').length} ユーザー`, }, { key: 'inactive', label: '非アクティブ', subtitle: `${allUsers.filter(u => u.status === 'not_in_use').length} ユーザー`, }, ]; const pagination = { currentPage, totalPages: Math.ceil(filteredUsers.length / 10), onPageChange: newPage => setCurrentPage(newPage), }; const labels = { emptyStateMessage: 'ユーザーが見つかりません', headerRow: { createdAt: '作成日時', name: 'ユーザー名', status: 'ステータス', }, cellData: { statusInUse: 'アクティブ', statusNotInUse: '非アクティブ', }, }; return ( <ListUsers listUsersTitle="ユーザー管理" data={filteredUsers} isLoading={isLoading} pagination={pagination} onNavigate={href => console.log('ナビゲート:', href)} rowHref={row => `/users/${row.id}`} tabs={tabs} currentTab={currentTab} onTabChange={tab => { setCurrentTab(tab); setCurrentPage(1); }} labels={labels} sx={{ maxWidth: 1200, mx: 'auto', bgcolor: '#ffffff', borderRadius: 3, boxShadow: '0 4px 20px rgba(0,0,0,0.08)', overflow: 'hidden', }} > {({defaultBlocks, defaultBlockOrder}) => ({ blocks: { ...defaultBlocks, header: ( <ListUsers.Header sx={{ p: 3, borderBottom: '1px solid #e2e8f0', '& .nbb-list-users-title': { fontSize: 24, fontWeight: 700, color: '#1e293b', }, }} /> ), tabs: ( <ListUsers.Tabs sx={{ px: 3, borderBottom: '1px solid #e2e8f0', '& .MuiTab-root': { textTransform: 'none', fontWeight: 500, color: '#64748b', '&.Mui-selected': { color: '#6366f1', fontWeight: 600, }, }, '& .MuiTabs-indicator': { bgcolor: '#6366f1', height: 3, borderRadius: '3px 3px 0 0', }, }} /> ), table: ( <ListUsers.Table sx={{ '& .MuiTableHead-root': { bgcolor: '#f8fafc', '& .MuiTableCell-head': { color: '#475569', fontWeight: 600, textTransform: 'uppercase', fontSize: 12, letterSpacing: '0.05em', py: 2, }, }, '& .MuiTableBody-root': { '& .MuiTableRow-root': { transition: 'background 0.2s ease', '&:hover': { bgcolor: '#f8fafc', }, }, '& .MuiTableCell-body': { py: 2, color: '#334155', }, }, }} /> ), }, blockOrder: defaultBlockOrder, })} </ListUsers> ); }
結果
Loading...
🔧 プロパティリファレンス
メインコンポーネントのプロパティ
| プロパティ | 型 | デフォルト | 説明 |
|---|---|---|---|
listUsersTitle | ReactNode | 必須 | ユーザーテーブルセクションのタイトル |
labels | UserLabels | 必須 | テーブルヘッダー、ステータスメッセージ、空状態用のラベルオブジェクト |
data | ListUsersRowData[] | 必須 | ユーザーデータオブジェクトの配列 |
isLoading | boolean | undefined | テーブルが現在ローディング中かどうか |
onNavigate | (to: string) => void | undefined | ナビゲーション用のコールバック関数 |
rowHref | (row: ListUsersRowData) => string | undefined | 行リンクURLを生成する関数 |
tabs | TabData[] | undefined | タブ設定オブジェクトの配列 |
currentTab | string | undefined | 現在アクティブなタブラベル |
onTabChange | (tab: string) => void | undefined | タブが変更されたときのコールバック関数 |
pagination | PaginationProps | undefined | ページネーション設定オブジェクト |
className | string | undefined | コンテナスタイリング用の追加CSSクラス名 |
children | BlocksOverride | undefined | デフォルトレンダリングをオーバーライドするカスタムブロックコンポーネント |
sx | SxProps | undefined | カスタムスタイリング用のMUI sxプロパティ |
spacing | number | 3 | 子要素間のスペーシング |
注意: このコンポーネントはMUI StackProps を拡張し、すべてのStackコンポーネントプロパティを継承します。
サブコンポーネント
ListUsersコンポーネントは複数のサブコンポーネントを提供します。すべてのサブコンポーネントは、メインコンポーネントのコンテキストからデフォルト値を受け取り、プロパティを通じてこれらの値をオーバーライドできます。
ListUsers.Title
| プロパティ | 型 | デフォルト | 説明 |
|---|---|---|---|
listUsersTitle | ReactNode | コンテキストから | 表示するタイトルコンテンツ |
children | ReactNode | コンテキストから | デフォルトタイトルレンダリングをオーバーライドするカスタムコンテンツ |
className | string | undefined | スタイリング用の追加CSSクラス名 |
variant | string | "h4" | MUI Typographyバリアント |
component | string | "h1" | レンダリングするHTML要素 |
注意: このコンポーネントはMUI TypographyProps を拡張します。
ListUsers.Header
| プロパティ | 型 | デフォルト | 説明 |
|---|---|---|---|
children | ReactNode | undefined | デフォルトヘッダーレンダリングをオーバーライドするカスタムコンテンツ |
className | string | undefined | スタイリング用の追加CSSクラス名 |
注意: このコンポーネントはMUI BoxProps を拡張します。
ListUsers.Content
| プロパティ | 型 | デフォルト | 説明 |
|---|---|---|---|
isLoading | boolean | コンテキストから | コンテキストからのローディング状態 |
children | ReactNode | undefined | デフォルトコンテンツレンダリングをオーバーライドするカスタムコンテンツ |
className | string | undefined | スタイリング用の追加CSSクラス名 |
注意: このコンポーネントはMUI BoxProps を拡張します。
ListUsers.Loader
| プロパティ | 型 | デフォルト | 説明 |
|---|---|---|---|
children | ReactNode | <CircularProgress /> | カスタムローディングインジケーターコンテンツ |
className | string | undefined | スタイリング用の追加CSSクラス名 |
sx | SxProps | undefined | カスタムスタイリング用のMUI sxプロパティ |
注意: このコンポーネントはデフォルト alignItems: 'center' を持つMUI StackProps を拡張します。
ListUsers.Tabs
| プロパティ | 型 | デフォルト | 説明 |
|---|---|---|---|
tabs | TabData[] | コンテキストから | タブ設定オブジェクトの配列 |
currentTab | string | コンテキストから | 現在アクティブなタブラベル |
onTabChange | (tab: string) => void | コンテキストから | タブ変更コールバック関数 |
className | string | undefined | スタイリング用の追加CSSクラス名 |
注意: このコンポーネントはMUI TabsProps(value、onChange、variant を除く)を拡張します。内部で variant="fullWidth" を使用します。
ListUsers.Table
| プロパティ | 型 | デフォルト | 説明 |
|---|---|---|---|
data | ListUsersRowData[] | コンテキストから | テーブルデータの配列 |
labels | UserLabels | コンテキストから | テーブルヘッダーとステータスメッセージ用のラベル |
rowHref | (row: ListUsersRowData) => string | コンテキストから | 行リンクURLを生成する関数 |
onNavigate | (to: string) => void | コンテキストから | ナビゲーションコールバック関数 |
pagination | PaginationProps | コンテキストから | ページネーション設定 |
className | string | undefined | スタイリング用の追加CSSクラス名 |
spacing | number | 3 | 要素間のスペーシング |
注意: このコンポーネントはMUI StackProps を拡張します。
🎨 設定例
カスタムタイトルスタイリング
<ListUsers.Title
variant="h3"
sx={{
color: 'primary.main',
fontWeight: 'bold',
textTransform: 'uppercase',
}}
>
カスタムユーザータイトル
</ListUsers.Title>
ページネーションセットアップ
<ListUsers
listUsersTitle="ページネーション付きユーザー"
labels={labels}
data={userData}
pagination={{
currentPage: 1,
totalPages: 10,
onPageChange: (page) => console.log('ページ:', page),
}}
/>
カスタム空状態メッセージ
const labels = {
emptyStateMessage: '検索条件に一致するユーザーが見つかりません',
headerRow: {
name: 'フルネーム',
createdAt: '登録日',
status: 'アカウント状態',
},
cellData: {
statusInUse: 'アクティブ',
statusNotInUse: '非アクティブ',
},
};
ブロックオーバーライドパターン
<ListUsers listUsersTitle="ユーザー" labels={labels} data={userData}>
{({defaultBlocks, defaultBlockOrder}) => ({
blocks: {
...defaultBlocks,
header: (
<ListUsers.Header
sx={{
p: 3,
borderBottom: '1px solid #e2e8f0',
'& .nbb-list-users-title': {
fontSize: 24,
fontWeight: 700,
color: '#1e293b',
},
}}
/>
),
tabs: (
<ListUsers.Tabs
sx={{
px: 3,
borderBottom: '1px solid #e2e8f0',
'& .MuiTab-root': {
textTransform: 'none',
fontWeight: 500,
color: '#64748b',
'&.Mui-selected': {
color: '#6366f1',
fontWeight: 600,
},
},
}}
/>
),
table: (
<ListUsers.Table
sx={{
'& .MuiTableHead-root': {
bgcolor: '#f8fafc',
},
}}
/>
),
},
blockOrder: defaultBlockOrder,
})}
</ListUsers>
カスタムスタイリング
<ListUsers
listUsersTitle="ユーザー"
data={users}
isLoading={false}
pagination={pagination}
onNavigate={console.log}
rowHref={row => `/users/${row.id}`}
labels={labels}
sx={{
bgcolor: 'grey.900',
color: 'grey.100',
borderRadius: 2,
}}
>
<ListUsers.Header
sx={{
p: 2,
borderBottom: '1px solid',
borderColor: 'grey.700',
'& .MuiTypography-root': {
color: 'grey.100',
},
}}
/>
<ListUsers.Table
sx={{
'& .MuiTableCell-root': {
color: 'grey.300',
borderColor: 'grey.700',
},
'& .MuiTableHead-root .MuiTableCell-root': {
color: 'grey.400',
bgcolor: 'grey.800',
},
}}
/>
</ListUsers>
サブタイトル付きタブ
const tabs = [
{label: 'アクティブ', subtitle: '(24)'},
{label: '非アクティブ', subtitle: '(8)'},
{label: '保留中', subtitle: '(3)', isDisabled: true},
];
<ListUsers tabs={tabs} currentTab="アクティブ" onTabChange={setTab} /* ... */ />
🔧 TypeScriptサポート
包括的な型定義による完全なTypeScriptサポート:
import {ListUsers} from '@nodeblocks/frontend-list-users-block';
import {useState} from 'react';
interface UserData {
id: string;
name: string;
status: string;
createdAt: string;
}
interface PaginationConfig {
currentPage: number;
totalPages: number;
onPageChange: (page: number) => void;
}
interface TabConfig {
key?: string;
label: string;
isDisabled?: boolean;
subtitle?: string;
}
interface LabelsConfig {
emptyStateMessage: string;
headerRow: {
createdAt: string;
name: string;
status: string;
};
cellData: {
statusInUse: string;
statusNotInUse: string;
};
}
function TypedListUsers() {
const userData: UserData[] = [
{
id: 'u1',
name: '田中太郎',
status: 'in_use',
createdAt: '2023-01-15',
},
{
id: 'u2',
name: '佐藤花子',
status: 'in_use',
createdAt: '2023-02-20',
},
{
id: 'u3',
name: '山田次郎',
status: 'not_in_use',
createdAt: '2023-03-10',
},
];
const paginationConfig: PaginationConfig = {
currentPage: 1,
totalPages: 1,
onPageChange: newPage => console.log('ページが変更されました:', newPage),
};
const tabConfig: TabConfig[] = [
{key: 'all', label: 'すべてのユーザー'},
{key: 'active', label: 'アクティブ'},
{key: 'inactive', label: '非アクティブ'},
];
const labelsConfig: LabelsConfig = {
emptyStateMessage: 'チームメンバーが見つかりません',
headerRow: {
createdAt: '参加日',
name: 'フルネーム',
status: 'ステータス',
},
cellData: {
statusInUse: 'アクティブ',
statusNotInUse: '非アクティブ',
},
};
const handleNavigate = (href: string): void => {
console.log('ナビゲート先:', href);
};
return (
<ListUsers
listUsersTitle="チーム管理"
data={userData}
isLoading={false}
pagination={paginationConfig}
onNavigate={handleNavigate}
rowHref={(row: UserData) => `/users/${row.id}`}
tabs={tabConfig}
currentTab="すべてのユーザー"
onTabChange={tab => console.log('タブが変更されました:', tab)}
labels={labelsConfig}
spacing={2}
sx={{
maxWidth: 1000,
mx: 'auto',
border: '1px solid #e5e7eb',
borderRadius: 2,
}}
>
<ListUsers.Header />
<ListUsers.Tabs />
<ListUsers.Table />
</ListUsers>
);
}
📝 注意事項
- コンポーネントはMUIの
Stackコンポーネントをベースとして使用し、柔軟なレイアウトオプションを提供します - デフォルトスペーシングは
3(24px)、デフォルトパディングはp: 3(24px)です - すべてのサブコンポーネントはメインコンポーネントからコンテキスト値を自動的に受け取ります
- 日付フォーマットは
luxonライブラリを使用し、表示形式はyyyy/M/dです - 完全な日時はホバー時に
title属性で表示されます Tabsコンポーネントは内部でMUIのvariant="fullWidth"を使用します- 空状態はラベルの
emptyStateMessageと人物アイコンを表示します - 行ホバーエフェクトは
rowHrefが提供されている場合のみ適用されます - 行をクリックすると
rowHrefが返すhrefでonNavigateがトリガーされます - デフォルトブロック:
title、header、content、tabs、table - CSSクラスはBEMスタイルの命名に従います:
nbb-list-users-container、nbb-list-users-titleなど LoaderコンポーネントはデフォルトでMUICircularProgressをレンダリングします
React、TypeScript、MUIを使用して❤️で構築されました。