安全バナーSafetyBannerExperimental

重要な警告や安全確認を強調し、必要に応じて明示的な確認状態を管理します。

プレビュー

状態とバリエーション

確認必須

確認前は関連操作を無効にし、理由をツールチップで示します。

確認済み

確認済み状態では後続操作を有効にし、押下後は完了状態とトーストを表示します。

注意

確認は求めず、注意喚起に関連する記録操作をその場で完了できます。

投与量を再確認

前回投与からの間隔が短いため、投与量と時間を確認してください。

情報

補足情報はpoliteなstatusとして通知し、関連情報を開く操作を添えます。

情報共有:検査結果待ち

最終判断前に検査結果の更新を確認してください。

プロパティ

表は横にスクロールできます
プロパティ初期値説明
titleReactNode-警告や確認事項の見出しです。
tone"destructive" | "warning" | "info""destructive"重要度です。destructiveはrole=alert、warning/infoはrole=statusです。
requireAckbooleanfalse明示的な確認ボタンを表示します。
acknowledged / defaultAcknowledgedboolean-controlled / uncontrolled の確認状態です。
onAcknowledge() => void-確認ボタン押下時に呼ばれます。
ackLabel / acknowledgedLabelReactNode-確認前後のラベルです。
actionsReactNode-右側に置く関連操作です。

使い方

import * as React from "react";
import { Button, SafetyBanner, Toast, Tooltip, TooltipContent, TooltipTrigger } from "@gunjo/ui";

export function PrescriptionGate() {
  const rootRef = React.useRef<HTMLDivElement | null>(null);
  const [portalContainer, setPortalContainer] = React.useState<HTMLElement | null>(null);
  const [acked, setAcked] = React.useState(false);
  const [signed, setSigned] = React.useState(false);
  const [toastMessage, setToastMessage] = React.useState<string | null>(null);

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

  return (
    <div ref={rootRef} className="relative flex w-full max-w-2xl flex-col gap-3 rounded-lg border bg-card p-4">
      {toastMessage ? (
        <div className="pointer-events-none absolute right-3 top-3 z-[100] w-[min(340px,calc(100%-1.5rem))]">
          <Toast
            message={toastMessage}
            type="success"
            isVisible
            placement="inline"
            closeLabel="閉じる"
            onClose={() => setToastMessage(null)}
            tooltipPortalContainer={portalContainer}
          />
        </div>
      ) : null}
      <SafetyBanner tone="destructive" title="アレルギー警告:ペニシリン" requireAck acknowledged={acked} onAcknowledge={() => setAcked(true)}>
        処方薬「アモキシシリン」は患者のアレルギーに該当します。投与は禁忌です。
      </SafetyBanner>
      {!acked ? (
        <Tooltip>
          <TooltipTrigger asChild>
            <span className="inline-flex w-fit" tabIndex={0} aria-label="安全確認にチェックすると署名できます。">
              <Button disabled variant="secondary">処方を署名</Button>
            </span>
          </TooltipTrigger>
          <TooltipContent>安全確認にチェックすると署名できます。</TooltipContent>
        </Tooltip>
      ) : signed ? (
        <span className="inline-flex min-h-9 w-fit items-center rounded-md border border-success-border bg-success-subtle px-3 text-sm font-medium text-success-subtle-foreground">
          署名済み
        </span>
      ) : (
        <Button onClick={() => {
          setSigned(true);
          setToastMessage("処方を署名しました。");
        }}>
          処方を署名
        </Button>
      )}
    </div>
  );
}

使用コンポーネント

設計の判断(UIXHERO)

「いつ・なぜ使うか」の判断は、姉妹サイト UIXHERO の記事で解説しています。