mcpField
S
solid

solid

github.com/vercel-labs開発18.8k1.1k 回インストール1 日前に更新
リポジトリ

solid について

@json-render/solidは、json-renderの仕様を細粒度リアクティブなSolidコンポーネントツリーに変換します。構造化UIを構築する開発者向けで、状態管理や検証のほか、ストリーミングUIにも対応します。

主な機能

  1. 01リアクティブなSolidコンポーネント描画
  2. 02状態・表示・検証のプロバイダー
  3. 03状態とフォームの組み込みアクション
  4. 04動的プロパティと状態バインディング
  5. 05ストリーミングUIとチャット生成

活用シーン

  1. 01SolidアプリでUI仕様を描画
  2. 02入力をリアクティブな状態にバインド
  3. 03フィールドとフォームを検証
  4. 04ストリーム生成UIを表示

インストール

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

$npx skills add https://github.com/vercel-labs/json-render --skill solid

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

詳細

@json-render/solid

@json-render/solid は、json-render の仕様を細粒度リアクティブな Solid コンポーネントツリーにレンダリングします。

クイックスタート

import { Renderer, JSONUIProvider } from "@json-render/solid";
import type { Spec } from "@json-render/solid";
import { registry } from "./registry";

export function App(props: { spec: Spec | null }) {
  return (
    <JSONUIProvider registry={registry} initialState={{}}>
      <Renderer spec={props.spec} registry={registry} />
    </JSONUIProvider>
  );
}

カタログの作成

import { defineCatalog } from "@json-render/core";
import { schema } from "@json-render/solid/schema";
import { z } from "zod";

export const catalog = defineCatalog(schema, {
  components: {
    Button: {
      props: z.object({
        label: z.string(),
        variant: z.enum(["primary", "secondary"]).nullable(),
      }),
      description: "Clickable button",
    },
    Card: {
      props: z.object({ title: z.string() }),
      description: "Card container",
    },
  },
  actions: {
    submit: { description: "Submit data" },
  },
});

コンポーネントの定義

コンポーネントは、レンダラーから ComponentRenderProps を受け取ります。

interface ComponentRenderProps<P = Record<string, unknown>> {
  element: UIElement<string, P>;
  children?: JSX.Element;
  emit: (event: string) => void;
  on: (event: string) => EventHandle;
  bindings?: Record<string, string>;
  loading?: boolean;
}

例:

import type { BaseComponentProps } from "@json-render/solid";

export function Button(props: BaseComponentProps<{ label: string }>) {
  return (
    <button onClick={() => props.emit("press")}>{props.props.label}</button>
  );
}

レジストリの作成

import { defineRegistry } from "@json-render/solid";
import { catalog } from "./catalog";
import { Card } from "./Card";
import { Button } from "./Button";

const { registry, handlers, executeAction } = defineRegistry(catalog, {
  components: {
    Card,
    Button,
  },
  actions: {
    submit: async (params, setState, state) => {
      // custom action logic
    },
  },
});

仕様の構造

{
  "root": "card1",
  "elements": {
    "card1": {
      "type": "Card",
      "props": { "title": "Hello" },
      "children": ["btn1"]
    },
    "btn1": {
      "type": "Button",
      "props": { "label": "Click me" },
      "on": {
        "press": { "action": "submit" }
      }
    }
  }
}

プロバイダー

  • StateProvider:store を介した状態モデルの読み取り/書き込みと制御モード
  • VisibilityProvider:visible 条件を評価します
  • ValidationProvider:フィールドの検証と validateForm の統合
  • ActionProvider:組み込みアクションとカスタムアクションを実行します
  • JSONUIProvider:プロバイダーをまとめてラップします

フック

  • useStateStore、useStateValue、useStateBinding
  • useVisibility、useIsVisible
  • useActions、useAction
  • useValidation、useOptionalValidation、useFieldValidation
  • useBoundProp
  • useUIStream、useChatUI

組み込みアクション

ActionProvider が自動的に処理します。

  • setState
  • pushState
  • removeState
  • validateForm

動的プロパティとバインディング

ネストしたリストでは、外側の repeat 内で repeat.statePath に { "$item": "field" } を設定できます。

次の式形式がサポートされています。

  • {"$state": "/path"}
  • {"$bindState": "/path"}
  • {"$bindItem": "field"}
  • {"$template": "Hi ${/user/name}"}
  • {"$computed": "fn", "args": {...}}
  • {"$cond": <condition>, "$then": <value>, "$else": <value>}

書き込み可能なバインド値には、コンポーネント内で useBoundProp を使用します。

import { useBoundProp, type BaseComponentProps } from "@json-render/solid";

function Input(props: BaseComponentProps<{ value?: string }>) {
  const [, setValue] = useBoundProp(props.props.value, props.bindings?.value);
  return (
    <input
      value={String(props.props.value ?? "")}
      onInput={(e) => setValue(e.currentTarget.value)}
    />
  );
}

useBoundProp は、スカラー値と書き戻し用のセッターを返します。後続の状態更新がリアクティブに保たれるよう、JSX 内で解決済みのプロパティを読み取ってください。

useStateValue、useStateBinding、および useFieldValidation の state / errors / isValid フィールドは、Solid のリアクティブなアクセサーです。JSX、createMemo、または createEffect 内で関数として呼び出してください。

Solid のリアクティビティに関するルール

  • 値のリアクティビティを保つ必要がある場合、関数シグネチャでコンポーネントのプロパティを分割代入しないでください。
  • 変化する値の読み取りは、JSX 式、createMemo、または createEffect 内に記述してください。
  • コンテキスト値はゲッターベースのオブジェクトを介して公開されるため、利用側は常に最新のシグナルを参照できます。

UI のストリーミング

import { useUIStream, Renderer } from "@json-render/solid";

const stream = useUIStream({ api: "/api/generate-ui" });
await stream.send("Create a support dashboard");

<Renderer
  spec={stream.spec}
  registry={registry}
  loading={stream.isStreaming}
/>;

チャットと UI 生成のワークフローには useChatUI を使用します。

コメント