ナビ行NavRowExperimental

設定画面やマイページで使う、ラベル、説明、現在値、末尾操作を持つ行です。

プレビュー

お支払い

状態とバリエーション

ナビゲーション行

onSelect を渡すと行全体が詳細へ進むボタンになり、既定で chevron が付きます。

お支払い

操作行

trailing に Switch などを渡す場合、行自体はボタンにせず操作対象を分けます。

通知・セキュリティ

配達前プッシュ通知お届け予定をプッシュでお知らせ

状態表示

Badge や値だけを見せる読み取り行にも使えます。

通知・セキュリティ

二段階認証アカウント保護の状態必須有効

プロパティ

表は横にスクロールできます
プロパティ初期値説明
labelReactNode-主ラベルです。
iconReactNode-先頭に置くアイコンです。
descriptionReactNode-ラベル下の補足行です。
valueReactNode-右寄せで表示する現在値です。
trailingReactNode-末尾アクセサリです。未指定で onSelect がある場合は chevron を出します。
opensDialogboolean-行が詳細ダイアログやシートを開く場合に aria-haspopup="dialog" を付けます。
onSelect() => void-行全体をナビゲーション/開示ボタンにします。トグルではないため aria-pressed は使いません。
SettingGroup.labelReactNode-グループ見出しです。
SettingGroup.childrenReactNode-丸角コンテナ内に配置する NavRow 群です。

使い方

import * as React from "react";
import {
  Button,
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
  NavRow,
  SettingGroup,
} from "@gunjo/ui";
import { IconCreditCard, IconMail } from "@tabler/icons-react";

export function BillingRows() {
  const rootRef = React.useRef<HTMLDivElement | null>(null);
  const [portalContainer, setPortalContainer] = React.useState<HTMLElement | null>(null);
  const [detail, setDetail] = React.useState<"payment" | "invoice" | null>(null);

  React.useEffect(() => {
    setPortalContainer(rootRef.current?.closest<HTMLElement>("[data-doc-component-preview-surface]") ?? rootRef.current);
  }, []);

  const detailContent = detail === "invoice"
    ? {
        title: "請求書の送付方法",
        value: "Web(メール通知)",
        description: "毎月の請求書はメール通知つきの Web 配信で送付されます。",
      }
    : {
        title: "お支払い方法",
        value: "口座振替",
        description: "登録済みの口座振替を確認し、必要に応じて変更申請へ進みます。",
      };

  return (
    <div ref={rootRef} className="relative flex w-full max-w-sm flex-col gap-4">
      <SettingGroup label="お支払い">
        <NavRow
          icon={<IconCreditCard className="size-5" />}
          label="お支払い方法"
          value="口座振替"
          opensDialog
          onSelect={() => setDetail("payment")}
        />
        <NavRow
          icon={<IconMail className="size-5" />}
          label="請求書の送付方法"
          description="毎月の請求書をどう受け取るか"
          value="Web(メール通知)"
          opensDialog
          onSelect={() => setDetail("invoice")}
        />
      </SettingGroup>
      <Dialog open={detail !== null} onOpenChange={(open) => !open && setDetail(null)} modal={false}>
        <DialogContent portalContainer={portalContainer} closeLabel="閉じる" className="sm:max-w-sm">
          <DialogHeader>
            <DialogTitle>{detailContent.title}</DialogTitle>
            <DialogDescription>{detailContent.description}</DialogDescription>
          </DialogHeader>
          <div className="rounded-md border bg-muted/30 px-3 py-2 text-sm">
            <span className="text-muted-foreground">現在値</span>
            <span className="mt-1 block font-medium text-foreground">{detailContent.value}</span>
          </div>
          <DialogFooter>
            <Button type="button" size="sm">変更する</Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </div>
  );
}

使用コンポーネント