招待リストブロック
ListInvitesコンポーネントは、ReactとTypeScriptで構築された完全にカスタマイズ可能でアクセシブルな招待管理インターフェースです。モダンなデザインパターン、アクションドロップダウン、ページネーションサポート、ローディング状態、および高度な招待管理アプリケーション向けの柔軟なカスタマイズオプションを備えた完全な表形式招待リスト体験を提供します。
🚀 インストール
npm install @nodeblocks/frontend-list-invites-block
📖 使用方法
import {ListInvites} from '@nodeblocks/frontend-list-invites-block';
- 基本的な使用方法
- 高度な使用方法
ライブエディター
function BasicListInvites() { const [isLoading, setIsLoading] = useState(false); const inviteData = [ { id: '1', name: '田中太郎', email: 'tanaka.taro@example.com', status: 'pending' }, { id: '2', name: '佐藤花子', email: 'sato.hanako@example.com', status: 'accepted' }, { id: '3', name: '鈴木次郎', email: 'suzuki.jiro@example.com', status: 'expired' } ]; const labels = { emptyStateMessage: '招待が見つかりません', actions: { inviteUser: 'ユーザーを招待' }, headerRow: { name: '名前', email: 'メールアドレス', status: 'ステータス' }, rowActions: { reject: '招待を拒否' }, unsetDateMessage: '日付未設定' }; const handleItemReject = (inviteId) => { console.log('招待を拒否:', inviteId); }; const handleClickAction = () => { console.log('ユーザーを招待がクリックされました'); }; const handleNavigate = (path) => { console.log('ナビゲート先:', path); }; const getRowHref = (row) => `/invites/${row.id}`; return ( <ListInvites listInvitesTitle="招待管理" labels={labels} isLoading={isLoading} onNavigate={handleNavigate} onClickAction={handleClickAction} onItemReject={handleItemReject} data={inviteData} rowHref={getRowHref}> <ListInvites.Header style={{display: 'flex', justifyContent: 'space-between', padding: '16px'}}> <ListInvites.Title /> <ListInvites.Action /> </ListInvites.Header> <ListInvites.Content> {isLoading ? ( <ListInvites.Loader /> ) : ( <ListInvites.Table /> )} </ListInvites.Content> </ListInvites> ); }
結果
Loading...
ライブエディター
function AdvancedListInvites() { const [isLoading, setIsLoading] = useState(false); const inviteData = [ { id: '1', name: '田中太郎', email: 'tanaka.taro@company.jp', status: '承認待ち' }, { id: '2', name: '佐藤花子', email: 'sato.hanako@company.jp', status: '承認済み' }, { id: '3', name: '鈴木次郎', email: 'suzuki.jiro@company.jp', status: '期限切れ' }, { id: '4', name: 'ロバート・ジョンソン', email: 'robert.johnson@global.com', status: '拒否済み' } ]; const labels = { emptyStateMessage: '招待状が見つかりません', actions: { inviteUser: '新しいメンバーを招待' }, headerRow: { name: '氏名', email: 'メールアドレス', status: 'ステータス' }, rowActions: { reject: '招待を取り消し' }, unsetDateMessage: '日付未設定' }; const handleItemReject = (inviteId) => { console.log('招待を拒否:', inviteId); }; const handleClickAction = () => { console.log('新しいメンバーを招待'); }; const handleNavigate = (path) => { console.log('ナビゲート:', path); }; const getRowHref = (row) => `/invites/${row.id}`; return ( <ListInvites listInvitesTitle="👥 チーム招待管理" labels={labels} isLoading={isLoading} onNavigate={handleNavigate} onClickAction={handleClickAction} onItemReject={handleItemReject} data={inviteData} rowHref={getRowHref} style={{ background: 'linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%)', borderRadius: '24px', padding: '24px', margin: '20px', boxShadow: '0 20px 60px rgba(0,0,0,0.12)', border: '1px solid rgba(255,255,255,0.3)' }}> {({ defaultBlocks, defaultBlockOrder }) => ({ blocks: { // モダンスタイリングで強化されたヘッダー header: { ...defaultBlocks.header, props: { ...defaultBlocks.header.props, style: { background: 'rgba(255, 255, 255, 0.8)', borderRadius: '16px', padding: '24px', marginBottom: '24px', backdropFilter: 'blur(10px)', border: '1px solid rgba(255,255,255,0.4)', boxShadow: '0 8px 32px rgba(0,0,0,0.08)', display: 'flex', justifyContent: 'space-between', alignItems: 'center' } } }, // グラデーションスタイリングで強化されたタイトル title: { ...defaultBlocks.title, props: { ...defaultBlocks.title.props, style: { background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)', WebkitBackgroundClip: 'text', WebkitTextFillColor: 'transparent', fontSize: window.innerWidth <= 800 ? '24px' : '32px', fontWeight: 'bold', margin: '0' } } }, // 強化されたアクションボタン action: { ...defaultBlocks.action, props: { ...defaultBlocks.action.props, style: { display: 'flex', alignItems: 'center', gap: '12px' }, children: ( <button onClick={handleClickAction} style={{ background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)', border: 'none', borderRadius: '12px', padding: '12px 24px', color: 'white', fontSize: '14px', fontWeight: 'bold', cursor: 'pointer', transition: 'all 0.3s ease', boxShadow: '0 4px 16px rgba(102, 126, 234, 0.3)', display: 'flex', alignItems: 'center', gap: '8px' }} onMouseOver={(e) => { e.target.style.transform = 'translateY(-2px)'; e.target.style.boxShadow = '0 8px 24px rgba(102, 126, 234, 0.4)'; }} onMouseOut={(e) => { e.target.style.transform = 'translateY(0)'; e.target.style.boxShadow = '0 4px 16px rgba(102, 126, 234, 0.3)'; }}> <span style={{ fontSize: '16px' }}>➕</span> {labels.actions.inviteUser} </button> ) } }, // 強化されたコンテンツコンテナ content: { ...defaultBlocks.content, props: { ...defaultBlocks.content.props, style: { background: 'rgba(255, 255, 255, 0.9)', borderRadius: '20px', padding: '0', backdropFilter: 'blur(10px)', border: '1px solid rgba(255,255,255,0.4)', boxShadow: '0 8px 32px rgba(0,0,0,0.08)', overflow: 'hidden' } } }, // プロフェッショナルスタイリングで強化されたテーブル table: { ...defaultBlocks.table, props: { ...defaultBlocks.table.props, style: { borderRadius: '20px', overflow: 'hidden', boxShadow: '0 4px 20px rgba(0,0,0,0.08)' } } } }, blockOrder: defaultBlockOrder })} </ListInvites> ); }
結果
Loading...
🔧 プロパティリファレンス
メインコンポーネントのプロパティ
プロパティ | 型 | デフォルト | 説明 |
---|---|---|---|
listInvitesTitle | ReactNode | 必須 | 招待セクションのタイトル |
labels | TableLabels | 必須 | テーブルヘッダー、アクション、メッセージのラベルオブジェクト |
isLoading | boolean | undefined | テーブルが現在読み込み中かどうか |
onNavigate | (to: string) => void | 必須 | ナビゲーション用のコールバック関数 |
onClickAction | () => void | 必須 | メインアクションボタンのコールバック関数 |
onItemReject | (inviteId: string) => void | 必須 | 招待が拒否されたときのコールバック関数 |
data | ListInvitesRowData[] | 必須 | 招待データオブジェクトの配列 |
rowHref | (row: ListInvitesRowData) => string | 必須 | 行リンクURLを生成する関数 |
pagination | {currentPage: number; onPageChange: (page: number) => void; totalPages: number} | コンテキストから | ページネーション設定 |
className | string | undefined | コンテナスタイリング用の追加CSSクラス名 |
children | BlocksOverride | undefined | デフォルトレンダリングをオーバーライドするカスタムブロックコンポーネント |
注意: このコンポーネントはすべてのHTML div
要素プロパティを継承します。
サブコンポーネント
ListInvitesコンポーネントは複数のサブコンポーネントを提供します。すべてのサブコンポーネントは、メインコンポーネントのコンテキストからデフォルト値を受け取り、プロパティを通じてこれらの値をオーバーライドできます。
ListInvites.Header
プロパティ | 型 | デフォルト | 説明 |
---|---|---|---|
children | ReactNode | undefined | デフォルトヘッダーレンダリングをオーバーライドするカスタムコンテンツ |
className | string | undefined | スタイリング用の追加CSSクラス名 |
注意: このコンポーネントはすべてのHTML div
要素プロパティを継承します。
ListInvites.Title
プロパティ | 型 | デフォルト | 説明 |
---|---|---|---|
children | ReactNode | undefined | デフォルトタイトルレンダリングをオーバーライドするカスタムコンテンツ |
size | enum | "3XL" | タイトルのタイポグラフィサイズ |
weight | enum | "bold" | タイポグラフィの太さ |
type | enum | "heading" | タイポグラフィタイプ |
color | enum | "low-emphasis" | タイトルのカラーテーマ |
className | string | undefined | スタイリング用の追加CSSクラス名 |
注意: このコンポーネントはすべてのHTML span
要素プロパティを継承します。
ListInvites.Action
プロパティ | 型 | デフォルト | 説明 |
---|---|---|---|
children | ReactNode | undefined | デフォルトアクションレンダリングをオーバーライドするカスタムコンテンツ |
direction | enum | "row" | アクションボタンのフレックス方向 |
alignItems | enum | "stretch" | コンテナ内のアイテムの整列 |
gapSize | enum | "S" | コンテナ内のアイテム間のギャップ |
className | string | undefined | スタイリング用の追加CSSクラス名 |
ListInvites.Content
プロパティ | 型 | デフォルト | 説明 |
---|---|---|---|
children | ReactNode | undefined | デフォルトコンテンツレンダリングをオーバーライドするカスタムコンテンツ |
className | string | undefined | スタイリング用の追加CSSクラス名 |
注意: このコンポーネントはすべてのHTML div
要素プロパティを継承します。
ListInvites.Loader
プロパティ | 型 | デフォルト | 説明 |
---|---|---|---|
children | ReactNode | 円形プログレスインジケーター | カスタムローディングインジケーターコンテンツ |
className | string | undefined | スタイリング用の追加CSSクラス名 |
注意: このコンポーネントはすべてのHTML div
要素プロパティを継承します。
ListInvites.Table
プロパティ | 型 | デフォルト | 説明 |
---|---|---|---|
className | string | undefined | スタイリング用の追加CSSクラス名 |
data | ListInvitesRowData[] | コンテキストから | テーブルデータの配列 |
labels | TableLabels | 必須 | テーブルヘッダー、アクション、メッセージのラベルオブジェクト |
dropdownMenuItems | (cell: ListInvitesRowData) => Array<DropDownMenuItems> | コンテキストから | ドロップダウンメニューアイテムを生成する関数 |
dropdownMenuState | {openedDropdownMenuId: string} | コンテキストから | 現在開かれているドロップダウンメニュー |
setDropdownMenuState | ({openedDropdownMenuId: string}) => void | コンテキストから | 開かれたドロップダウンメニューが変更されたときのコールバック関数 |
emptyState | {icon?: IconType; message: string} | コンテキストから | 空状態の設定 |
isLoading | boolean | コンテキストから | ローディング状態 |
onNavigate | (to: string) => void | コンテキストから | ナビゲーションコールバック関数 |
pagination | {currentPage: number; onPageChange: (page: number) => void; totalPages: number} | コンテキストから | ページネーション設定 |
rowHref | `(cell: ListInvitesRowData) => string | undefined | null` |
🔧 TypeScript サポート
包括的な型定義による完全なTypeScriptサポート:
import {ListInvites} from '@nodeblocks/frontend-list-invites-block';
interface ListInvitesRowData {
id: string;
name: string;
email: string;
status: string;
}
interface CustomInviteTableProps {
invites: ListInvitesRowData[];
onRejectInvite: (inviteId: string) => void;
onInviteUser: () => void;
isTableLoading: boolean;
}
interface TableLabels {
emptyStateMessage: string;
actions: {
inviteUser: string;
};
headerRow: {
name: string;
email: string;
status: string;
};
rowActions: {
reject: string;
};
unsetDateMessage: string;
}
const InviteTableComponent = ({invites, onRejectInvite, onInviteUser, isTableLoading}: CustomInviteTableProps) => {
const tableLabels: TableLabels = {
emptyStateMessage: '利用可能な招待がありません',
actions: {inviteUser: '招待を送信'},
headerRow: {
name: '氏名',
email: 'メールアドレス',
status: '招待ステータス',
},
rowActions: {
reject: '招待を拒否',
},
unsetDateMessage: '日付未設定',
};
return (
<ListInvites
listInvitesTitle="チーム招待"
labels={tableLabels}
isLoading={isTableLoading}
onNavigate={path => console.log('ナビゲート:', path)}
onClickAction={onInviteUser}
onItemReject={onRejectInvite}
data={invites}
rowHref={row => `/invites/${row.id}`}>
<ListInvites.Header />
<ListInvites.Content />
</ListInvites>
);
};
React、TypeScript、モダンなウェブ標準を使用して❤️で構築されました。