コンテンツにスキップ

SDKを使う

3つのSDKは共通のプロトコルとランタイムの概念を使います。次の例はビルド済みチェックアウトのローカルパッケージを使います。app.start()は標準入出力を使うため、開発プレビュー経由で表示してください。

SDKとHubは別に導入します。自分のSDKアプリを表示するHubは、LinuxまたはmacOSとNode.js 22以上でnpx @omochi-ui/cli hubとして起動できます。HubがローカルGatewayも自動起動します。インストールとダッシュボードへの接続を参照してください。ローカル検出にはUnixSocketServerTransportが必要で、以下の標準入出力の例は開発プレビュー向けです。

import asyncio
from dataclasses import dataclass
from omochi_ui import ActionContext, App, ui
@dataclass
class State:
temperature: float = 50
result: str | None = None
@dataclass
class RunInput:
temperature: float
app = App(State())
@app.action
async def run(input: RunInput, context: ActionContext[State]):
async with context.update() as state:
state.temperature = input.temperature
state.result = f"Ran at temperature {input.temperature:g}"
def main(state: State) -> None:
form = ui.local("form", RunInput(state.temperature))
ui.text("Hello", key="title", variant="h2")
ui.slider("temperature", 0, 100, bind=form.temperature)
ui.button("Run", on_click=run, input=form, variant="primary")
if state.result:
ui.text(state.result, key="result")
app.mount(main)
asyncio.run(app.start())
import { schema, App } from "@omochi-ui/sdk";
const state: { temperature: number; result: string | null } = {
temperature: 50,
result: null,
};
const app = new App(state);
const run = app.action("run", schema.object({ temperature: schema.number() }), async (input, context) => {
await context.update((current) => { current.temperature = input.temperature; current.result = `Ran at temperature ${input.temperature}`; });
});
app.surface("main", (ui, current) => {
const form = ui.local("form", { temperature: current.temperature });
ui.text("Hello", { key: "title", variant: "h2" });
ui.slider("temperature", 0, 100, { bind: form.field("temperature").bind() });
ui.button("Run", run.call({ temperature: form.field("temperature").value() }), { variant: "primary" });
if (current.result) ui.text(current.result, { key: "result" });
});
await app.start();
use omochi_ui::{ActionInput, Button, ButtonVariant, Input, Slider, Text, TextVariant};
use omochi_ui::{App, Result};
use serde::{Deserialize, Serialize};
struct State {
temperature: f64,
result: Option<String>,
}
#[derive(Deserialize, Serialize, ActionInput)]
struct RunInput {
temperature: f64,
}
impl Default for State {
fn default() -> Self {
Self {
temperature: 50.0,
result: None,
}
}
}
#[tokio::main]
async fn main() -> Result<()> {
let mut app = App::new(State::default());
let run = app.action::<RunInput, _, _>("run", |input, context| async move {
context
.update(|state| {
state.temperature = input.temperature;
state.result = Some(format!("Ran at temperature {}", input.temperature));
})
.await?;
Ok(())
})?;
app.surface("main", move |ui, state| {
let form = ui.local(
"form",
RunInput {
temperature: state.temperature,
},
)?;
ui.add(Text::new("Hello").key("title").variant(TextVariant::H2))?;
ui.add(
Slider::new("temperature", 0.0, 100.0)
.bind(form.field(RunInput::field_temperature()).bind()?),
)?;
ui.add(
Button::new("Run")
.on_press(run.call(RunInputInput {
temperature: Input::expression(
form.field(RunInput::field_temperature()).value(),
),
})?)
.variant(ButtonVariant::Primary),
)?;
if let Some(result) = &state.result {
ui.add(Text::new(result.clone()).key("result"))?;
}
Ok(())
})?;
app.start().await
}

上の例のように、ui.local()が返すLocalのフィールドを入力部品に結び付けます。bind()とvalue()はPointer引数を取りません。先にフィールドを選び、その後に.bind()や.value()を呼びます。フォーム自体の.value()はフォーム全体を参照します。Pythonではform.temperatureをbind=に直接渡し、input=formでフォーム全体を渡すこともできます。

Actionの操作時にレンダラーが入力式を確定するため、Runtimeは確定済みJSONを受け取り、入力途中の値を保存しません。各SDKのフィールド参照はブラウザが持つ入力を参照してください。

TypeScriptは@omochi-ui/sdk、Node専用Transportは@omochi-ui/sdk/nodeから読み込みます。Pythonはomochi_ui、Rustはcrate名omochi-uiをomochi_uiとして使います。

依存関係は同梱exampleのマニフェストを参照してください。TypeScriptは事前ビルド、Pythonは3.11以上、RustはCargoとTokioが必要です。公開エントリーポイントはSDKリファレンスにまとめています。

型付き入力と移行手順の詳細は英語版SDKガイドを参照してください。