フィルター検索パネルブロック
FilterSearchPanelコンポーネントは、ReactとTypeScriptで構築された、完全にカスタマイズ可能でアクセシブルなフィルタリング機能付き検索インターフェースです。モダンなデザインパターン、フォームバリデーション、柔軟なカスタマイズオプションを備えた、完全な検索・フィルター体験を提供します。
🚀 インストール
npm install @nodeblocks/frontend-filter-search-panel-block
📖 使用方法
import {FilterSearchPanel} from '@nodeblocks/frontend-filter-search-panel-block';
- 基本的な使用方法
- 高度な使用方法
ライブエディター
function BasicFilterSearchPanel() { const [filters, setFilters] = useState([ { label: 'アクティブ', key: 'status-active', groupName: 'ステータス' }, { label: 'ウェブ開発', key: 'category-web', groupName: 'カテゴリー' } ]); const handleRemoveFilter = (filter: FilterChip) => { setFilters(filters.filter(f => f.key !== filter.key)); }; const handleSearch = ({search}: {search: string}) => { console.log('検索が実行されました:', search); setFilters(prev => [...prev, {label: search, key: search, groupName: 'カスタム'}]); }; return ( <FilterSearchPanel filters={filters} onClickRemoveFilter={handleRemoveFilter} onClickFilterButton={() => console.log('フィルターボタンがクリックされました')} onSearch={handleSearch} searchPlaceholder="サービスを検索..." noFilterText="フィルターが適用されていません" filterLabel="フィルター設定"> <FilterSearchPanel.SearchInput /> <FilterSearchPanel.ActionGroup /> </FilterSearchPanel> ); }
結果
Loading...
ライブエディター
function AdvancedFilterSearchPanel() { const [filters, setFilters] = useState([ {label: 'フロントエンド', key: 'tech-frontend', groupName: 'テクノロジー'}, {label: 'React', key: 'framework-react', groupName: 'フレームワーク'}, {label: 'シニア', key: 'level-senior', groupName: 'レベル'}, ]); const [searchHistory, setSearchHistory] = useState(['react 開発者', 'nodejs バックエンド', 'フルスタック エンジニア']); const handleRemoveFilter = (filter: {key: string}) => { setFilters(filters.filter(f => f.key !== filter.key)); }; const handleSearch = ({search}: {search: string}) => { console.log('検索が実行されました:', search); if (search.trim()) { setSearchHistory(prev => [search, ...prev.slice(0, 4)]); setFilters(prev => [...prev, {label: search, key: search, groupName: '検索'}]); } }; return ( <FilterSearchPanel filters={filters} onClickRemoveFilter={handleRemoveFilter} onClickFilterButton={() => console.log('高度なフィルターパネルが開かれました')} onSearch={handleSearch} searchPlaceholder="開発者を検索..." noFilterText="🔍 フィルターが適用されていません - すべての結果を表示中" filterLabel="🎯 高度なフィルター" style={{ background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)', borderRadius: '12px', padding: '24px', boxShadow: '0 8px 32px rgba(0,0,0,0.1)', }} > {({defaultBlocks, defaultBlockOrder}) => { const searchInput = ( <div style={{position: 'relative'}}> {defaultBlocks.searchInput} {searchHistory.length > 0 && ( <div style={{ top: '100%', left: 0, right: 0, background: 'white', borderRadius: '8px', marginTop: '8px', padding: '12px', boxShadow: '0 4px 12px rgba(0,0,0,0.15)', zIndex: 10, }} > <div style={{fontSize: '12px', color: '#666', marginBottom: '8px'}}>📝 最近の検索:</div> {searchHistory.map((term, index) => ( <div key={index} style={{ padding: '4px 8px', fontSize: '14px', color: '#333', cursor: 'pointer', borderRadius: '4px', }} > {term} </div> ))} </div> )} </div> ); const actionGroup = ( <div style={{ background: 'rgba(255,255,255,0.9)', borderRadius: '12px', padding: '16px', marginTop: '16px', }} > {defaultBlocks.actionGroup} </div> ); const searchStats = ( <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '12px 16px', background: 'rgba(255,255,255,0.1)', borderRadius: '8px', marginTop: '12px', color: 'white', }} > <span style={{fontSize: '14px'}}>📊 {filters.length} 個のアクティブフィルター</span> <span style={{fontSize: '14px'}}>🎯 {Math.floor(Math.random() * 150) + 50} 件の結果が見つかりました</span> </div> ); const quickActions = ( <div style={{ display: 'flex', gap: '8px', marginTop: '16px', flexWrap: 'wrap', }} > <button style={{ padding: '8px 16px', background: 'rgba(255,255,255,0.2)', border: 'none', borderRadius: '20px', color: 'white', fontSize: '14px', cursor: 'pointer', transition: 'all 0.3s ease', }} > 🔄 すべてリセット </button> <button style={{ padding: '8px 16px', background: 'rgba(255,255,255,0.2)', border: 'none', borderRadius: '20px', color: 'white', fontSize: '14px', cursor: 'pointer', transition: 'all 0.3s ease', }} > 💾 検索を保存 </button> <button style={{ padding: '8px 16px', background: 'rgba(255,255,255,0.2)', border: 'none', borderRadius: '20px', color: 'white', fontSize: '14px', cursor: 'pointer', transition: 'all 0.3s ease', }} > 🔔 アラートを作成 </button> </div> ); return { blocks: {searchInput, actionGroup, searchStats, quickActions}, blockOrder: ['searchStats', 'quickActions', 'searchInput', 'actionGroup'], }; }} </FilterSearchPanel> ); }
結果
Loading...
🔧 プロパティリファレンス
メインコンポーネントのプロパティ
プロパティ | 型 | デフォルト | 説明 |
---|---|---|---|
filters | FilterChip[] | [] | 表示する現在選択されているフィルターチップの配列 |
defaultSearchValue | string | undefined | 検索入力フィールドのデフォルト値 |
onClickRemoveFilter | (filter: FilterChip) => void | undefined | フィルターチップが削除されたときにトリガーされるコールバック関数 |
onClickFilterButton | () => void | undefined | フィルターボタンがクリックされたときにトリガーされるコールバック関数 |
onSearchChange | (event: HTMLInputElement) => void | undefined | 検索入力値が変更されたときにトリガーされるコールバック関数 |
onSearch | (data: T) => void | undefined | 検索データでフォームが送信されたときにトリガーされるコールバック関数 |
searchPlaceholder | string | undefined | 検索入力フィールドのプレースホルダーテキスト |
noFilterText | string | undefined | フィルターが選択されていないときに表示されるテキスト |
filterLabel | string | undefined | フィルターボタンのラベルテキスト |
className | string | undefined | フォームコンテナのスタイリング用の追加CSSクラス名 |
children | BlocksOverride | undefined | デフォルトレンダリングをオーバーライドするカスタムブロックコンポーネント |
注意: このコンポーネントはHTML form
要素のすべてのプロパティを継承します。
サブコンポーネント
FilterSearchPanelコンポーネントは複数のサブコンポーネントを提供します。すべてのサブコンポーネントは、メインコンポーネントのコンテキストからデフォルト値を受け取り、プロパティを通じてこれらの値をオーバーライドできます。
FilterSearchPanel.SearchInput
プロパティ | 型 | デフォルト | 説明 |
---|---|---|---|
searchPlaceholder | string | コンテキストから | 検索入力に表示されるプレースホルダーテキスト |
onSearchChange | (event: HTMLInputElement) => void | undefined | 入力値が変更されたときにトリガーされるコールバック関数 |
onSearch | () => void | undefined | 検索が実行されたときにトリガーされるコールバック関数 |
defaultSearchValue | string | undefined | 検索入力のデフォルト値 |
className | string | undefined | スタイリング用の追加CSSクラス名 |
注意: このコンポーネントはHTML div
要素のすべてのプロパティを継承します。
FilterSearchPanel.FilterButton
プロパティ | 型 | デフォルト | 説明 |
---|---|---|---|
filterLabel | string | コンテキストから | フィルターボタンに表示されるラベルテキスト |
onClickFilterButton | () => void | コンテキストから | ボタンがクリックされたときにトリガーされるコールバック関数 |
className | string | undefined | スタイリング用の追加CSSクラス名 |
children | ReactNode | コンテキストから | デフォルトレンダリングをオーバーライドするカスタムコンテンツ |
注意: このコンポーネントはHTML button
要素のすべてのプロパティを継承します。
FilterSearchPanel.SelectedFilterList
プロパティ | 型 | デフォルト | 説明 |
---|---|---|---|
filters | FilterChip[] | コンテキストから | 表示するフィルターチップの配列 |
onClickRemoveFilter | (filter: FilterChip) => void | コンテキストから | フィルターが削除されたときにトリガーされるコールバック関数 |
noFilterText | string | コンテキストから | フィルターが選択されていないときに表示されるテキスト |
className | string | undefined | スタイリング用の追加CSSクラス名 |
注意: このコンポーネントはHTML div
要素のすべてのプロパティを継承します。
FilterSearchPanel.FilterBadge
プロパティ | 型 | デフォルト | 説明 |
---|---|---|---|
filter | FilterChip | 必須 | ラベル、キー、グループ名を含むフィルターチップオブジェクト |
onClickRemoveFilter | (filter: FilterChip) => void | 必須 | フィルターが削除されたときにトリガーされるコールバック関数 |
className | string | undefined | スタイリング用の追加CSSクラス名 |
注意: このコンポーネントはHTML div
要素のすべてのプロパティを継承します。
FilterSearchPanel.ActionGroup
プロパティ | 型 | デフォルト | 説明 |
---|---|---|---|
className | string | undefined | スタイリング用の追加CSSクラス名 |
注意: このコンポーネントはHTML div
要素のすべてのプロパティを継承します。
🔧 TypeScript サポート
包括的な型定義による完全なTypeScriptサポート:
import FilterSearchPanel from '@nodeblocks/frontend-filter-search-panel-block';
// フィルターチップの構造
interface FilterChip {
label: string;
key: string;
groupName: string;
}
// デフォルトの検索フォームデータ構造
interface SearchFormData {
search: string;
}
// カスタムフィールドで拡張
interface CustomSearchFormData extends SearchFormData {
category?: string;
status?: string;
customField?: string;
}
const MyFilterSearchPanel = () => {
const [selectedFilters, setSelectedFilters] = useState<FilterChip[]>([
{ label: 'アクティブ', key: 'status-active', groupName: 'ステータス' },
{ label: 'プレミアム', key: 'type-premium', groupName: 'タイプ' }
]);
const handleSearch = (formData: CustomSearchFormData) => {
console.log('検索が実行されました:', formData);
// 検索送信の処理
};
const handleRemoveFilter = (filter: FilterChip) => {
setSelectedFilters(prev => prev.filter(f => f.key !== filter.key));
};
const handleFilterButtonClick = () => {
console.log('フィルターモーダルを開いています');
// フィルターボタンクリックの処理
};
const handleSearchChange = (event: React.ChangeEvent<HTMLInputElement>) => {
console.log('検索値が変更されました:', event.target.value);
// 検索入力変更の処理
};
return (
<FilterSearchPanel<CustomSearchFormData>
filters={selectedFilters}
onSearch={handleSearch}
onClickRemoveFilter={handleRemoveFilter}
onClickFilterButton={handleFilterButtonClick}
onSearchChange={handleSearchChange}
searchPlaceholder="サービスを検索..."
noFilterText="フィルターが適用されていません"
filterLabel="フィルターオプション">
<FilterSearchPanel.SearchInput />
<FilterSearchPanel.ActionGroup />
</FilterSearchPanel>
);
};
React、TypeScript、モダンなウェブ標準を使用して❤️で構築されました。