settings-api-key-created
API キーを発行した直後に、「一度しか表示しない」注意とともにキー値を提示しコピーできるカードです。card / callout / clipboard / input-group / field / input / button の 7 部品を合成します。Blocks は既存部品の合成例であり、新しい UI 部品は追加しません。
主参照は対応表 ID R0241(代表構成: 単一キー)で、R0242(複数キー行表示)を集約しています。キー値はすべて fd_demo_ 接頭辞の架空データであり、実在サービスの秘密情報ではありません。
本 Demo は無 JS の静的表示のみであり、<form> を含みません。
Demo
API キーを発行しました
この API キーはアプリケーションが外部サービスへ認証するために使います。
このキーは今回のみ表示されます。閉じる前に安全な場所へ保管してください。
API キーを発行しました
この API キーはアプリケーションが外部サービスへ認証するために使います。
このキーは今回のみ表示されます。閉じる前に安全な場所へ保管してください。
使用部品
Rust コード
Rust
use fandhe_frontend_core::{div, text, Node};
use fandhe_frontend_pre_styled_ui::button::{button, ButtonProps};
use fandhe_frontend_pre_styled_ui::callout::{self, CalloutProps};
use fandhe_frontend_pre_styled_ui::card::{self, CardProps, CardVariant};
use fandhe_frontend_pre_styled_ui::clipboard;
use fandhe_frontend_pre_styled_ui::field::{
self, FieldIds, FieldOrientation, FieldProps, FieldRootProps,
};
use fandhe_frontend_pre_styled_ui::input::{self, InputProps};
use fandhe_frontend_pre_styled_ui::input_group::{self, InputGroupAlign, InputGroupProps};
use fandhe_frontend_pre_styled_ui::visually_hidden;
/// 版 A(単一キー、R0241)で提示するダミーキー値。実在サービスの
/// シークレット形式を避けた明白な架空パターン(モジュール doc「ダミー値は
/// 明白な架空パターン」節参照)。
const KEY_A: &str = "fd_demo_0000-1111-2222-3333";
/// 版 B(複数キー、R0242)で提示するダミーキー値 3 件(用途ラベルと対)。
const KEYS_B: &[(&str, &str)] = &[
("本番用", "fd_demo_4444-5555-6666-7777"),
("ステージング用", "fd_demo_8888-9999-aaaa-bbbb"),
("読み取り専用", "fd_demo_cccc-dddd-eeee-ffff"),
];
/// 「発行完了」見出し + 注意 + コピー欄 + 完了ボタンを束ねるカード骨格。
/// `key_area` は版ごとに異なるキー表示領域(A: 単一 clipboard、B: 複数行)。
fn card_with(key_area: Node) -> Node {
card::root(
CardProps::from(CardVariant::Outline),
vec![],
vec![
card::header(
vec![],
vec![
card::title(vec![], vec![text("API キーを発行しました")]),
card::description(
vec![],
vec![text(
"この API キーはアプリケーションが外部サービスへ認証するために使います。",
)],
),
],
),
card::body(
vec![("class", "blocks-settings-api-key-created-body")],
vec![
callout::root(
&CalloutProps::default(),
vec![],
vec![callout::text(
vec![],
vec![text(
"このキーは今回のみ表示されます。閉じる前に安全な場所へ保管してください。",
)],
)],
),
key_area,
],
),
card::footer(
vec![("class", "blocks-settings-api-key-created-footer")],
vec![button(&ButtonProps::default(), vec![], vec![text("完了")])],
),
],
)
}
/// A: 代表構成(R0241)。単一キーを `clipboard` で提示する。
fn version_single_key() -> Node {
let input_id = "blocks-settings-api-key-created-a-input";
let key_area = clipboard::root(
KEY_A,
false,
vec![
("id", "blocks-settings-api-key-created-a"),
("data-blocks-settings-api-key-created-clipboard", ""),
],
vec![
visually_hidden::root(
vec![],
vec![clipboard::label(
false,
Some(input_id),
vec![],
vec![text("API キー")],
)],
),
clipboard::control(
false,
vec![],
vec![
clipboard::input(KEY_A, false, vec![("id", input_id)]),
clipboard::trigger(
false,
vec![],
vec![
clipboard::indicator(false, false, vec![], vec![text("コピー")]),
clipboard::indicator(true, false, vec![], vec![text("コピーしました")]),
],
),
],
),
],
);
card_with(key_area)
}
/// B の 1 行分(`label`・キー値)を組み立てる。`clipboard` root を使わない
/// 理由はモジュール doc「Demo 内の `clipboard` root は 1 個に限る」節参照。
/// `row_index` は `id` 一意性のための連番(0 始まり)。
fn key_row(row_index: usize, label: &'static str, value: &'static str) -> Node {
let input_id = format!("blocks-settings-api-key-created-b-{row_index}-input");
let field_props = FieldProps {
id: input_id.as_str(),
ids: FieldIds::default(),
disabled: false,
invalid: false,
required: false,
readonly: true,
has_helper_text: false,
};
let group_props = InputGroupProps {
disabled: false,
invalid: false,
};
field::root(
&FieldRootProps {
orientation: FieldOrientation::Vertical,
},
&field_props,
vec![],
vec![
field::label(&field_props, vec![], vec![text(label)]),
input_group::root(
&group_props,
vec![("data-blocks-settings-api-key-created-key", "")],
vec![
input::input(&InputProps::default(), &field_props, vec![("value", value)]),
input_group::addon(
InputGroupAlign::InlineEnd,
&group_props,
vec![],
vec![input_group::button(
// `clipboard` scope の外側にあり `headless_clipboard`
// 配線が届かないため、押しても何も起きないことを
// `disabled: true` で明示する(`hero_install_command`
// の版 B と同型の判断)。
&InputGroupProps {
disabled: true,
..group_props
},
vec![],
vec![text("コピー")],
)],
),
],
),
],
)
}
/// B: 複数キー行表示版(R0242)。3 行のキー欄を縦に積む(コピー状態は
/// 持たない)。
fn version_multiple_keys() -> Node {
let rows: Vec<Node> = KEYS_B
.iter()
.enumerate()
.map(|(i, (label, value))| key_row(i, label, value))
.collect();
let key_area = div(
vec![("class", "blocks-settings-api-key-created-rows")],
rows,
);
card_with(key_area)
}
/// `settings-api-key-created` の Demo 本体。呼び出しごとに同一の `Node` を
/// 返す純関数。版 A・B を縦に並記する。
pub fn demo() -> Node {
div(
vec![("class", "blocks-settings-api-key-created-stack")],
vec![version_single_key(), version_multiple_keys()],
)
}原案差分メモ
- 版 A(代表構成、R0241): 単一キーを
clipboard1 個で提示します。 - 版 B(複数キー行表示、R0242): 3 個のキー(本番用・ステージング用・読み取り専用)を行ごとに
field+input-group+readonlyのinputで行表示します(hero-install-commandの版 B と同じ構成)。キー値は選択して手動でコピーできます。 - 版 B の各行のコピーボタンは
clipboardscope の外側にあるinput_group::buttonで、disabledにしています。headless_clipboard配線は「1 root : 1 状態機械契約」(Runtime::mount/hydrateに渡されたマウントルート配下の全clipboardパーツの表示が連動する簡略化)を持つため、Demo 内にclipboardroot を複数置くと 1 つのキーをコピーしただけで他のキーまで「コピーしました」表示になります。これを避けるためclipboardroot は版 A の 1 個に限っています。実アプリで行ごとにコピーさせる場合は、版 A のclipboardを行ごとに別々のマウントルートへ置き、個別にmount/hydrateしてください。 - 「完了」ボタンは遷移先を持たない合成例のボタンです(押下は無効化していません)。
関連情報: Card / Callout / Clipboard / Input Group / Field / Input / Button