mcpField
N
norigin-spatial-navigation-react

norigin-spatial-navigation-react

github.com/noriginmedia開発49391 回インストール2 日前に更新
リポジトリ

norigin-spatial-navigation-react について

norigin-spatial-navigation-reactは、Norigin Spatial Navigationを使い、Reactアプリで矢印キーやリモコンのフォーカスを管理するスキルです。TVアプリなどのために、フォーカス可能な要素、階層コンテナ、境界、プログラムによるフォーカス設定を解説します。

主な機能

  1. 01React向けの空間フォーカスナビゲーション
  2. 02フォーカス可能なリーフと階層コンテナ
  3. 03モーダルやオーバーレイのフォーカス境界
  4. 04プログラムによるフォーカス設定と安定したキー
  5. 05方向入力のカスタマイズとイベントコールバック

活用シーン

  1. 01Smart TV画面の矢印キー操作の構築
  2. 02メニュー、グリッド、カルーセルのフォーカス管理
  3. 03モーダルダイアログ内へのフォーカス制限
  4. 04カスタムリモコンキーへの対応

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/noriginmedia/norigin-spatial-navigation --skill norigin-spatial-navigation-react

インストール後、Claude Code で/norigin-spatial-navigation-reactを入力して読み込まれたか確認します。

詳細

Norigin Spatial Navigation

React アプリ(スマートテレビ、セットトップボックス、ブラウザー)で、矢印キー/リモコンによるフォーカス管理を行うライブラリです。空間上の位置に基づいて次にフォーカス可能な要素を計算するため、方向キーのロジックを手動で設定する必要はありません。

ドキュメント全文: https://github.com/NoriginMedia/Norigin-Spatial-Navigation/tree/main/docs

このスキルの範囲を超える詳細が必要な場合は、該当するページを直接参照してください。

  • 概念と階層:docs/guides/concepts.md、docs/guides/focus-hierarchy.md
  • クイックスタートとインストール:docs/guides/quick-start.md、docs/guides/installation.md
  • useFocusable API:docs/api-reference/useFocusable.md
  • SpatialNavigation API(init、setFocus、pause など):docs/api-reference/SpatialNavigation.md
  • 境界/モーダル:docs/guides/focus-boundaries.md
  • プログラムによるフォーカス設定:docs/guides/programmatic-focus.md
  • 距離計算の調整:docs/guides/distance-calculation.md
  • キーマッピング(カスタムリモコン):docs/guides/key-mapping.md
  • イベントコールバック:docs/guides/event-callbacks.md
  • パフォーマンス:docs/guides/performance.md
  • デバッグ:docs/guides/debugging.md
  • レシピ(リスト、グリッド、仮想化):docs/guides/recipes.md
  • アクセシビリティラベル:docs/guides/accessibility-labels.md
  • RTL:docs/guides/rtl-support.md

基本的な考え方

コンポーネントの形状は次の2種類です。

  1. リーフ — 実際にフォーカスを受け取るインタラクティブな要素です。useFocusable から focused を取得します。
  2. コンテナー — フォーカス可能な子要素をラップします。focusKey を取得し、FocusContext.Provider を通じて提供することで、子要素が階層に参加できるようにします。必要に応じて hasFocusedChild も取得できます(trackChildren: true が必要です)。

すべてのフォーカス可能なコンポーネントは、返された ref を実際の DOM 要素に必ず設定してください。コンテナーは、子要素を必ず <FocusContext.Provider value={focusKey}> でラップしてください。そうしないと、子要素がルートに孤立し、子要素間のナビゲーションが機能しなくなります。

初期化

アプリの起動時(たとえば App.tsx)に、一度だけ init を呼び出します。

import { init as initNavigation } from '@noriginmedia/norigin-spatial-navigation-core';

initNavigation({
  debug: false,
  visualDebug: false,
  throttle: 0,
  distanceCalculationMethod: 'corners' // 'center' | 'edges' | 'corners'
});

カスタムリモコンキーを使用する場合は、キーマッピングも設定してください(docs/guides/key-mapping.md を参照)。

パターン

リーフ(ボタン、メニュー項目)
import { useFocusable } from '@noriginmedia/norigin-spatial-navigation-react';

function Button({ label, onPress }: Props) {
  const { ref, focused } = useFocusable({ onEnterPress: onPress });
  return (
    <div ref={ref} className={focused ? 'focused' : ''}>
      {label}
    </div>
  );
}
コンテナー
import {
  useFocusable,
  FocusContext
} from '@noriginmedia/norigin-spatial-navigation-react';

function Menu({ items }: Props) {
  const { ref, focusKey, hasFocusedChild } = useFocusable({
    trackChildren: true,
    saveLastFocusedChild: true
  });

  return (
    <FocusContext.Provider value={focusKey}>
      <div ref={ref} className={hasFocusedChild ? 'active' : ''}>
        {items.map((i) => (
          <MenuItem key={i.id} {...i} />
        ))}
      </div>
    </FocusContext.Provider>
  );
}
モーダル/ポップアップ(フォーカスを閉じ込め、マウント時にフォーカスを取得)
function Popup() {
  const { ref, focusKey, focusSelf } = useFocusable({ isFocusBoundary: true });

  useEffect(() => {
    focusSelf();
  }, [focusSelf]);

  return (
    <FocusContext.Provider value={focusKey}>
      <div ref={ref}>{/* buttons */}</div>
    </FocusContext.Provider>
  );
}

一部のみを閉じ込める場合(たとえば水平方向のみをブロックする場合)は、focusBoundaryDirections を使用してください。docs/guides/focus-boundaries.md を参照してください。

任意の場所からプログラムでフォーカスを設定
import {
  setFocus,
  doesFocusableExist
} from '@noriginmedia/norigin-spatial-navigation-core';

const KEY = 'primary-cta';
useFocusable({ focusKey: KEY });

if (doesFocusableExist(KEY)) setFocus(KEY);
条件付きでフォーカス可能にする
const { ref } = useFocusable({ focusable: !disabled });
方向入力のブロック/上書き

onArrowPress(direction, props) — デフォルトのナビゲーションを許可するには true を返し、ブロックするには false を返します。ページ分割された行、カスタムカルーセル、または端で現在のコンテナーから移動できないようにする場合に便利です。

useFocusable — 知っておきたいパラメーター

パラメーター目的
focusable要素をナビゲーションの対象にするかどうかを切り替えます。デフォルトは true です。
trackChildrenhasFocusedChild を有効にします。パフォーマンスに影響するため、参照する場合のみ有効にしてください。
saveLastFocusedChildコンテナーに再度入ったとき、最後にフォーカスされていた子要素にフォーカスを戻します。デフォルトは true です。
isFocusBoundary / focusBoundaryDirectionsコンテナー内にフォーカスを閉じ込めます。
focusKeysetFocus / doesFocusableExist 用の安定したキーです。
preferredChildFocusKeyコンテナーに入ったとき、どの子要素に最初にフォーカスするかを指定します。
onEnterPress、onArrowPress、onFocus、onBlurイベントフックです。docs/guides/event-callbacks.md を参照してください。
extraPropsコールバックに渡される任意のペイロード(項目 ID など)です。

戻り値:ref(必須)、focusKey、focused(リーフ)、hasFocusedChild(コンテナー)、focusSelf()。

トップレベル API

import {
  init,
  setFocus,
  getCurrentFocusKey,
  doesFocusableExist,
  navigateByDirection,
  pause,
  resume,
  setKeyMap,
  setThrottle,
  destroy
} from '@noriginmedia/norigin-spatial-navigation-core';

一覧とシグネチャーの全容は docs/api-reference/SpatialNavigation.md を参照してください。

ベストプラクティス

推奨

  • ref は必ず DOM 要素にアタッチしてください。
  • コンテナーの子要素は <FocusContext.Provider value={focusKey}> で囲んでください。
  • hasFocusedChild を実際に使用する場合のみ、trackChildren を有効にしてください。
  • プログラムから対象にする要素には、安定した focusKey を使用してください。
  • 特にルートの変更時や非同期データを扱う場合は、setFocus の呼び出しを doesFocusableExist でガードしてください。
  • モーダル、ドロワー、オーバーレイには isFocusBoundary を使用してください。
  • 頻繁に切り替わる可能性のある無効または非表示の項目は、アンマウントするのではなく focusable: false を設定してください。

非推奨

  • コンテナーの focused は参照しないでください。代わりに hasFocusedChild を使用してください。
  • コンテナーで FocusContext.Provider を省略しないでください。子要素が兄弟要素から到達できなくなります。
  • マウントされていない可能性のあるキーに対して、むやみに setFocus を呼び出さないでください(フォーカスが通知なく失われます)。
  • レンダーのたびに変わる focusKey を生成しないでください。フォーカス状態が失われます。
  • 本番ビルドでは debug / visualDebug を有効にしないでください。

デバッグ

init で診断機能を有効にします。

init({ debug: true, visualDebug: true });

よくある問題:

  • 要素にフォーカスできない — ref がアタッチされていない、focusable: false が設定されている、または祖先に FocusContext.Provider がありません。
  • フォーカスが誤った隣接要素に移動する — 別の distanceCalculationMethod(corners / center / edges)を試してください。visualDebug を有効にすると、ヒットボックスを確認できます。
  • 再レンダー時にフォーカスが失われる — focusKey が不安定か、フォールバックがないままフォーカスされていたノードがアンマウントされています。preferredChildFocusKey を使用するか、新しいツリーのマウント後に setFocus を呼び出してください。
  • モーダルからフォーカスが漏れる — モーダルコンテナーに isFocusBoundary が設定されていません。

詳細:docs/guides/debugging.md、docs/guides/performance.md。

クイックリファレンス

// Leaf
const { ref, focused } = useFocusable();

// Container
const { ref, focusKey } = useFocusable();
<FocusContext.Provider value={focusKey}>
  <div ref={ref}>{children}</div>
</FocusContext.Provider>;

// Focus on mount
const { focusSelf } = useFocusable({ isFocusBoundary: true });
useEffect(() => {
  focusSelf();
}, [focusSelf]);

// Manual focus
if (doesFocusableExist('my-key')) setFocus('my-key');

コメント