# MimoProvider

Fluxlay SDK に同梱されている合成入力フォワーダ Mimo で壁紙ツリーを包み、OS カーソルが壁紙ウィンドウに入っていなくても通常の React の DOM イベント（`onClick`, `onPointerDown`, `onKeyDown`, ドラッグ＆ドロップライブラリ、フォーカスリング等）が発火するようにします。

Mimo がそもそも何で、なぜ壁紙に必要かは [Mimo: 壁紙内のインタラクティブ UI](/ja/studio/developer/how-to/development/mimo.md) を参照してください。

## インポート

`MimoProvider` はメインエントリと別の subpath に置かれており、Mimo の依存ツリーがメインエントリに混ざらないようになっています。

```tsx
import { MimoProvider } from "@fluxlay/react/mimo";
```

## クイックスタート

壁紙のルートに置くだけで、OS の pointer / keyboard イベントが自動的にフォワーダへ流れます。

```tsx
import { MimoProvider } from "@fluxlay/react/mimo";

export function Root() {
  return (
    <MimoProvider cursor>
      <App />
    </MimoProvider>
  );
}
```

これで `<App />` 内では普通の React ハンドラ（`<button onClick={...}>`、dnd-kit、Framer Motion drag、`useIsFocused` を使った `<input>` のフォーカスリング等）がそのまま使えます。`cursor` prop は合成 pointer に追従する仮想カーソル div を表示します。壁紙ウィンドウには OS カーソルが描画されないため、ユーザがどこを指しているかを示すのに便利です。

IME（日本語・中国語・韓国語などの変換入力）も自動でハンドリングされます。`<input>` / `<textarea>` にフォーカスすると IME プロキシが有効化され、確定文字列がフィールドに書き込まれます。直接制御したい場合のみ [`useImeInput`](/ja/studio/developer/reference/sdk/use-ime-input.md) を参照してください。

## シグネチャ

```tsx
function MimoProvider(props: MimoProviderProps): ReactNode;

interface MimoProviderProps extends Omit<MimoForwarderOptions, "pointerSource" | "keyboardSource"> {
  pointer?: boolean;
  keyboard?: boolean;
  children?: ReactNode;
}
```

`pointerSource` / `keyboardSource` は意図的に省かれています。`MimoProvider` は input source の所有権を持ち、Fluxlay の OS フック（`useMousePosition`, `useMouseEvents`, `useKeyboard`）と接続するためです。独自 source を差し込みたい場合（テスト、リプレイ、Fluxlay デスクトップアプリ外での実行）は後述の `MimoForwarderProvider` を使ってください。

## Props

| Prop                     | 型                         | 既定値             | 説明                                                                                                                                                                               |
| ------------------------ | -------------------------- | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `pointer`                | `boolean`                  | `true`             | `false` にすると OS pointer イベントをフォワーダへ injection しません。一時的にカーソルを切り離したいデモトグルやモーダル時に有用です。                                            |
| `keyboard`               | `boolean`                  | `true`             | `false` にすると OS keyboard イベントを injection しません。                                                                                                                       |
| `cursor`                 | `boolean \| CursorOptions` | `false`            | 合成 pointer に追従する仮想カーソル要素を描画します。壁紙ウィンドウ内に OS カーソルは表示されないため有用。                                                                        |
| `autoFocus`              | `boolean`                  | `true`             | `pointerdown` 時に最も近い focusable な祖先にフォーカスを移します。実ブラウザの挙動の再現。                                                                                        |
| `doubleClickThresholdMs` | `number`                   | `500`              | ダブルクリックとして扱う最大間隔（ms）。                                                                                                                                           |
| `clickMoveThresholdPx`   | `number`                   | `5`                | この距離以上カーソルが動いた up は drag と見なし、`click` を抑制します。                                                                                                           |
| `keyboardTarget`         | `KeyboardTargetStrategy`   | `"active-element"` | キーボードイベントの dispatch 先。`"active-element"`（既定 — `useIsFocused` や `<input>` フォーカスと連携）／ `"pointer-target"` ／ `"document"` から選択。                        |
| `pointerCapture`         | `boolean`                  | `true`             | `Element.prototype.{set,release,has}PointerCapture` をプロセスワイドにパッチして capture をフォワーダ経由にします。dnd-kit, react-dnd Pointer backend, Framer Motion drag に必要。 |
| `children`               | `ReactNode`                | –                  | 壁紙のツリー。                                                                                                                                                                     |

## useMimoForwarder

直近の provider が所有する `MimoForwarder` インスタンスを返します。provider の外で使うと例外を投げます。`injectPointer` / `injectKeyboard` のような命令的 API をテストやリプレイから呼びたい場合に便利です。

```tsx
import { useMimoForwarder } from "@fluxlay/react/mimo";

function ReplayButton() {
  const forwarder = useMimoForwarder();
  return (
    <button
      onClick={() => {
        forwarder.injectPointer({ kind: "move", x: 100, y: 100 });
        forwarder.injectPointer({ kind: "button", x: 100, y: 100, button: "left", pressed: true });
        forwarder.injectPointer({ kind: "button", x: 100, y: 100, button: "left", pressed: false });
      }}
    >
      クリックを再生
    </button>
  );
}
```

provider の外でも `null` を許容したい場合は `MimoForwarderContext` を直接購読できます。

## カスタム入力 source: MimoForwarderProvider

`MimoProvider` は常に Fluxlay の OS フックをフォワーダに送り込みます。独自の `pointerSource` / `keyboardSource` を差し込みたい場合（合成ストリームでのユニットテスト、録画したセッションのリプレイ、Fluxlay デスクトップアプリ外での組み込み等）は、低レベルの `MimoForwarderProvider` を使います。

```tsx
import { MimoForwarderProvider, type PointerSource, type KeyboardSource } from "@fluxlay/react/mimo";

const pointerSource: PointerSource = handler => {
  const ws = new WebSocket("ws://localhost:9999/pointer");
  ws.onmessage = ev => handler(JSON.parse(ev.data));
  return () => ws.close();
};

const keyboardSource: KeyboardSource = handler => {
  // ...
  return () => {};
};

export function ReplayRoot() {
  return (
    <MimoForwarderProvider pointerSource={pointerSource} keyboardSource={keyboardSource}>
      <App />
    </MimoForwarderProvider>
  );
}
```

`MimoForwarderProvider` は `MimoForwarderOptions` の全 prop（`MimoProvider` の prop に加えて `pointerSource` / `keyboardSource`）を受け付けます。`PointerSource` は handler を受け取って unsubscribe を返す関数で、座標は対象 document の viewport に対する CSS px です。`KeyboardSource` も同じ形をしています。

## エクスポートされている型

`@fluxlay/react/mimo` から以下がエクスポートされています。

- `MimoForwarder`, `MimoForwarderContext`, `useMimoForwarder`
- `MimoForwarderProvider`, `MimoForwarderProviderProps`
- `MimoForwarderOptions`, `CursorOptions`, `KeyboardTargetStrategy`
- `PointerSource`, `PointerSourceEvent`, `PointerSourceMoveEvent`, `PointerSourceButtonEvent`, `PointerSourceWheelEvent`, `PointerSourceCancelEvent`, `PointerButton`, `PointerType`
- `KeyboardSource`, `KeyboardSourceEvent`, `KeyboardModifiers`
- `Unsubscribe`

## 備考

- `MimoProvider` は壁紙ウィンドウあたり 1 つの forwarder をマウントします。複数マウント自体は許容されています（最後に start したものが capture を取る）が一般的ではありません。
- 合成イベントを使用するため、ブラウザの `isTrusted` ゲートに引っかかる挙動（HTML5 のネイティブ drag-and-drop、`<input>` / `<textarea>` への生テキスト入力、OS のコンテキストメニュー、autoplay 解除等）は trigger できません。多くは Fluxlay 側で代替が用意されています。IME 合成は [`useImeInput`](/ja/studio/developer/reference/sdk/use-ime-input.md) が、OS カーソル不在のフォーカスリングは [`useIsFocused`](/ja/studio/developer/reference/sdk/use-is-focused.md) と仮想カーソルがそれぞれカバーします。
