Notificationsブロック
Notifications は、MUI 上に構築された通知パネルです。
インストール
- npm
- yarn
- pnpm
- bun
npm install @nodeblocks/frontend-notifications-block
yarn add @nodeblocks/frontend-notifications-block
pnpm add @nodeblocks/frontend-notifications-block
bun add @nodeblocks/frontend-notifications-block
必要なもの
| 項目 | 用途 |
|---|---|
isNotificationsOpen | ポップオーバーパネルが開いているかどうかを制御する |
setIsNotificationsOpen | パネルを閉じる(例: 外側クリック時) |
notificationsList | パネルにレンダリングする通知項目の配列 |
onClick | ベルボタンのクリックを処理する(通常は開閉状態を切り替える) |
unreadCount (任意) | ベルボタンのバッジ件数を制御する |
heading (任意) | リストの上に表示するパネル見出し |
emptyStateMessage (任意) | リストが空のときに表示する文言 |
Notifications はパネルの開閉状態を所有しません。アプリ側で isNotificationsOpen を保持し、setIsNotificationsOpen を渡してポップオーバーが正しく閉じられるようにしてください。
notificationsList の各項目は次をサポートします:
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
title | string | はい | 通知見出し |
createdAt | string | はい | 相対時間表示に使用する ISO 日付文字列 |
text | ReactNode | いいえ | 任意の本文 |
href | string | いいえ | 設定すると、項目がリンクとしてレンダリングされる |
icon | Partial<AvatarProps> & { isLoading?: boolean } | いいえ | アバター画像、イニシャル、または読み込みプレースホルダー |
コード例
- クイックスタート
- 空の状態
- 複合コンポーネント
- ブロックのオーバーライド
function Example() { const [isNotificationsOpen, setIsNotificationsOpen] = React.useState(false); const [unreadCount, setUnreadCount] = React.useState(10); const notificationsList = [ { title: 'メールアドレスを更新しました', text: 'メールアドレスが正常に更新されました。', createdAt: new Date().toISOString(), href: '/settings', }, { icon: {children: 'G'}, title: '注文を発送しました', text: '注文 #2847 を発送しました。', href: '/orders', createdAt: new Date(Date.now() - 86400000).toISOString(), }, ]; return ( <Notifications isNotificationsOpen={isNotificationsOpen} setIsNotificationsOpen={setIsNotificationsOpen} notificationsList={notificationsList} unreadCount={unreadCount} onClick={() => { setUnreadCount(0); setIsNotificationsOpen(!isNotificationsOpen); }} /> ); }
空のリストでパネルを開きます。emptyStateMessage でメッセージをカスタマイズします。
function Example() { const [isNotificationsOpen, setIsNotificationsOpen] = React.useState(false); return ( <Notifications isNotificationsOpen={isNotificationsOpen} setIsNotificationsOpen={setIsNotificationsOpen} notificationsList={[]} heading="更新" emptyStateMessage="すべて確認済みです" unreadCount={0} onClick={() => setIsNotificationsOpen(!isNotificationsOpen)} /> ); }
子ブロックを使ってトリガーとパネルをカスタマイズします。ルートではなくサブコンポーネントにコンテンツを渡します。
function Example() { const [isNotificationsOpen, setIsNotificationsOpen] = React.useState(false); const [unreadCount, setUnreadCount] = React.useState(5); const notificationsList = [ { title: '新しいメッセージ', text: 'チームから新しいメッセージがあります。', createdAt: new Date().toISOString(), href: '#messages', }, ]; return ( <Notifications isNotificationsOpen={isNotificationsOpen} setIsNotificationsOpen={setIsNotificationsOpen} notificationsList={notificationsList} onClick={() => { setUnreadCount(0); setIsNotificationsOpen(!isNotificationsOpen); }} unreadCount={unreadCount} > <Notifications.Button /> <Notifications.List heading="アラート" emptyStateMessage="アラートはまだありません" /> </Notifications> ); }
関数の children を使ってデフォルトブロックと表示順序をオーバーライドします。
function Example() { const [isNotificationsOpen, setIsNotificationsOpen] = React.useState(false); const [unreadCount, setUnreadCount] = React.useState(25); const notificationsList = [ { title: 'ドキュメントが共有されました', text: 'ドキュメントが共有されました。', createdAt: new Date().toISOString(), }, ]; return ( <Notifications isNotificationsOpen={isNotificationsOpen} setIsNotificationsOpen={setIsNotificationsOpen} notificationsList={notificationsList} sx={{alignItems: 'flex-end'}} onClick={() => { setUnreadCount(0); setIsNotificationsOpen(!isNotificationsOpen); }} unreadCount={unreadCount} > {({defaultBlocks, defaultBlockOrder}) => ({ blocks: { ...defaultBlocks, banner: ( <div style={{display: 'flex', flexDirection: 'column', alignItems: 'flex-end'}}> <div style={{position: 'relative', display: 'inline-flex', marginBottom: 10}}> <div style={{ background: '#eef4ff', border: '1px solid #cddcff', borderRadius: '8px', padding: '8px 12px', fontSize: '14px', }} > ここで更新を確認してください </div> <div style={{ position: 'absolute', bottom: -5, right: 14, width: 10, height: 10, background: '#eef4ff', borderRight: '1px solid #cddcff', borderBottom: '1px solid #cddcff', transform: 'rotate(45deg)', }} /> </div> <div style={{marginRight: 10}}>{defaultBlocks.button}</div> </div> ), button: <></>, }, blockOrder: ['banner', ...defaultBlockOrder.filter(key => key !== 'button')], })} </Notifications> ); }
ブロックのオーバーライドを使うタイミング
ブロックの表示順序を変更したり、デフォルトのベルボタンやパネルを差し替えたり、カスタムコンテンツを挿入する必要がある場合にオーバーライドを使います。
主要プロパティ
コアプロパティ
| プロパティ | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
isNotificationsOpen | boolean | はい | - | 通知ポップオーバーが開いているかどうか |
setIsNotificationsOpen | (open: boolean) => void | はい | - | 開閉状態を更新する。外側クリックで閉じるために必要 |
onClick | React.MouseEventHandler<HTMLButtonElement> | はい | - | ベルボタンのクリックハンドラー。通常は開閉状態を切り替える |
notificationsList | NotificationItem[] | はい | - | パネルにレンダリングする項目(上記の形状を参照) |
unreadCount | number | いいえ | undefined | ベルボタンのバッジ件数。50 を超える値は 50+ と表示される |
コンテンツプロパティ
| プロパティ | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
heading | string | いいえ | 'Notifications' | リストの上に表示するパネル見出し |
emptyStateMessage | string | いいえ | 'No notifications' | リストが空のときに表示するメッセージ |
isLoading | boolean | いいえ | undefined | true のとき、リスト項目の代わりにローダーを表示する |
レイアウトと構成プロパティ
| プロパティ | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
anchorEl | HTMLElement | null | いいえ | 内部状態 | ポップオーバーの位置決め用アンカー要素 |
setAnchorEl | (el: HTMLElement | null) => void | いいえ | 内部 setter | ポップオーバーのアンカー要素を更新する |
children | BlocksOverride | ReactNode | いいえ | undefined | 複合サブコンポーネント、またはブロックオーバーライド関数 |
className | string | いいえ | undefined | ルートコンテナのクラス名(nbb-notifications も適用されます) |
sx | SxProps | いいえ | undefined | ルート Stack 用の MUI システムスタイル |
Notifications は StackProps(children を除く)を継承するため、ルートでは標準のレイアウトプロパティをサポートします。デフォルトのブロック順序は button → list です。listItem と loader は Notifications.List 内で内部的に使用されるデフォルトブロックです。
サブコンポーネントはコンテキストから値を読み取り、MUI プロパティの一部を受け取れます:
Notifications.Button—IconButtonのプロパティ。デフォルトはBadgeでNotificationsOutlinedをラップNotifications.List—StackPropsに加え、任意のheading、emptyStateMessage、isLoading、formatRelativeDateTextNotifications.ListItem—StackPropsに加え、title、createdAt、任意のtext、href、icon、formatRelativeDateTextNotifications.Loader—StackProps。デフォルトはCircularProgress
formatRelativeDateText のデフォルトは、date-fns による ISO 日付の解析と日本語ロケールを使用し、今日作成された通知には 今日 を返します。日付が別の形式またはロケールを使用する場合は、Notifications.List または Notifications.ListItem にカスタムフォーマッターを渡してください。
デフォルト UI ブロック
| ブロック | ベース | 備考 |
|---|---|---|
Notifications (ルート) | Stack rendered as aside | トリガーボタンとポップオーバーリスト用のインラインラッパー |
Notifications.Button | IconButton + Badge | 未読件数バッジ付きのベルアイコン |
Notifications.List | Popover + Typography | 見出し、区切り線、空の状態、読み込み状態を備えたスクロール可能なパネル |
Notifications.ListItem | Stack + Avatar + Typography | href が設定されている場合はアンカーとしてレンダリングされる |
Notifications.Loader | Stack + CircularProgress | isLoading が true のときに表示される中央配置のスピナー |
TypeScript
import {Notifications} from '@nodeblocks/frontend-notifications-block';
import type {ComponentProps} from 'react';
type NotificationsProps = ComponentProps<typeof Notifications>;
type NotificationItem = NotificationsProps['notificationsList'][number];
function ActivityNotifications({items, unreadCount}: {items: NotificationItem[]; unreadCount: number}) {
const [isOpen, setIsOpen] = React.useState(false);
return (
<Notifications
isNotificationsOpen={isOpen}
setIsNotificationsOpen={setIsOpen}
notificationsList={items}
heading="アクティビティ"
unreadCount={unreadCount}
onClick={() => setIsOpen(prev => !prev)}
/>
);
}