ViewOrganizationブロック
ViewOrganization は、MUI 上に構築されたキー・バリュー表示ブロックで、枠線付きヘッダー(タイトルと任意のアクションボタン)、任意のサブヘッダーを備えています。
インストール
- npm
- yarn
- pnpm
- bun
npm install @nodeblocks/frontend-view-organization-block
yarn add @nodeblocks/frontend-view-organization-block
pnpm add @nodeblocks/frontend-view-organization-block
bun add @nodeblocks/frontend-view-organization-block
必要なもの
| 項目 | 用途 |
|---|---|
labels.headerTitle | ヘッダーの組織名 |
data | 会社フィールドを Record<string, ReactNode>(行キーがラベルになる)または値のみの行用の ReactNode[] として渡す |
labels.subheaderTitle (任意) | ヘッダー下のセカンダリ行(例: 設立日やタグライン) |
labels.headerActionButton + headerAction (任意) | アウトラインのヘッダーボタンのラベルとクリックハンドラー |
layout (任意) | one-column はキー/バリュー行を縦に積む; two-column は横並びで表示(デフォルト) |
ViewOrganization は組織状態を保持しません — ページから labels、data、任意の headerAction を渡してください。オブジェクト形式の data のキーが行ラベルになり、値は文字列または React ノード(複数行テキスト、リンク、レイアウト)にできます。labels.headerActionButton と headerAction を設定すると、ハンドラー付きのヘッダーアクションボタンが表示されます。
コード例
- クイックスタート
- ラベル
- レイアウト
- 複合コンポーネント
- ブロックのオーバーライド
function Example() { const labels = { headerTitle: 'Co-Lift Inc.', }; const data = { 業種: 'サービス', ウェブサイト: 'https://www.co-lift.com/', 概要: 'Co-Liftは、戦略から開発まで、ビジネス資産をプロダクトのアイデアに変える本質的な視点に焦点を当てています。', 事業重点: 'フルスタックエンジニアリングによるエンドツーエンドのプロダクト開発で、顧客の課題を解決します。', 設立: '2017年9月11日', 経営陣: '木下 寛太、CEO · 定島 螢吾、CEO', }; return <ViewOrganization labels={labels} data={data} />; }
ヘッダーのコピー、サブヘッダー、ヘッダーアクション、行コンテンツ、レイアウトをカスタマイズします。
function Example() { const [lastAction, setLastAction] = React.useState(''); const labels = { headerTitle: 'Co-Lift Inc.', subheaderTitle: '2017年9月11日設立 · 東京都', headerActionButton: '組織を編集', }; const data = { 本社: '東京都渋谷区代々木5丁目604 151-0053', 電話: '03-6821-0661', ウェブサイト: ( <Typography component="a" href="https://www.co-lift.com/" target="_blank" rel="noopener noreferrer" variant="body2" sx={{ color: 'primary.main', fontWeight: 600, textDecoration: 'none', '&:hover': { textDecoration: 'underline' } }} > www.co-lift.com </Typography> ), 業種: 'サービス', 従業員: '6', 概要: 'プロダクトとビジネスイノベーションのための戦略から開発までのパートナー。', }; return ( <Box> <ViewOrganization labels={labels} data={data} layout="two-column" headerAction={() => setLastAction('組織を編集')} /> {lastAction ? ( <Typography variant="caption" color="text.secondary" sx={{ display: 'block', mt: 1 }}> 最後のアクション: {lastAction} </Typography> ) : null} </Box> ); }
headerTitle、subheaderTitle、headerActionButton はルートの labels オブジェクト(または複合レイアウトでは ViewOrganization.Header / ViewOrganization.HeaderActionButton)に設定します。行ラベルは data オブジェクトのキーから取得されます。
レイアウトを切り替えてみてください。
function Example() { const [layout, setLayout] = React.useState('two-column'); const labels = { headerTitle: 'Co-Lift Inc.', subheaderTitle: '2017年9月11日設立', }; const data = { 本社: '東京都渋谷区', 電話: '03-6821-0661', 業種: 'サービス', 従業員: '6', ウェブサイト: 'https://www.co-lift.com/', 設立: '2017年9月11日', }; return ( <Box> <Box sx={{ display: 'flex', gap: 1, mb: 2 }}> <Box component="button" type="button" onClick={() => setLayout('two-column')} sx={{ px: 1.5, py: 0.75, borderRadius: 1, border: '1px solid', borderColor: layout === 'two-column' ? 'primary.main' : 'divider', bgcolor: layout === 'two-column' ? 'primary.main' : 'background.paper', color: layout === 'two-column' ? 'primary.contrastText' : 'text.primary', cursor: 'pointer', fontSize: 14, fontWeight: layout === 'two-column' ? 600 : 400, }} > 2列 </Box> <Box component="button" type="button" onClick={() => setLayout('one-column')} sx={{ px: 1.5, py: 0.75, borderRadius: 1, border: '1px solid', borderColor: layout === 'one-column' ? 'primary.main' : 'divider', bgcolor: layout === 'one-column' ? 'primary.main' : 'background.paper', color: layout === 'one-column' ? 'primary.contrastText' : 'text.primary', cursor: 'pointer', fontSize: 14, fontWeight: layout === 'one-column' ? 600 : 400, }} > 1列 </Box> </Box> <ViewOrganization labels={labels} data={data} layout={layout} /> </Box> ); }
two-column(デフォルト)は各フィールドのラベルと値を横並びで表示します。one-column はラベルを値の上に積み、余白を広げます — 狭いビューポートや情報量の多い会社プロフィールに適しています。
ViewOrganization.Header、ViewOrganization.Subheader、ViewOrganization.ItemList を直接構成します。ルートだけでなく子コンポーネントにも labels と headerAction を渡します; data はルートの ViewOrganization に保持します。
function Example() { const [lastAction, setLastAction] = React.useState(''); const data = { 本社: '東京都渋谷区', 電話: '03-6821-0661', 業種: 'サービス', 従業員: '6', ウェブサイト: 'https://www.co-lift.com/', }; return ( <Box> <ViewOrganization layout="two-column"> <ViewOrganization.Header labels={{ headerTitle: 'Co-Lift Inc.', headerActionButton: '組織を編集', }} headerAction={() => setLastAction('組織を編集')} sx={{ px: 2, py: 1.5, bgcolor: 'grey.50', borderRadius: 2, border: '1px solid', borderColor: 'divider', }} /> <ViewOrganization.Subheader labels={{ subheaderTitle: '2017年9月11日設立' }} sx={{ px: 2, fontStyle: 'italic', color: 'text.secondary' }} /> <ViewOrganization.ItemList data={data} sx={{ border: '1px solid', borderColor: 'divider', borderRadius: 2, overflow: 'hidden', '& .MuiListItem-root': { bgcolor: 'background.paper' }, }} /> </ViewOrganization> {lastAction ? ( <Typography variant="caption" color="text.secondary" sx={{ display: 'block', mt: 1 }}> 最後のアクション: {lastAction} </Typography> ) : null} </Box> ); }
defaultBlocks と defaultBlockOrder を使う関数の children で、ブロックの注入、デフォルトの差し替え、順序の制御を行います。
function Example() { const [noticeVisible, setNoticeVisible] = React.useState(true); const labels = { headerTitle: 'Co-Lift Inc.', subheaderTitle: 'プロフィール審査中', }; const data = { 本社: '東京都渋谷区', 電話: '03-6821-0661', 業種: 'サービス', 従業員: '6', }; return ( <ViewOrganization labels={labels} data={data}> {({ defaultBlocks, defaultBlockOrder }) => ({ blocks: { ...defaultBlocks, orgNotice: noticeVisible ? ( <Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 2, px: 2, py: 1.5, mb: 1, borderRadius: 2, bgcolor: 'info.main', color: 'info.contrastText', }} > <Typography variant="body2" sx={{ fontWeight: 600 }}> 組織詳細が最近更新されました </Typography> <Box component="button" type="button" onClick={() => setNoticeVisible(false)} aria-label="通知を閉じる" sx={{ flexShrink: 0, border: '1px solid rgba(255,255,255,0.35)', bgcolor: 'rgba(255,255,255,0.12)', color: 'inherit', borderRadius: '50%', width: 28, height: 28, cursor: 'pointer', fontSize: 16, lineHeight: 1, }} > × </Box> </Box> ) : null, header: ( <ViewOrganization.Header labels={labels} sx={{ px: 2, py: 2, borderRadius: 2, border: '1px solid', borderColor: 'divider', bgcolor: 'background.paper', }} /> ), itemList: ( <ViewOrganization.ItemList data={data} sx={{ mt: 2, border: '1px solid', borderColor: 'divider', borderRadius: 2, '& .MuiListItem-root:nth-of-type(even)': { bgcolor: 'grey.50' }, }} /> ), }, blockOrder: [ ...(noticeVisible ? ['orgNotice'] : []), 'header', 'subheader', 'itemList', ], })} </ViewOrganization> ); }
ブロックのオーバーライドを使うタイミング
デフォルトの defaultBlockOrder は header、subheader、itemList、item、itemKey、itemValue です。デフォルトのレンダーは itemList で data をマッピングします。個別の item / itemKey / itemValue エントリは、きめ細かなオーバーライド用です。この例では、閉じられる orgNotice を先頭に追加し、header と itemList をスタイル付きバリアントに差し替え、未使用のブロックキーを blockOrder から除外しています。
主要プロパティ
コアプロパティ
| プロパティ | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
data | Record<string, ReactNode> | ReactNode[] | いいえ | undefined | 行コンテンツ: オブジェクトのキーがフィールドラベルになる; 配列は値のみの行をレンダリング |
labels | { headerTitle?: string; headerActionButton?: string; subheaderTitle?: string } | いいえ | undefined | ヘッダータイトル、任意のアクションボタンラベル、サブヘッダーのテキスト |
コンテンツプロパティ
| プロパティ | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
labels.headerTitle | string | いいえ | undefined | ViewOrganization.Header のメイン見出し |
labels.subheaderTitle | string | いいえ | undefined | ヘッダー下のセカンダリ行(ViewOrganization.Subheader) |
labels.headerActionButton | string | いいえ | undefined | アウトラインのヘッダーボタンのラベル; labels.headerActionButton または headerAction が設定されている場合(または ViewOrganization.HeaderActionButton に渡されている場合)に表示 |
headerAction | () => void | いいえ | undefined | デフォルトのヘッダーアクションボタンがクリックされたときに呼び出される(ボタンの onClick の後) |
layout | 'one-column' | 'two-column' | いいえ | 'two-column' | 行レイアウト: キー/バリューを縦に積む vs 横並びの列 |
レイアウトと構成プロパティ
| プロパティ | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
children | BlocksOverride | ReactNode | いいえ | undefined | 複合 JSX の子、または blocks と blockOrder を返す関数オーバーライド |
className | string | いいえ | undefined | ルートスタックのクラス名(nbb-view-organization) |
sx | SxProps | いいえ | undefined | ルートスタック用の MUI システムスタイル(デフォルトレンダーには margin: 'auto' を含む) |
ViewOrganization は StackProps(children を除く)を継承します。デフォルトの defaultBlockOrder: header、subheader、itemList、item、itemKey、itemValue。
サブコンポーネントのプロパティ
サブコンポーネントはコンテキストから読み取り、同じコンテンツキーをプロパティとして渡すとローカルで上書きできます。
| サブコンポーネント | 主要プロパティ | 継承 | ベース |
|---|---|---|---|
ViewOrganization.Header | labels(headerTitle、headerActionButton)、headerAction、children、className、sx | StackProps | Stack + Typography + 任意の ViewOrganization.HeaderActionButton |
ViewOrganization.HeaderActionButton | labels(headerActionButton)、headerAction、children、className、onClick | ButtonProps | Button(variant="outlined"、size="medium") |
ViewOrganization.Subheader | labels(subheaderTitle、headerTitle、headerActionButton)、children、className、sx | StackProps | Stack + Typography |
ViewOrganization.ItemList | data、children、className、sx | ListProps | List(component="dl")+ ViewOrganization.Item 行 |
ViewOrganization.Item | layout、children、className、sx | ListItemProps | ListItem |
ViewOrganization.Item.Key | layout、children、className、sx | TypographyProps | Typography(component="dt"、variant="subtitle1") |
ViewOrganization.Item.Value | layout、children、className、sx | TypographyProps | Typography(component="dd"、variant="body2") |
デフォルト UI ブロック
| ブロック | ベース | 備考 |
|---|---|---|
ViewOrganization(ルート) | Stack | spacing={3}、margin: 'auto' の縦レイアウト(nbb-view-organization) |
header(ViewOrganization.Header) | Stack | labels.headerTitle、labels.headerActionButton、またはカスタム children が設定されている場合にレンダリング; デフォルトスタイルは下枠線、py: 3、mb: 3 を追加; headerAction または labels.headerActionButton が設定されている場合は ViewOrganization.HeaderActionButton を含む |
subheader(ViewOrganization.Subheader) | Stack | labels.subheaderTitle またはカスタム children が設定されている場合にレンダリング |
itemList(ViewOrganization.ItemList) | List | data オブジェクトのエントリまたは配列の値をキー/バリュー行にマッピング |
デフォルトのルートレンダリング順序: header → subheader → itemList。
TypeScript
import * as React from 'react';
import { ViewOrganization } from '@nodeblocks/frontend-view-organization-block';
import type { ReactNode } from 'react';
type OrganizationLabels = {
headerTitle?: string;
headerActionButton?: string;
subheaderTitle?: string;
};
type OrganizationData = Record<string, ReactNode>;
export function OrganizationDetailView() {
const labels: OrganizationLabels = {
headerTitle: 'Co-Lift Inc.',
subheaderTitle: '2017年9月11日設立',
headerActionButton: '組織を編集',
};
const data: OrganizationData = {
本社: '東京都渋谷区',
電話: '03-6821-0661',
業種: 'サービス',
ウェブサイト: 'https://www.co-lift.com/',
};
return (
<ViewOrganization
labels={labels}
data={data}
headerAction={() => {
/* 遷移または編集ダイアログを開く */
}}
/>
);
}