Skip to content
fandhe-frontendcore v0.4.3
GitHub

wasm-full feature 選択ガイド

本ドキュメントはイシュー #2330 を契機に作成しました。fandhe-frontend-wasm-full(イシュー #2326/#2327)が持つ 2 軸の Cargo feature(配線群別 32 件・scope 別 16 件、いずれも既定 on。このほか別枠 9 件も既定 on で、既定の合計は 57 件)と、fandhe-frontend-dist-server(イシュー #2329)が配布する最小構成を、利用者向けに一箇所へ集約します。機械可読な一次情報(対応表そのもの)は crates/wasm-full/src/lib.rs クレート doc・crates/wasm-full/Cargo.toml の [features] 直前コメントであり、本書はそれを利用者の目的別に読みやすく再構成したものです。

1. 対象読者

  • fandhe-frontend-wasm-full を直接依存に持つアプリ(examples/interactive-view-transitions のように default-features = false で必要な feature だけを選びたい利用者)
  • fandhe-frontend-dist-server を利用し、配布 WASM に含まれる部品を把握したい利用者(examples/dist-server-docker 相当)

2. feature の 2 軸と既定 on

fandhe-frontend-wasm-full の feature は独立した 2 軸に分かれます。

  • 配線群別 feature(イシュー #2326): Runtime::mount/hydrate が呼ぶ wire_* 呼び出し 1 件を feature 1 件でゲートします。off にすると、その配線自体が mount/hydrate から呼ばれなくなります。
  • scope feature(イシュー #2327): keynav::wire_keynav 内部の match scope 分岐(部品ごとの 1 arm)と headless::MAPPING_TABLE の該当行を feature 1 件でゲートします。off にすると、keynav::wire_keynav 自体は呼ばれ続けますが、その部品のキーボード操作・クリック配線のみが失われます。

両軸は独立しているため、部品ごとに次の組み合わせを選べます。

  • クリック操作のみで良い = 当該 scope feature のみを有効にする(keynav は off のままで良い)
  • キーボード操作も使う = keynav feature + 当該 scope feature の両方を有効にする

いずれも既定はすべて on(default-features = false を指定しない限り、既存の挙動は変わりません)。

3. 配線群別 feature 対応表(イシュー #2326、0.19.0 で追加)

配線feature
events::wire_eventsゲートしない(data-action 委譲、全構成必須)
keynav::wire_readonly_click_guardゲートしない(readonly RadioGroup の click capture 保護)
Runtime::wire_headlessゲートしない(headless::MAPPING_TABLE 全行のクリック dispatch)
keynav::wire_keynavkeynav
focus_visible::wire_focus_visiblefocus-visible
Runtime::wire_avataravatar
Runtime::wire_clipboardclipboard
Runtime::wire_timertimer
Runtime::wire_angle_sliderangle-slider
Runtime::wire_splittersplitter
Runtime::wire_signature_padsignature-pad
Runtime::wire_number_inputnumber-input
Runtime::wire_commandcommand
Runtime::wire_sidebarsidebar
Runtime::wire_chartchart
Runtime::wire_chart_rangechart-range
Runtime::wire_questionnairequestionnaire
Runtime::wire_message_scrollermessage-scroller
Runtime::wire_data_tabledata-table
Runtime::wire_in_viewin-view
Runtime::wire_gesturegesture
Runtime::wire_scroll_driverscroll-driver
Runtime::wire_drag_gesturedrag-gesture
Runtime::wire_confetticonfetti
Runtime::wire_svg_pathsvg-path
Runtime::wire_hold_to_confirmhold-to-confirm
Runtime::wire_add_to_basketadd-to-basket
Runtime::wire_magneticmagnetic
Runtime::wire_carousel_motioncarousel-motion
Runtime::wire_count_upcount-up
Runtime::wire_keydownaction-keydown
Runtime::wire_text_animationtext-animation
Runtime::wire_tickerticker
Runtime::wire_cursorcursor

cursor feature(0.36.0 で追加、イシュー #2542)は scroll-driver/ confetti/hold-to-confirm/magnetic/text-animation と同型(配線群かつ dep:fandhe-frontend-animation 有効化)で、カスタムカーソル要素(data-fandhe-cursor opt-in)をポインタに spring で追従させます。hover 対象(data-fandhe-cursor-target)の data-* 値をカーソル要素へ写してバリアント切替・ラベル表示を行い、data-fandhe-cursor-target-magnetic 付き対象では中心へ吸着します。fandhe-frontend-animation::cursor::CursorAnimator が spring 演算・rAF 駆動・DOM 書き込みを担い、prefers-reduced-motion: reduce・pointer: coarse のいずれかが真なら配線自体を行いません。

magnetic feature(0.31.0 で追加、イシュー #2550)は scroll-driver/ confetti/hold-to-confirm と同型(配線群かつ dep:fandhe-frontend-animation 有効化)で、ポインタに追従して吸い付く CTA ボタン(data-fandhe-magnetic opt-in)のオフセットを fandhe-frontend-animation::magnetic::compute_pull/write_offset で計算・書き込みます。rAF ループ・spring 計算は使わず、pointermove ごとに直接 CSS カスタムプロパティ(--fandhe-motion-magnetic-x/-y)へ書き込み、実際の追従感は既存の CSS motion トークンによる transition へ委ねる設計です(crates/frontend-animation/src/magnetic.rs モジュール doc参照)。

count-up feature(0.36.0 で追加、イシュー #2539)は magnetic/ hold-to-confirm と同型(配線群かつ dep:fandhe-frontend-animation 有効化)で、stat の数値表示(data-fandhe-count-up opt-in)を 0 から目標値へ補間しながら textContent へ書き込みます。整形済み文字列の書式(桁区切り・prefix/suffix)を保存したまま数値部分だけを補間する fandhe-frontend-animation::count_up::NumberText/start を消費し、本 feature 自体は候補収集・トリガー判定(マウント時 / data-fandhe- count-up-trigger="in-view")・MutationObserver による外部更新の再補間起動のみを担います(crates/wasm-full/src/count_up.rs モジュール doc 参照)。

action-keydown feature(0.43.0 で追加、イシュー #3754)は追加依存を持たない配線群で、data-action-keydown(action 名)・data-keys(対象キー)を持つ要素(またはその祖先)で押されたキーを Component の action として dispatch します。Runtime::mount/hydrate の最後の配線として登録されるため、部品専用の keydown 配線が preventDefault したキーはそちらが優先されます。preventDefault() は data-keydown-prevent-default の opt-in があるときだけ呼びます。IME 変換中は action になりません。押しっぱなしの自動リピートを無視したい要素には data-keydown-ignore-repeat(空文字列または true、0.44.0 で追加、イシュー #3763)を付けます。2 回目以降の keydown(KeyboardEvent.repeat)だけ dispatch せず、最初の keydown は通ります。data-keydown-prevent-default も付けていれば repeat 中も preventDefault() は維持されます。属性なしの挙動は従来どおりです。ペイロードは、要素に data-payload を付ければ click と同じ値になります(0.45.0 で追加、イシュー #3764)。付けない場合は従来どおりキーの正規トークン(例: Control+Enter)で、付けるとキー情報は payload に入りません。document/window に登録される部品の keydown とは排他になります(0.46.0 で追加、イシュー #3768)。overlay(OverlayCloseController)の Escape(最上位が close_on_escape のとき)、sidebar の Cmd/Ctrl+B(有効な trigger/rail があるとき)と Escape(モバイル drawer または開いている menu-button tooltip があるとき)、command の Ctrl/Cmd+K(Shift・Alt なし、有効な dialog があるとき)では、部品が消費するため汎用 action は見送られ(preventDefault() も呼ばれません)、部品だけが動きます。部品が消費しない状況(overlay が閉じている・最上位が opt-out・trigger が無効・dialog がない等)や、OverlayCloseController を使わない構成では従来どおり汎用 action が動きます。entry.rs の参照実装(mount/hydrate)は Runtime::mount/hydrate を呼ぶため、この配線は追加コードなしで有効になります(AppState では increment 等に加え、data-payload を付ければ set_draft・remove_item も keydown で使えます)。詳細は docs/design/wasm-full-architecture.md §40.5・§41 を参照してください。

text-animation feature(0.35.0 で追加、イシュー #2532)は scroll-driver/ confetti/hold-to-confirm/magnetic と同型(配線群かつ dep:fandhe-frontend-animation 有効化)で、data-fandhe-typewriter/ data-fandhe-scramble opt-in 要素の .fd-text-reveal__display 子要素へ fandhe-frontend-animation::text_animation::play_typewriter/ play_scramble(AnimationLoop/RafDriver を消費)で 1 文字送り・乱数置換のフレームを毎フレーム書き込みます。split-text reveal(chars/ words)は SSR + CSS @keyframes のみで完結する fandhe_frontend_pre_styled_ui::text_reveal(motion feature)側の責務であり、本 feature の対象外です。

ticker feature(0.36.0 で追加、イシュー #2540)は magnetic と同型(配線群かつ dep:fandhe-frontend-animation 有効化)で、marquee の JS 駆動拡張(実測に基づく複製数決定・rAF による offset 前進・hover/scroll 速度連動)を data-fandhe-ticker opt-in 要素へ配線します。純計算・DOM 駆動は fandhe-frontend-animation::ticker::Ticker の責務であり、本 feature は opt-in 要素の走査・イベント委譲・prefers-reduced-motion 判定のみを担います(crates/wasm-full/src/ticker.rs モジュール doc 参照)。

carousel-motion feature(0.36.0 で追加、イシュー #2541)も同型で、data-fandhe-carousel-drag opt-in root 配下の item-group へのポインタドラッグを fandhe-frontend-animation::carousel::CarouselTrack(spring スナップ + AnimationLoop/RafDriver)で追従させ、release 後に "goto" を dispatch します。coverflow 3D 表示(CSS のみ)は fandhe_frontend_pre_styled_ui::carousel_motion(motion feature)側の責務であり、本 feature とは独立です。

magnetic feature(0.31.0 で追加、イシュー #2550)は scroll-driver/ confetti/hold-to-confirm と同型(配線群かつ dep:fandhe-frontend-animation 有効化)で、ポインタに追従して吸い付く CTA ボタン(data-fandhe-magnetic opt-in)のオフセットを fandhe-frontend-animation::magnetic::compute_pull/write_offset で計算・書き込みます。rAF ループ・spring 計算は使わず、pointermove ごとに直接 CSS カスタムプロパティ(--fandhe-motion-magnetic-x/-y)へ書き込み、実際の追従感は既存の CSS motion トークンによる transition へ委ねる設計です(crates/frontend-animation/src/magnetic.rs モジュール doc参照)。

hold-to-confirm feature(0.30.0 で追加、イシュー #2538)は scroll-driver/ confetti と同型(配線群かつ dep:fandhe-frontend-animation 有効化)で、fandhe-frontend-animation の AnimationLoop/RafDriver/DomTarget(#2403/#2517)を消費して長押し確定ボタンの進行度を毎フレーム DOM へ書き込みます。add-to-basket feature(同 0.30.0、同イシュー)は data-state 状態機械 + タイマーのみで完結し(headless_clipboard.rs と同型のパターン)、fandhe-frontend-animation への依存追加は伴いません。

scroll-driver feature(0.27.0 で追加、イシュー #2521)は配線群別 feature でありながら fandhe-frontend-animation を optional 依存として有効化する初めての feature です(animation-driver/animate は別枠・非配線の feature、scroll-driver は配線群かつ optional dep 有効化という新パターン)。drag-gesture feature・confetti feature(マージコミット注記: 両者はそれぞれ独立に 0.28.0 へ到達したのち衝突し、.claude/rules/ coding-rust.md #638 条項に従い +1 して 0.29.0 で合流、イシュー #2535/#2533)も scroll-driver と同型(配線群かつ optional dep 有効化)です。drag-gesture は pointer capture ベースの汎用ドラッグ(drag_gesture モジュール)を配線し、fandhe_frontend_animation::drag::DragController の軸制約・範囲クランプ・離脱速度推定・spring 復帰を pointer/keyboard イベントへ繋ぎます。confetti は wasm-full が canvas 系 web-sys feature(CanvasRenderingContext2d/HtmlCanvasElement)を一切追加しません(fandhe-frontend-animation::confetti::fire が web_sys::Element を受け取り、canvas への cast は fandhe-frontend-animation 側で完結する設計。SignaturePad 由来の「canvas を使わない」方針を維持)。svg-path feature(0.32.0 で追加、イシュー #2519)も scroll-driver/confetti と同型(配線群かつ dep:fandhe-frontend-animation 有効化)です。全長取得(getTotalLength())・stroke-dasharray/stroke-dashoffset の初期値計算・WAAPI 呼び出しはいずれも fandhe-frontend-animation::svg_path の責務であり、wasm-full 側は [data-fandhe-svg-path-draw] 要素の走査・呼び出し配線のみを担います(duration/easing 等のカスタマイズは扱わない固定既定値のみ)。

0.29.0(イシュー #2534。main の #2533 取り込みに伴う 0.28.0 同士の版数衝突の再バンプ)で scroll-driver の挙動を拡張し、data-fandhe-scroll-progress 属性値により進捗の計算範囲を選べるようになりました(新規 feature の追加は伴いません)。""(存在マーカーのみ)・"entry" は従来どおりの entry 進捗、"cover"/"contain" は fandhe-frontend-pre-styled-ui の SlotRecipe::parallax/ SlotRecipe::sticky_progress のネイティブ範囲(animation-range: cover 0% cover 100%/contain 0% contain 100%)に対応するフォールバック進捗を書き込みます。未知の属性値は "entry" へ fail-closed します(fandhe_frontend_wasm_full::scroll_driver::progress_range_from_attr)。

position feature(0.20.1 で追加)はこの表とは別枠です。headless::wire_headless_component 内の自動 positioning 呼び出し(ensure_global_controller・配線時/dispatch 後の reposition_within)のみをゲートし、position モジュール自体・公開 API(PositionController 等)はゲート対象外です。

stagger feature(0.21.0 で追加、イシュー #2397)も同じく別枠です。Runtime::apply_update_for_dirty の keyed list 構造反映(Insert/ Move)直後の stagger_index::sync_stagger_index 呼び出しのみをゲートし、stagger_index モジュール自体・公開関数(stagger_index_value)はゲート対象外です。

animation-driver feature(0.25.0 で追加、イシュー #2403/#2517)も同じく別枠です。fandhe-frontend-animation(rAF Driver・DOM Target)を optional 依存として有効化し、animation_driver モジュール(fandhe-frontend-animation の型の薄い再公開のみ)を公開します。Runtime::mount/hydrate からの新規呼び出しは伴いません。data-* 属性からの実消費配線は後続 issue(親トラッキング #2508)が追加します。

view-transitions feature(0.25.0 で追加、イシュー #2400)も同じく別枠です。Runtime::apply_with_view_transition(任意の状態更新を document.startViewTransition() でラップする新規公開 API)のみをゲートし、view_transition モジュール自体・view_transition::with_view_transition(nav.rs の router 経由 View Transitions、イシュー #404 が使う共有実装)はゲート対象外です。nav.rs 側の呼び出しは本 feature の有効・無効に関わらず無条件で動作し続けます。

view-transition-name feature(0.25.0 で追加、イシュー #2515)も別枠ですが、position/stagger とはゲート対象が異なります: Runtime 内部の呼び出し箇所ではなく、view_transition_name::set_view_transition_name(Runtime を経由しないアプリ直接利用 API)という公開関数そのものの存在をゲートします。view_transition_name モジュール自体・純粋関数(is_valid_view_transition_name)はゲート対象外です。off にすると set_view_transition_name が使えなくなります。

view-transition-preset feature(0.32.3 で追加、イシュー #2516)も別枠です。Runtime::apply_with_view_transition_named(named view transition プリセット選択、view_transition_preset::ViewTransitionPreset)という公開メソッドの存在をゲートします。view_transition_preset モジュール自体・VIEW_TRANSITION_PRESET_ATTR/ViewTransitionPreset はゲート対象外です。off にすると apply_with_view_transition_named が使えなくなります(apply_with_view_transition〔unnamed、view-transitions feature〕は影響を受けません)。ViewTransitionPreset はイシュー #2537(0.34.0)で Iris/Doors/Shutter/Blinds/Strips/Pixels/MaskWipe/MaskRadial の 8 バリアントを追加しました。既存の match を exhaustive に書いている利用者は、この feature の on/off に関わらずコンパイルが壊れる点に注意してください(_ => の網羅、または新バリアントへの対応が必要です)。

animate feature(0.25.0 で追加、イシュー #2398)も同じく別枠です。ただし position/stagger/view-transition-name とは異なり、ゲート対象の wire_* 呼び出し自体が存在しません。optional 依存 fandhe-frontend-animation(element.animate() WAAPI 薄いラッパ)を有効化し、pub use fandhe_frontend_animation; で本クレート経由に再エクスポートするだけの feature です。data-* 属性からの自動トリガー配線は本 issue のスコープ外(後続 Phase 4 issue の責務)です。有効なら自前で fandhe-frontend-animation に依存を追加しなくても fandhe_frontend_wasm_full::fandhe_frontend_animation::animate::{animate, AnimateOptions, WaapiKeyframe} を呼び出せます。off にするとこの再エクスポートが消え、アプリ側で直接呼び出せなくなります。

layout-animation feature(イシュー #2518。main との複数回の同一版数衝突〔#638 条項の「+1」運用〕を経て到達した具体的な版数は下表「7. default-features = false 利用者の移行手順」を正とする)も別枠です。Runtime::apply_update_for_dirty の keyed list 構造変化コミット前後で fandhe_frontend_animation::flip(layout FLIP アニメーション)の Before/After 計測・Invert・Play を起動する呼び出し(layout_flip:: capture_before/play_after)をゲートします。layout_flip モジュール自体・座標計測やアニメーション計算のロジックは fandhe-frontend-animation 側の責務であり、本クレートはいつ呼ぶかのみを担います。対象リストは親要素に data-fandhe-flip-auto 属性を持つ keyed list へオプトインで限定されるため、off にすると当該属性を付けたリストでも並べ替えアニメーションが起動しなくなります。

入れ子 FLIP リストの所有権契約(codex-review 追加ラウンド 2 巡目是正、イシュー #2518): data-fandhe-flip-auto を持つ keyed list が、同属性を持つ祖先リストの配下にある場合、その内側リストは自分では capture/play しません。最外側の FLIP リストがサブツリー全体のアニメーションを所有し、内側リストの並べ替え差分は外側リストの行(内側リストを含む)の Before/Last 矩形の変化として自然に取り込まれます。内側リストが dirty のときは祖先 FLIP リスト全件を停止・捕捉しますが、実際に play するのは常に最外側リストのみであり、この挙動は dirty field の列挙順に依存しません。詳細な契約は crates/wasm-full/src/layout_flip.rs モジュール doc「入れ子 FLIP リストの所有権契約」節を正とします。「入れ子リストそれぞれが独立にアニメーションする」ことは本契約の対象外です(最外側リストがサブツリー全体の Invert 変形を所有する設計上のスコープ外であり、将来の課題として扱います)。

共有レイアウト遷移(イシュー #2536)を含む: layout-animation feature は上記の同一要素向け layout FLIP に加え、crate::shared_layout(data-fandhe-layout-id 属性、旧要素→新要素の id 突合による共有レイアウト遷移。motion.dev layoutId 相当)もゲートします。新規 feature は切らず既存 layout-animation を再利用しているため、off にすると両方のアニメーションが同時に無効化されます。詳細は アニメーション機能ガイド §12 を参照してください。

presence feature(イシュー #2544、既定 on)も layout-animation と同型の別枠です。Runtime::apply_update_for_dirty の keyed list 構造変化コミットの前後で、fandhe_frontend_animation::presence(削除行の座標スナップショット撮影・退場ゴースト配置・実測 CSS アニメーション時間経過後の除去)を起動する呼び出し(list_presence::capture_before/ play_exit_after)をゲートします。list_presence モジュール自体・座標計測やタイマー処理のロジックは fandhe-frontend-animation 側の責務であり、本クレートはいつ呼ぶかのみを担います。対象リストは親要素に data-fandhe-flip-auto と同型の data-fandhe-presence-auto 属性を持つ keyed list へオプトインで限定されるため、off にすると当該属性を付けたリストでも削除行の退場アニメーションが起動しなくなります(並べ替え〔layout-animation〕・追加行の入場(fandhe-frontend-pre-styled-ui motion feature の list_motion が提供する CSS、stagger feature の --fandhe-motion-stagger-index 同期)とは独立の feature です)。

ゴースト方式: 削除された行は DOM から即座に取り除かれるのではなく、元の座標(offsetTop/offsetLeft/offsetWidth/offsetHeight)へ position: absolute で list 末尾へ再挿入され、inert・aria-hidden="true"・data-state="exiting" を付与されます(Motion の AnimatePresence〔popLayout〕相当)。ゴーストからは data-key/data-bind-*/data-action を剥がすため、次回の keyed list 差分・FLIP・束縛点走査・イベント委譲のいずれにも拾われません。除去は animationend イベントに依存せず、computed animation-duration/ animation-delay から求めた実測時間 + 50ms 後のタイマーで行うため、motion feature 未読み込み・prefers-reduced-motion: reduce・animation-duration: 0s のいずれでもゴーストは即座に除去されます(fail-safe)。ゴーストは絶対配置のため後続行は FLIP で即座に詰まります(既知の視覚的挙動、Motion popLayout と同じ見え方)。

4. scope feature 対応表(イシュー #2327、0.20.0 で追加)

feature 名は headless::MAPPING_TABLE の scope 文字列と一致します(keynav の match arm リテラルが異なる場合のみ併記)。

featureMAPPING_TABLE 行数keynav の match arm
accordion1"accordion"
calendar3"calendar"
collapsible1なし
combobox3"combobox"
dialog2なし
listbox0(keynav 専用)"listbox"
menu4"menu"
menubar3"menubar"
navigation-menu1"navigation-menu-trigger"・"navigation-menu-link"
popover2なし
radio-group1"radio"・change リスナー
select3"select"
tabs1"tabs"・bubble click
toggle-group1"toggle-group"
tooltip1なし
tree-view2"tree-view"・tree 復元

配線群別 feature である sidebar(MAPPING_TABLE 2 行)・signature-pad(同 1 行)も、それぞれ同名 feature で MAPPING_TABLE 行を追加ゲートします(上表とは別枠)。

readonly RadioGroup の click capture 保護(keynav::wire_readonly_click_guard)はいずれの scope feature にも依存しない常時配線です。radio-group を off にしても、この保護は失われません。

5. feature に関わらず常時有効な配線

  • events::wire_events(data-action 委譲)
  • keynav::wire_readonly_click_guard(readonly RadioGroup の click capture 保護)
  • Runtime::wire_headless(headless::MAPPING_TABLE 全行のクリック dispatch)

6. gating 対象外の直接利用 API

overlay / tooltip / position / focus_trap / headless_file_upload / headless_select モジュール(Runtime を経由せずアプリが直接呼び出す公開 API)は、いずれの feature でもゲートされません。

名前の衝突に注意してください: tooltip / select / menu 等の feature 名は、上記モジュール名と同じ文字列ですが、feature が実際にゲートするのは headless::MAPPING_TABLE 行・keynav の match arm のみで、tooltip モジュール自体や headless_select モジュール自体の公開 API を無効化するものではありません。

7. default-features = false 利用者の移行手順

fandhe-frontend-wasm-full は以下の版数で feature を追加しました(いずれも 0.x の破壊的変更として minor バンプ)。

版数追加内容
0.19.0配線群別 feature 14 件(イシュー #2326)
0.20.0scope feature 16 件(イシュー #2327)
0.20.1position feature(イシュー #2209/#2332)
0.20.5message-scroller feature(イシュー #2122)
0.20.8data-table feature(イシュー #2126)
0.21.0stagger feature(イシュー #2397)・in-view feature(イシュー #2396)
0.22.0view-transition-name feature(イシュー #2515)
0.23.0view-transitions feature(イシュー #2400。main の #2515 取り込みに伴う版数衝突の再バンプ、PR #2553)
0.24.0animate feature(イシュー #2398。main の #2400 取り込みに伴う 0.23.0 同士の版数衝突の再バンプ、PR #2475)
0.25.0animation-driver feature(イシュー #2403/#2517。main の #2515/#2400/#2398 取り込みに伴う版数衝突の再バンプ、PR #2554)
0.26.0gesture feature(イシュー #2520。main の #2515/#2400/#2398/#2403/#2517 取り込みに伴う版数衝突の再バンプ、PR #2555)
0.27.0scroll-driver feature(イシュー #2521)
0.28.0layout-animation feature(イシュー #2518)と confetti feature(イシュー #2533、origin/main)が独立に 0.27.0 から同一版数へ到達(並行衝突。以降のマージで main 側の 0.28.0〜0.30.0 系列と本 PR 側の再バンプが個別に進んだ)
0.29.0scroll-driver の挙動拡張(data-fandhe-scroll-progress、イシュー #2534。main の #2533 取り込みに伴う 0.28.0 同士の版数衝突の再バンプ)
0.30.0drag-gesture feature(イシュー #2535。本 PR(#2535)と main(#2534)が独立に 0.28.0 から 0.29.0 へ同一版数バンプしており衝突。.claude/rules/coding-rust.md #638 条項の「同一版数も衝突として +1」運用に従い、さらに +1 して 0.30.0 とした)
0.31.0hold-to-confirm/add-to-basket feature(イシュー #2538。本 PR(#2535 到達の 0.30.0)と main(#2538 到達の 0.30.0)が独立に同一版数へバンプしており衝突。#638 条項に従いさらに +1 して 0.31.0 とする)
0.32.0feature 追加なし。イシュー #2518 の layout FLIP 視覚矩形ベース再設計に伴う fandhe-frontend-animation 依存 version 要求の更新(layout-animation feature 自体は #2518 で既に導入済み)。本 PR(#2518、layout-animation feature 追加で 0.30.0 → 0.31.0 へ到達)と main(#2538 到達の 0.31.0)が独立に同一版数へバンプしており衝突。#638 条項に従いさらに +1 して 0.32.0 とする(origin/main 側では svg-path feature〔イシュー #2519〕が同じ 0.32.0 へ独立到達しており、以降の各コミットは同一版数として記載する)
0.32.1main(PR #2572): magnetic の中心計算を transform 込みの矩形から静止位置基準へ是正(イシュー #2550、Bugbot 指摘。公開 API は変更しないため patch バンプ)
0.32.2main(PR #2572): magnetic の中心計算を transition 中も決定的にする再是正(イシュー #2550、codex-review P1 指摘。公開 API は変更しないため patch バンプ)
0.33.0svg-path feature(イシュー #2519、origin/main)。origin/main 側は独立に 0.31.0 から 0.32.0 へ到達しており、本 PR(#2518、codex-review 第 6 ラウンド是正)の上記 0.32.0 と同一版数へ再度衝突した。#638 条項に従いさらに +1 して 0.33.0 とする。base main 取り込み時(PR #2572、magnetic feature・0.32.2 到達)、本 PR 側の到達値 0.33.0 が main の到達値 0.32.2 を上回るため、そのまま維持する(さらなる衝突バンプ不要)
(merge)base main 再取り込み時(イシュー #2518 codex-review 追加ラウンド是正、view-transition-preset feature 追加): main 側はさらにイシュー #2516(view-transition-preset feature)で 0.32.2 → 0.32.3 へ独立にバンプしていた。本 PR 側の到達値 0.33.0 は main の到達値 0.32.3 をすでに上回っており同一版数の衝突には該当しないため、本 PR の到達値 0.33.0 をそのまま維持する(さらなる衝突バンプ不要)
0.34.0ViewTransitionPreset へ 8 バリアント追加(イシュー #2537。既存 exhaustive match 利用者への破壊的変更のため minor バンプ)
0.35.0text-animation feature(イシュー #2532、typewriter/scramble 配線)。あわせて fandhe-frontend-animation の依存 version 要求を 0.11.0 → 0.12.0 へ追随した。本 PR(#2532)と origin/main(#2537、view-transition-preset の破壊的バリアント追加)が同じ merge base(0.33.0)から独立に 0.34.0 へ到達したため、#638 条項に従いさらに +1 して 0.35.0 とする
(0.36.0、PR #2582 ブランチ側)ticker feature(イシュー #2540、marquee の JS 駆動拡張)。あわせて fandhe-frontend-animation の依存 version 要求を 0.12.0 → 0.13.0 へ追随した。本 PR(#2540)と origin/main(#2532、text-animation feature)が同じ merge base(0.34.0)から独立に 0.35.0 へ到達したため、#638 条項に従いさらに +1 して 0.36.0 とする
0.36.0cursor feature(イシュー #2542、カスタムカーソル配線)。あわせて fandhe-frontend-animation の依存 version 要求を 0.12.0 → 0.13.0 へ追随した
0.37.0presence feature(イシュー #2544、keyed list 削除行の退場ゴースト配線)。あわせて fandhe-frontend-animation の依存 version 要求を 0.13.0 → 0.14.0 へ追随した
0.36.0count-up feature(イシュー #2539)。あわせて fandhe-frontend-animation の依存 version 要求を 0.12.0 → 0.13.0 へ追随した。本 PR(#2539)と origin/main(#2532 到達の 0.35.0)が同じ merge base(0.34.0)から独立に 0.35.0 へ到達したため、#638 条項に従いさらに +1 して 0.36.0 とする
0.36.1PR #2580 レビュー是正: count_up.rs の自己書き込み検知を fandhe-frontend-animation の self_write_count へ追随させた(内部実装のみ、公開 API 不変)ため patch バンプ。あわせて fandhe-frontend-animation の依存 version 要求を 0.13.0 → 0.14.0 へ追随した
0.40.0PR #2582 で本ブランチ(#2540、ticker feature)を origin/main(#2541/#2542 の carousel-motion/cursor feature、独立到達値 0.39.0)へ統合し 0.40.0 とする
0.40.1PR #2582 レビュー指摘対応: ticker::wiring::resolve_ticker_targets で入れ子 ticker の祖先すべてへ hover/focus 一時停止を及ぼす修正(公開 API 不変のため patch バンプ)。origin/main も独立に 0.40.1(fandhe-frontend-animation 0.16.1 追随)へ到達
0.40.2PR #2582 で本ブランチ(0.40.1)を origin/main(#2544 の presence feature、独立到達値 0.40.1)へ統合。同一版数の衝突のため #638 条項に従い +1 して 0.40.2 とする
0.40.2count-up feature の統合(イシュー #2539、PR #2580。本 PR は独立に 0.36.1 まで到達していたが、origin/main が carousel-motion/presence 等で 0.40.1 まで進んでいたため、main の到達値に本 PR の patch 分を +1 して 0.40.2 とする。あわせて fandhe-frontend-animation の依存 version 要求を 0.17.0 へ追随した)
0.40.3PR #2582 で origin/main(#2536 の shared_layout〔layout-animation feature 配下、feature 追加なし〕統合で 0.40.2 到達)を再取り込み。本 PR 側も 0.40.2 のため同一版数の衝突として #638 条項に従い +1 して 0.40.3 とする。あわせて fandhe-frontend-animation の依存 version 要求を 0.16.3 へ追随した
0.40.3版数衝突の再バンプ(PR #2580 の main 再取り込み。main 側が #2536 shared_layout の統合で 0.40.2 へ到達し本 PR と同版になったため +1。feature 追加なし)
0.41.0Runtime::dispatch_action 追加(イシュー #3751、PR #3756)。DOM イベント以外から action を dispatch する公開 API で、feature gating はない(§13)
0.42.0汎用 keydown 配線の属性解釈とキー絞り込みの純粋ロジック追加(イシュー #3753、PR #3757)。内部ロジックのみで、利用者向けの挙動はこの版ではまだ配線されない
0.43.0action-keydown feature(イシュー #3754)。汎用 keydown 配線を Runtime::mount/hydrate に追加
0.44.0data-keydown-ignore-repeat 追加(自動リピート抑止、イシュー #3763、PR #3772)
0.45.0keydown action の payload を data-payload 優先に変更(イシュー #3764)
0.46.0overlay・sidebar・command が消費する keydown では汎用 keydown 配線が action を見送る(排他、イシュー #3768。これまで両方発火していた組み合わせが部品優先の片方のみになる)
0.40.4PR #2582 で origin/main(#2539 の count-up feature 統合で 0.40.3 到達)を再取り込み。本 PR 側も 0.40.3 のため同一版数の衝突として #638 条項に従い +1 して 0.40.4 とする。あわせて fandhe-frontend-animation の依存 version 要求を 0.17.1 へ追随した

0.19.0 以降へアップグレードし default-features = false を使っている場合、上記の配線・MAPPING_TABLE 行・keynav 分岐が既定では失われます。従来どおりの挙動を維持するには、Cargo.toml の依存指定へ default 配列と同じ 57 件を明示してください(entry 機能を使わないアプリは wasm-bindgen-exports を省略できます)。

TOML
[dependencies.fandhe-frontend-wasm-full]
version = "0.46.0"
default-features = false
features = [
  "wasm-bindgen-exports",
  "keynav",
  "focus-visible",
  "avatar",
  "clipboard",
  "timer",
  "angle-slider",
  "splitter",
  "signature-pad",
  "number-input",
  "command",
  "sidebar",
  "chart",
  "chart-range",
  "questionnaire",
  "message-scroller",
  "data-table",
  "in-view",
  "gesture",
  "scroll-driver",
  "drag-gesture",
  "confetti",
  "svg-path",
  "hold-to-confirm",
  "add-to-basket",
  "magnetic",
  "ticker",
  "carousel-motion",
  "text-animation",
  "cursor",
  "count-up",
  "action-keydown",
  "position",
  "stagger",
  "animation-driver",
  "view-transitions",
  "view-transition-name",
  "view-transition-preset",
  "animate",
  "layout-animation",
  "presence",
  "accordion",
  "calendar",
  "collapsible",
  "combobox",
  "dialog",
  "listbox",
  "menu",
  "menubar",
  "navigation-menu",
  "popover",
  "radio-group",
  "select",
  "tabs",
  "toggle-group",
  "tooltip",
  "tree-view",
]

wire_signature_pad_component を Runtime 経由せず直接呼ぶ利用者への注意

headless_signature_pad::wire_signature_pad_component を自前のマウント処理から直接呼んでいる利用者(Runtime::wire_headless 経由ではない構成)は、既定の signature-pad feature 有効化だけでは救済されません。上記の features = [...] 一覧に加えて、headless::wire_headless_component を同じ root/component へ明示的に呼び出してください(Runtime::wire_headless の実装と同型の呼び出しで足ります)。

8. dist-server 最小構成

fandhe-frontend-dist-server(配布 WASM)は「最小インタラクティブコンポーネント」として次の 7 feature のみを有効にして配布します(イシュー #2329、単一定義は crates/dist-server/src/wasm_dist_features.rs の WASM_DIST_FEATURES)。

wasm-bindgen-exports, collapsible, dialog, popover, tooltip, position, action-keydown

判断根拠:

  • REQ-11 が定義するワークロード(カウンター・フォーム入力・動的リスト更新相当)は常時配線の events::wire_events と束縛点更新のみで成立し、scope feature を 1 つも要求しません(理論下限は wasm-bindgen-exports のみ)。
  • 「button / input / dialog 系」に、クリック操作のみで機能が完結する disclosure / overlay 部品(collapsible / dialog / popover / tooltip)を加えます。これら 4 scope は keynav.rs に cfg 分岐を持たず、keynav off でも WAI-ARIA 上のキーボード操作が欠けません。
  • keynav/focus-visible は REQ-11 の実測でサイズへの影響が大きい支配的なレバーのため除外します。他の scope feature(accordion / calendar / combobox / listbox / menu / menubar / navigation-menu / radio-group / select / tabs / toggle-group / tree-view)は keynav の match arm を持つため、「click 行だけを配布してキーボード操作を欠いた部品」を出荷しないよう除外します。
  • position は popover / tooltip の表示位置決めに必要なため含めます。
  • action-keydown は追加依存を持たない汎用 keydown 配線で、gzip 実測の増分が小さく上限余裕を十分に残すため含めます(イシュー #3765、wasm-full-architecture.md §41.4)。
  • action-keydown 以外の配線群別 feature(avatar / clipboard / timer / angle-slider / splitter / signature-pad / number-input / command / sidebar / chart / chart-range / questionnaire / message-scroller / data-table / in-view / gesture)は対象外です。

実測(ローカル、wasm-opt 適用済み): bundle-size: total_gzip_bytes=124556/200000 files=2 result=PASS(上限余裕 75,444 B)。CI は wasm-opt 未導入のため構成が異なりますが、実測比較(wasm-opt 導入評価「#1972 の結論」節)から CI 側の値はむしろ小さくなる方向であり、上記余裕を侵食する懸念はありません。

最小構成に含まれない部品を使う場合

配布 WASM の最小構成に含まれない部品(accordion / menu / select 等)を利用したい場合の選択肢は 2 つです。

  1. fandhe-frontend-wasm-full を自アプリの直接依存として追加し、上記 §7 の要領で必要な feature を選ぶ(examples/interactive-view-transitions 参照)。
  2. fandhe-frontend-dist-server を fork/vendor し、crates/dist-server/src/wasm_dist_features.rs の WASM_DIST_FEATURES を変更する(crates/wasm-full/tests/bundle_size.rs の実測値を必ず併せて確認する)。

9. 検証方法

-p fandhe-frontend-wasm-full を単体で指定し、対象 target を明示して cargo check してください。

Bash
cargo check -p fandhe-frontend-wasm-full \
  --no-default-features \
  --features wasm-bindgen-exports,collapsible,dialog,popover,tooltip,position,action-keydown \
  --target wasm32-unknown-unknown --locked

--workspace を付けて --no-default-features/--features を指定した場合、Cargo の解決対象がワークスペース全体に広がるため、意図した縮小構成の検証にはなりません。縮小構成の検証は必ず -p fandhe-frontend-wasm-full 単体で行ってください。

10. 関連ドキュメント

11. 新規 feature 追加チェックリスト(イシュー #2395)

Phase 4 以降(イシュー #2396 以降、fandhe-frontend-animation 由来の feature を含む)で fandhe-frontend-wasm-full へ feature を追加する際の定型チェックリストです。feature 集合の記述は複数箇所へ分散しており、更新漏れが起きやすいため、追加時は以下を順に確認してください。

11.1 共通チェックリスト(配線群別 feature・scope feature 共通)

  1. crates/wasm-full/Cargo.toml の [features] へ <name> = [] を追加し、default 配列にも追加する(配線群か scope かで見出しコメントの表を選ぶ)。
  2. crates/wasm-full/src/lib.rs クレート doc の該当対応表(配線群別 feature 表/scope feature 対応表)と、直前の件数記述(「配線群別 feature n 件 + scope feature n 件」等)を更新する。
  3. CLAUDE.md の crates/wasm-full/ 行(「配線群別 feature n 件 + scope feature n 件」)の件数を更新する。
  4. 既存 CI ジョブ(配線群 feature なら wasm-full-feature-matrix-wiring、scope feature なら wasm-full-feature-matrix-scope)へ、既存 feature と同型の name:/run: 1 行を追加する。新規ジョブは作らない(ruleset PUT が必要になるため、.claude/rules/ci.md の「wasm-full の feature matrix ジョブ」節参照)。
  5. 本ガイド(§3 or §4 の対応表、§7 の default-features = false 移行手順の feature 列挙・版数表)へ反映する。
  6. cargo test -p fandhe-frontend-wasm-full --test bundle_size を実行し、bundle-size: 1 行サマリの実測値を PR 本文に記録する(.claude/rules/ci.md 既定要件)。
  7. crates/dist-server/src/wasm_dist_features.rs の WASM_DIST_FEATURES(7 feature の最小インタラクティブ構成)へ新規 feature を追加しないことを確認する(既定は非追加。追加が必要な場合は同ファイル冒頭コメントへ判断根拠を追記する重い変更になる)。

11.2 3 層構成(fandhe-frontend-animation 由来 feature、#2417)固有の追加項目

  • fandhe-frontend-animation を crates/wasm-full/Cargo.toml の optional 依存として追加し、新設 feature が dep:fandhe-frontend-animation で有効化する形にする。
  • wasm-full 側にアニメーション演算ロジックを書かない。fandhe-animation/fandhe-frontend-animation が計算した結果を DOM/Web Animations API へ配線する呼び出しのみを wasm-full に置く(docs/design/animation-core-architecture.md の層責務を踏襲)。

11.3 検証チェックリスト

  • ローカルで以下を実行し、単体構成が成立することを CI 追加前に確認する。
Bash
cargo check -p fandhe-frontend-wasm-full \
  --no-default-features \
  --features wasm-bindgen-exports,<new-feature> \
  --target wasm32-unknown-unknown --locked
  • scope feature の場合は crates/wasm-full/tests/feature_gating_contract.rs(MAPPING_TABLE/keynav の cfg ゲート・default 配列列挙の一貫性を機械検証)を実行する。既存テストが追加漏れを検知するため、新規テスト作成は不要。
  • CI ジョブへの 1 行追加は crates/xtask/tests/workflow_wasm_full_feature_matrix.rs(ci.yml の run: 行から抽出した feature 集合と Cargo.toml [features] の過不足なき一致を検証)を実行する。追加漏れ・記載ミスは fail-closed に検知される。
  • 新規 CI ジョブを作らない方針は ruleset の required_status_checks 個別列挙契約(.claude/rules/ci.md「ci-complete 集約ジョブと ruleset 必須チェック」節)に追随更新(マニフェスト更新+ruleset PUT)を要する運用コストが根拠であり、既存 2 ジョブへの行追加で完結することを確認する。

12. keyed list の更新の挙動と注意点(イシュー #3755)

keyed list(keyed_list() が返す data-bind-list 付きのコンテナ)の更新には、利用者がつまずきやすい挙動が 2 つあります。どちらも意図した仕様です。

12.1 親要素の属性は view() に書く

keyed list の field が dirty になる更新のたびに、親要素の属性は view() が返す属性列へ同期されます。view() に無い属性は削除されます。JS などで後から付けた aria-live・class・data-*、layout FLIP の opt-in 属性 data-fandhe-flip-auto(§3)も対象です。

  • 要素そのものは置き換わらず、ノードの同一性は保たれます。例外は親要素のタグが変わる更新と、構造フォールバック(root 配下の作り直し)です。
  • view() も出している属性の値を外部で書き換えた場合の戻り方は属性の種別で異なります。イベントハンドラ・URL・srcset の各属性は毎回検証して書き戻すため、次の dirty 更新で view() の値へ戻ります。それ以外(class・aria-live など)は直前の更新で読み戻した値と新しい view() の値が同じなら書き込みを省略するため、外部の値は次の dirty 更新では残ります。その更新で外部の値がキャッシュへ読み戻されるので、さらにその次の dirty 更新で view() の値へ戻ります(view() の値が変わった更新では、その更新で上書きされます)。外部書き換えの復元には頼らず、値は view() 側で管理してください。
  • 他の field だけが変わる更新では、この親要素の同期は走りません。
  • 子アイテム(data-key 要素)も、内容が変わった更新で同じ同期を受けます。
  • 理由は、SSR hydrate 由来のドリフトを確実に収束させることと、イベントハンドラ・URL・srcset を毎回検証して書き戻す REQ-1 の自己修復を保つことです。

親要素に必要な属性は、後から付けずに view() 側で渡してください。

Rust
// 悪い例: view() の外(JS など)で付けた属性は次の更新で消える
// element.setAttribute("aria-live", "polite");

// 良い例: view() の attrs に含める
let list = keyed_list("ul", vec![("aria-live", "polite")], "log", items);

12.2 項目数の上限と超過時の挙動

項目数は 4,096 件(MAX_KEYED_LIST_ITEMS)、キー文字列の合計は 262,144 バイト(MAX_KEYED_LIST_KEY_BYTES)までです。超えると keyed_list() が KeyedListError::TooManyItems または KeyedListError::KeyBytesExceeded の Err を返します。上限は SSR / SSG / CSR の全ターゲットに一律で掛かります。

Component::view は Result を返せないため、Err の扱いはアプリ側の責務です。

  • expect() / unwrap() すると wasm が panic し、インスタンスが停止します。以後のイベントは処理されません。
  • data-bind-list を持たないプレーンな ul へフォールバックすると、表示は壊れません。ただし keyed 差分更新が使えず、更新のたびに root 配下を作り直すため、ノード同一性とフォーカスの保持を失います。参照例は fandhe-frontend-interactive の AppState です。

12.3 推奨

  • 上限に近づく前にページングする。
  • 長いログは末尾 N 件だけを keyed list にし、古い分は捨てるか、非 keyed の静的な節へ移す。
  • 1 つのリストに詰め込まず、field 名の異なる複数の keyed list に分ける(上限はリストごとに掛かります)。
  • Err は必ず明示的に扱い、フォールバック表示(件数超過の案内など)を view() で返す。ログへキー値や項目の中身を出さない。

上限定数は HashDoS 対策の防御のため、引き上げたり keyed_list() を迂回したりしないでください。

13. 外部からの action 起動(Runtime::dispatch_action)

Runtime::dispatch_action は、DOM イベント(data-action 経路)以外から Component の action を dispatch する公開 API です(0.41.0 で追加、イシュー #3751)。タイマーのコールバック、postMessage、storage イベントなど、DOM 要素のクリックやキー入力ではない入力を Component へ届ける用途を想定しています。postMessage など外部由来の入力を渡す場合、送信元 origin の検証は呼び出し側の責務です。

Rust
pub fn dispatch_action(&self, name: &str, payload: &str) -> DispatchOutcome

13.1 引数と動作

  • name: action 名です。Component 側で解釈されます。
  • payload: data-payload と同じく信頼できない入力として扱われ、Component::decode_action へ渡されます。DOM への反映は既存の既定エスケープ済みの経路だけを通り、エスケープを迂回する経路は作られません。
  • action が受理されると Component::update が呼ばれ、data-action 経路と同じ差分更新(束縛点・keyed list)が当たります。束縛点または keyed list として宣言されたフィールドの更新では、フォーカス・IME・入力途中の値・要素の参照が保たれます。
  • 束縛点にも keyed list にも対応しないフィールドを更新する action では、構造フォールバックにより root 配下が全置換され、これらは保たれません。要素の保持が必要なら、更新対象のフィールドを束縛点または keyed list として宣言してください。

13.2 戻り値(DispatchOutcome)

variant意味
Dispatchedaction が受理され Component::update が呼ばれた。dirty field が空で DOM 更新がなくても、この値になります
UnknownAction未知の action または不正な payload。状態も DOM も変更されない(安全側の no-op)
ReentrantComponent の借用が取れなかった(再入)。状態も DOM も変更されない

DispatchOutcome は fandhe_frontend_wasm_full::DispatchOutcome として公開されます。

13.3 再入時の扱い

Runtime::component() が返す借用を保持している間、Component::update の実行中、配線コールバックの内部、Runtime::rerender の実行中に呼ぶと、Reentrant を返して何もしません(panic はしません)。action は保留もキューイングもされず捨てられます。反映したい場合は、呼び出し側が setTimeout などでコールバックの外へ逃がしてください。

13.4 feature gating

dispatch_action を有効化する Cargo feature はありません。Runtime は wasm32 ターゲットでのみ定義されるため、本メソッドも wasm32 専用であり、native からは呼べません。

13.5 使用例

Runtime を保持する thread_local! から、タイマーのコールバックで呼ぶ例です。

Rust
let tick = Closure::<dyn FnMut()>::new(|| {
    RUNTIME.with(|r| {
        if let Some(rt) = r.borrow().as_ref() {
            // Reentrant なら何もしない。必要なら次のタイマーで再試行する。
            let _ = rt.dispatch_action("tick", "");
        }
    });
});