minimoon

    A MoonBit UI runtime for WeChat MiniApp Skyline with Elm-style state machines, Val-based UI composition, transactional local state, and generated MiniApp host commands.

    moonbit
    elm-architecture
    tea
    host-runtime
    host-commands
    component-state
    miniapp
    skyline
    incremental-graph
    ui-runtime
    Download zip
    Author
    Version
    0.2.0
    License
    Apache-2.0
    Last updated
    9 days ago
    Downloads
    36

    Dependencies

    #Minimoon

    Build WeChat Skyline MiniApps in MoonBit: describe pages, update typed state, and let Minimoon generate the MiniApp files. No handwritten JavaScript bridge or setData is needed.

    #Project status

    Core lampclaw/minimoon 0.2.0 and optional lampclaw/minimoon_ui 0.1.0 are pre-1.0 candidates. This checkout's default setup below uses source; registry installation is an alternative only after the matching version is published. See project status for publication availability. Implemented capabilities, automated checks, real-host acceptance and publication are separate milestones.

    #What you can build

    • Stateful pages and reusable components with typed events, local state and navigation.
    • HTTP-backed applications with typed requests and optional application-owned shared state.
    • Native, touch-first interfaces using the optional Minimoon UI library; the starter needs only core.

    #Before you start

    Use moon 0.1.20260904 / moonc v0.10.12 or newer, Node >=24.20.0, Bun 1.4.2, Git and WeChat Developer Tools with Skyline support. Existing moon 0.1.20260907 installations need no downgrade. See environment setup for version checks and the pinned CI toolchain.

    #Create your first app

    In a development directory with enough free space, use two sibling directories: minimoon/ for the framework and my-app/ for your application. Run these commands in a terminal with MoonBit, Node and Bun available:

    git clone https://github.com/lucavance/minimoon.git minimoon cd minimoon bun install --frozen-lockfile moon update moon install --path src/cmd/minimoon minimoon --version minimoon init ../my-app --minimoon-root "$PWD" cd ../my-app bun install minimoon build . minimoon verify . --candidate

    Use a new or empty my-app/. The generated moon.work binds this app to the sibling source checkout, so no unpublished core registry package is required. Keep that checkout while developing; the quickstart explains the separate registry setup.

    Import my-app/dist/, not the repository root, into WeChat Developer Tools. Enable Skyline, ES6-to-ES5 transformation, enhanced compilation and minification (setting.es6=true, setting.enhance=true, setting.minified=true); use an online minimum base library of 3.17.0. For your AppID, edit only the ignored private configuration described in the quickstart.

    You should see Hello Minimoon, a counter starting at 0, a name input and Open details. Tap +1: the counter becomes 1. Open Details and return. A passed CLI check is automated validation, not proof that these host interactions passed.

    #Make your first change

    In your generated app's src/pages/home/page.mbt, find the initial model inside program() and change name: "Minimoon" to name: "My App". From my-app/, rerun minimoon build . and minimoon verify . --candidate. Cold-restart the MiniApp: the heading should now read Hello My App.

    Edit src/, not dist/ or generated/. For rebuild-on-change, run minimoon dev . in the app directory; this watches and rebuilds files, not a browser preview server.

    #What page code looks like

    This small illustration shows the ordinary page / Val style. It is not a replacement for the starter's complete Home page and its navigation/tests:

    pub fn program() -> @minimoon.Page {
    @minimoon.page(
    id="home",
    route=@minimoon.route("pages/home/home"),
    title="Home",
    build=_ => {
    let (count, update_count) = @minimoon.create_variable(0)
    count.view(value => @minimoon.div([
    @minimoon.h1(value.to_string()),
    @minimoon.button(
    on_tap=update_count(current => current + 1),
    event_key="increment",
    "+1",
    ),
    ]))
    },
    )
    }

    count is a read-only value, update_count creates the update command, and view describes what to display. The starter imports lampclaw/minimoon in its page's moon.pkg. More complex behavior uses typed Model/Msg updates; components are ordinary functions, not a mandatory object hierarchy.

    #Learn next

    1. Pages, state and components
    2. Typed HTTP requests
    3. Navigation and layout
    4. Application-owned shared state
    5. Optional Minimoon UI

    #Examples

    ExampleUse it for
    Starter, created by minimoon initStarting your own two-page application
    ConformanceCore behavior: 7 pages, 4 native Tabs — 首页 / 交互 / 平台 / 应用
    UI ShowcaseExploring native UI components across 6 pages

    Conformance's Platform page owns the public HTTP scenarios. From the framework checkout, bun run check:http-live runs an optional public-API probe; it is not a WeChat host test.

    #Boundaries and next steps

    Minimoon targets WeChat Skyline, not browser DOM compatibility or a general cross-platform renderer. UI is optional, and applications supply their own backends, credentials and production request domains.

    The near-term focus is a reliable onboarding path and release preparation. Dynamic account/workspace scopes and additional targets remain deferred, not promised features or dates. Follow the Roadmap for priorities rather than treating this README as a task tracker.

    #Contributing and internals

    Start with the documentation index. The architecture, API ergonomics, repository validation and release workflow and host checklist cover the details needed by framework contributors. Full repository gates and release evidence are not prerequisites for writing your first application.

    See LICENSE and third-party notices for licensing and Rabbita/RUI provenance.

    #Minimoon authoring contract

    This package-level README is compiled with the root package. It keeps the primary authoring examples synchronized with the public API while the module README remains the longer user-facing introduction.

    #Page and component composition

    Ordinary page builders and functions returning Val[Node] are the main authoring path. Local state is created inside the builder; render callbacks stay pure. elmish_page below remains a convenience for simple one-model pages.

    ///|
    #warnings("-unused_value")
    fn readme_composition_page() -> Page {
    page(
    id="readme_composition",
    route=route("pages/readme_composition/readme_composition"),
    title="Composition",
    build=_ => {
    let (count, update_count) = create_variable(0)
    count.view(value => {
    div([
    h1(value.to_string()),
    button(
    on_tap=update_count(current => current + 1),
    event_key="increment",
    "+1",
    ),
    ])
    })
    },
    )
    }

    #Elm-style convenience

    Emit[Msg] is a callable message sink. Mapping it adapts child payloads without exposing a mutable signal or a renderer patch.

    ///|
    priv enum ReadmePageMsg {
    ReadmeIncrement
    ReadmeNameChanged(String)
    }

    ///|
    #warnings("-unused_value")
    fn readme_page() -> Page {
    elmish_page(
    id="readme",
    route=route("pages/readme/readme"),
    title="Readme",
    model=(0, "MoonBit"),
    update=(model, message, _emit) => {
    match message {
    ReadmeIncrement => no_cmd((model.0 + 1, model.1))
    ReadmeNameChanged(name) => with_cmd((model.0, name), none)
    }
    },
    view=(model, emit) => {
    div([
    button(on_tap=emit(ReadmeIncrement), model.0.to_string()),
    input(value=model.1, on_input=value => emit(ReadmeNameChanged(value))),
    ])
    },
    )
    }

    #HTTP requests

    HTTP requests use their page or application's declared Request capability. Non-2xx status codes are transport successes; invalid arguments are deferred InvalidPayload errors. The runtime executing the command owns the request, not its result emitter. For an App-owned request, send a message to App and return request from the App update; a request executed by a page still ends with that page's lifetime.

    ///|
    #warnings("-unused_value")
    fn readme_request(resolve : Emit[Result[RequestResult, HostError]]) -> Cmd {
    request(
    "https://httpbingo.org/post",
    resolve,
    http_method=Post,
    query=[query("tag", "one"), query("tag", "two")],
    headers={ "X-Minimoon-Test": "public-smoke" },
    body=JsonBody(Json::object({ "message": Json::string("测试") })),
    timeout_ms=15000,
    )
    }

    #Optional application state

    Without application, configured page factories take no arguments. With it, the application factory returns App[Deps] and every page factory receives those Deps. App constructors return Shared[Model], while page-local constructors return Val[Model]. Bind/select creates a page-owned projection.

    Unlike page-local emitters, the App emitter below delivers across the page/App boundary after the page transaction commits. It remains usable after another page unloads, until its App is disposed.

    ///|
    priv struct ReadmeAppDeps {
    count : Shared[Int]
    change_count : Emit[Int]
    }

    ///|
    #warnings("-unused_value")
    fn readme_app() -> App[ReadmeAppDeps] {
    app(build=context => {
    let (count, change_count) = context.create_pure_state(0, update=(
    count,
    delta : Int,
    ) => count + delta)
    { count, change_count, }
    })
    }

    ///|
    #warnings("-unused_value")
    fn readme_shared_page(deps : ReadmeAppDeps) -> Page {
    page(
    id="readme_shared",
    route=route("pages/readme-shared/readme-shared"),
    title="Shared state",
    build=context => {
    context
    .bind(deps.count)
    .view(count => {
    button(
    on_tap=(deps.change_count)(1),
    event_key="readme/shared/increment",
    "Shared count: " + count.to_string(),
    )
    })
    },
    )
    }

    #Local state and resources

    State constructors return the read-only incremental value and its emitter. One-shot resources start when their committed scope is initialized, and their first successfully committed terminal completion wins.

    ///|
    priv enum ReadmeLocalMsg {
    ReadmeAdd
    }

    ///|
    fn readme_local_authoring(input_value : Val[Int]) -> Val[Node] {
    let (pure, pure_emit) = create_pure_state(0, update=(
    model,
    _message : ReadmeLocalMsg,
    ) => model + 1)
    let (state, state_emit) = create_state(0, update=(
    model,
    _message : ReadmeLocalMsg,
    _emit,
    ) => with_cmds(model + 1, []))
    let (initialized, initialized_emit) = create_state_with_init(
    init=emit => (0, emit(ReadmeAdd)),
    update=(model, _message : ReadmeLocalMsg, _emit) => no_cmd(model + 1),
    )
    let (input_state, input_emit) = create_state_with_input(
    input=input_value,
    init=(_emit, input) => no_cmd(input),
    update=(model, input, _message : ReadmeLocalMsg, _emit) => {
    no_cmd(model + input)
    },
    )
    let (flag, set_flag) = create_variable(false)
    let resource = create_resource(done => done(Ok("ready")))
    Val::view6(pure, state, initialized, input_state, flag, resource, (
    a,
    b,
    c,
    d,
    enabled,
    status,
    ) => {
    let status_text = match status {
    Pending => "pending"
    Loaded(value) => value
    Failed(_) => "failed"
    }
    div([
    button(on_tap=pure_emit(ReadmeAdd), a.to_string()),
    button(on_tap=state_emit(ReadmeAdd), b.to_string()),
    button(on_tap=initialized_emit(ReadmeAdd), c.to_string()),
    button(on_tap=input_emit(ReadmeAdd), d.to_string()),
    button(on_tap=set_flag(value => !value), enabled.to_string()),
    p(status_text),
    ])
    })
    }

    ///|
    #warnings("-unused_value")
    fn readme_local_page() -> Page {
    page(
    id="readme_local",
    route=route("pages/readme-local/readme-local"),
    title="Readme local",
    build=_ => readme_local_authoring(Val::constant(2)),
    )
    }

    Enumerate

    pub trait Enumerate {
    fn tag(Self) -> String
    }

    IsChildren

    pub trait IsChildren {
    fn to_nodes(Self) -> Array[Node]
    }

    App

    type App[Deps]

    An optional application definition. Constructing it does not run effects.

    App::capabilities

    fn[Deps] App::capabilities(self : App[Deps]) -> Array[Capability]

    App::create_runtime

    fn[Deps] App::create_runtime(self : App[Deps]) -> AppRuntime[Deps]

    App::preview

    fn[Deps, A] App::preview(self : App[Deps], inspect : (Deps) -> A) -> A

    Inspect initial page contracts without launching effects or subscriptions.

    AppContext

    type AppContext

    AppContext::create_pure_state

    fn[Model : Eq, Msg] AppContext::create_pure_state(self : AppContext, initial : Model, update~ : (Model, Msg) -> Model) -> (Shared[Model], Emit[Msg])

    AppContext::create_state

    fn[Model : Eq, Msg] AppContext::create_state(self : AppContext, initial : Model, update~ : (Model, Msg, Emit[Msg]) -> (Model, Cmd), subscriptions? : (Model, Emit[Msg]) -> Sub) -> (Shared[Model], Emit[Msg])

    AppContext::create_state_with_init

    fn[Model : Eq, Msg] AppContext::create_state_with_init(self : AppContext, init~ : (Emit[Msg]) -> (Model, Cmd), update~ : (Model, Msg, Emit[Msg]) -> (Model, Cmd), subscriptions? : (Model, Emit[Msg]) -> Sub) -> (Shared[Model], Emit[Msg])

    AppContext::every

    fn AppContext::every(self : AppContext, key~ : String, interval_ms~ : Int, command~ : Cmd) -> Sub

    AppContext::lifecycle

    fn AppContext::lifecycle(self : AppContext, hook : AppLifecycleHook, decode : (Json) -> Result[Cmd, DecodeError]) -> Sub

    AppContext::on_hide

    fn AppContext::on_hide(self : AppContext, command : Cmd) -> Sub

    AppContext::on_launch

    fn AppContext::on_launch(self : AppContext, command : Cmd) -> Sub

    AppContext::on_show

    fn AppContext::on_show(self : AppContext, command : Cmd) -> Sub

    AppLifecycleHook

    pub(all) enum AppLifecycleHook {
    Launch
    Show
    Hide
    } derive(Eq)

    AppRuntime

    type AppRuntime[Deps]

    AppRuntime::create_page

    fn[Deps] AppRuntime::create_page(self : AppRuntime[Deps], page : Page, input? : Map[String, String], layout? : PageLayout) -> Result[PageRuntime, DecodeError]

    AppRuntime::deps

    fn[Deps] AppRuntime::deps(self : AppRuntime[Deps]) -> Deps

    AppRuntime::dispatch

    fn[Deps] AppRuntime::dispatch(self : AppRuntime[Deps], command : Cmd) -> String

    AppRuntime::dispose

    fn[Deps] AppRuntime::dispose(self : AppRuntime[Deps]) -> String

    AppRuntime::flush

    fn[Deps] AppRuntime::flush(self : AppRuntime[Deps]) -> String

    AppRuntime::has_ready_work

    fn[Deps] AppRuntime::has_ready_work(self : AppRuntime[Deps]) -> Bool

    Ready work excludes unresolved host effects and future subscription ticks.

    AppRuntime::lifecycle

    fn[Deps] AppRuntime::lifecycle(self : AppRuntime[Deps], hook : String, payload_json : String) -> String

    AppRuntime::resolve_effect

    fn[Deps] AppRuntime::resolve_effect(self : AppRuntime[Deps], request_id : String, phase : String, payload_json : String) -> String

    AppRuntime::subscription

    fn[Deps] AppRuntime::subscription(self : AppRuntime[Deps], key : String) -> String

    Capability

    pub(all) enum Capability {
    Login
    GetStorage
    SetStorage
    Request
    ShowToast
    GetLocation
    ChooseMedia
    RequestPayment
    NavigateTo
    RedirectTo
    SwitchTab
    NavigateBack
    MeasureNodes
    } derive(Eq,
    Debug
    )

    Capability::name

    fn Capability::name(self : Capability) -> String

    ChooseMediaResult

    pub struct ChooseMediaResult {
    temp_files : Array[MediaFile]
    media_type : String?
    }

    Cmd

    type Cmd

    DecodeError

    pub struct DecodeError {
    message : String
    }

    DecodeError::message

    fn DecodeError::message(self : DecodeError) -> String

    Emit

    pub(all) struct Emit[Msg]((Msg) -> Cmd)

    Emit::map

    fn[A, B] Emit::map(self : Emit[A], map : (B) -> A) -> Emit[B]

    FocusDetail

    pub struct FocusDetail {
    value : String
    height : Int
    }

    Native MiniApp focus payload shared by input and textarea.

    FormButtonType

    pub(all) enum FormButtonType {
    SubmitForm
    ResetForm
    } derive(Eq,
    Debug
    )

    HostError

    pub struct HostError {
    capability : Capability
    kind : HostErrorKind
    message : String
    code : String?
    raw : Json
    }

    HostErrorKind

    pub(all) enum HostErrorKind {
    Failed
    Unavailable
    InvalidPayload
    } derive(Eq,
    Debug
    )

    HttpMethod

    pub(all) enum HttpMethod {
    Get
    Post
    Put
    Delete
    Head
    Options
    } derive(Eq,
    Debug
    )

    ImageLoadDetail

    pub struct ImageLoadDetail {
    width : Double
    height : Double
    } derive(Eq,
    Debug
    )

    ImageMode

    pub(all) enum ImageMode {
    ScaleToFill
    AspectFit
    AspectFill
    WidthFix
    HeightFix
    ImageCenter
    } derive(Eq,
    Debug
    )

    InputBlurDetail

    pub struct InputBlurDetail {
    value : String
    }

    Native MiniApp input blur payload.

    InputType

    pub(all) enum InputType {
    TextInput
    NumberInput
    DigitInput
    IdCardInput
    } derive(Eq,
    Debug
    )

    KeyedNode

    type KeyedNode

    LayoutRect

    pub(all) struct LayoutRect {
    left : Double
    top : Double
    width : Double
    height : Double
    } derive(Eq, ToJson,
    Debug
    )

    A rectangle in logical px, relative to the screen's top-left corner.

    LocationResult

    pub struct LocationResult {
    latitude : Double
    longitude : Double
    speed : Double?
    accuracy : Double?
    altitude : Double?
    vertical_accuracy : Double?
    horizontal_accuracy : Double?
    }

    LoginResult

    pub struct LoginResult {
    code : String
    }

    MediaFile

    pub struct MediaFile {
    temp_file_path : String
    size : Int?
    file_type : String?
    width : Int?
    height : Int?
    duration : Double?
    thumb_temp_file_path : String?
    }

    pub(all) enum NavigatorMode {
    Navigate
    Redirect
    } derive(Eq)

    Node

    type Node

    impl IsChildren for Node
    impl Eq for Node

    NodeRect

    pub struct NodeRect {
    id : String
    left : Double
    top : Double
    right : Double
    bottom : Double
    width : Double
    height : Double
    } derive(Eq,
    Debug
    )

    A viewport-relative rectangle in logical pixels. A missing node yields None.

    Page

    type Page

    Page::contract

    fn Page::contract(self : Page) -> String

    Page::contract_json

    fn Page::contract_json(self : Page) -> Json

    Page::create_runtime

    fn Page::create_runtime(self : Page, input? : Map[String, String], layout? : PageLayout) -> Result[PageRuntime, DecodeError]

    Page::id

    fn Page::id(self : Page) -> String

    Page::initial_tree

    fn Page::initial_tree(self : Page, layout? : PageLayout) -> Json

    Page::route

    fn Page::route(self : Page) -> String

    Page::title

    fn Page::title(self : Page) -> String

    Page::wxml

    fn Page::wxml(self : Page) -> String

    PageContext

    type PageContext

    PageContext::bind

    fn[T : Eq] PageContext::bind(self : PageContext, shared : Shared[T]) -> Val[T]

    PageContext::every

    fn PageContext::every(self : PageContext, key~ : String, interval_ms~ : Int, command~ : Cmd) -> Sub

    PageContext::layout

    fn PageContext::layout(self : PageContext) -> Val[PageLayout]

    PageContext::lifecycle

    fn PageContext::lifecycle(self : PageContext, hook : PageLifecycleHook, decode : (Json) -> Result[Cmd, DecodeError]) -> Sub

    PageContext::on_hide

    fn PageContext::on_hide(self : PageContext, command : Cmd) -> Sub

    PageContext::on_load

    fn PageContext::on_load(self : PageContext, command : Cmd) -> Sub

    PageContext::on_pull_down_refresh

    fn PageContext::on_pull_down_refresh(self : PageContext, command : Cmd) -> Sub

    PageContext::on_reach_bottom

    fn PageContext::on_reach_bottom(self : PageContext, command : Cmd) -> Sub

    PageContext::on_show

    fn PageContext::on_show(self : PageContext, command : Cmd) -> Sub

    PageContext::on_unload

    fn PageContext::on_unload(self : PageContext, command : Cmd) -> Sub

    PageContext::select

    fn[T : Eq, U : Eq] PageContext::select(self : PageContext, shared : Shared[T], select : (T) -> U) -> Val[U]

    PageLayout

    pub(all) struct PageLayout {
    window : WindowMetrics?
    menu_button : LayoutRect?
    } derive(Eq, ToJson,
    Debug
    )

    Page-owned layout facts, separate from immutable route input.

    PageLayout::from_json

    fn PageLayout::from_json(value : Json) -> PageLayout

    Decode the owned host layout envelope, dropping unavailable/invalid parts. This never substitutes device dimensions or reads a host API.

    PageLayout::unavailable

    fn PageLayout::unavailable() -> PageLayout

    PageLifecycleHook

    pub(all) enum PageLifecycleHook {
    Load
    Show
    Hide
    Unload
    PullDownRefresh
    ReachBottom
    } derive(Eq)

    PageRuntime

    type PageRuntime

    PageRuntime::dispatch

    fn PageRuntime::dispatch(self : PageRuntime, event_key : String, payload_json : String) -> String

    PageRuntime::dispatch_batch

    fn PageRuntime::dispatch_batch(self : PageRuntime, events_json : String) -> String

    PageRuntime::dispose

    fn PageRuntime::dispose(self : PageRuntime) -> String

    PageRuntime::flush

    fn PageRuntime::flush(self : PageRuntime) -> String

    Drain ready local completions and synchronize committed application values.

    PageRuntime::has_ready_work

    fn PageRuntime::has_ready_work(self : PageRuntime) -> Bool

    Pending host requests and future subscription ticks are not ready work.

    PageRuntime::lifecycle

    fn PageRuntime::lifecycle(self : PageRuntime, hook : String, payload_json : String) -> String

    PageRuntime::mount

    fn PageRuntime::mount(self : PageRuntime) -> String

    PageRuntime::page_id

    fn PageRuntime::page_id(self : PageRuntime) -> String

    PageRuntime::refresh

    fn PageRuntime::refresh(self : PageRuntime) -> String

    Synchronize committed application values through the page transaction.

    PageRuntime::resolve_effect

    fn PageRuntime::resolve_effect(self : PageRuntime, request_id : String, phase : String, payload_json : String) -> String

    PageRuntime::snapshot

    fn PageRuntime::snapshot(self : PageRuntime) -> String

    PageRuntime::subscription

    fn PageRuntime::subscription(self : PageRuntime, key : String, payload_json : String) -> String

    PageRuntime::update_layout

    fn PageRuntime::update_layout(self : PageRuntime, layout : PageLayout) -> String

    Update visible layout transactionally; hidden pages retain only the latest metrics until Show. Invalid readings retain the last usable information.

    PaymentParams

    pub struct PaymentParams {
    time_stamp : String
    nonce_str : String
    package_value : String
    sign_type : String
    pay_sign : String
    }

    PaymentParams::new

    fn PaymentParams::new(time_stamp~ : String, nonce_str~ : String, package_value~ : String, sign_type~ : String, pay_sign~ : String) -> PaymentParams

    Query

    pub struct Query {
    name : String
    value : String
    }

    RequestBody

    pub(all) enum RequestBody {
    JsonBody(Json)
    FormBody(Array[(String, String)])
    TextBody(String)
    }

    RequestResult

    pub struct RequestResult {
    status_code : Int
    data : Json
    headers : Map[String, String]
    cookies : Array[String]
    }

    Route

    pub struct Route {
    path : String
    query : Array[Query]
    }

    Route::has_query

    fn Route::has_query(self : Route) -> Bool

    Route::path

    fn Route::path(self : Route) -> String

    Route::url

    fn Route::url(self : Route) -> String

    Route::with_query

    fn Route::with_query(self : Route, query : Array[Query]) -> Route

    ScrollDetail

    pub struct ScrollDetail {
    scroll_left : Double
    scroll_top : Double
    scroll_height : Double
    scroll_width : Double
    delta_x : Double
    delta_y : Double
    }

    SemanticRole

    pub(all) enum SemanticRole {
    GenericRole
    ButtonRole
    GroupRole
    HeadingRole
    RegionRole
    NavigationRole
    TabRole
    TabListRole
    TabPanelRole
    DialogRole
    MenuRole
    MenuItemRole
    MenuItemCheckboxRole
    MenuItemRadioRole
    SeparatorRole
    AlertRole
    AlertDialogRole
    CheckboxRole
    RadioRole
    RadioGroupRole
    SwitchRole
    TextboxRole
    ComboboxRole
    ListboxRole
    OptionRole
    SliderRole
    ProgressbarRole
    StatusRole
    TooltipRole
    TableRole
    RowRole
    CellRole
    ColumnHeaderRole
    } derive(Eq,
    Debug
    )

    Semantics

    type Semantics

    Shared

    type Shared[T]

    A read-only application value. Bind it to a page before composing a view.

    Status

    pub enum Status[T] {
    Pending
    Loaded(T)
    Failed(Error)
    }

    impl Enumerate for Status[T]
    impl Eq for Status[T]

    StorageResult

    pub struct StorageResult {
    data : Json
    }

    Sub

    type Sub

    Sub::batch

    fn Sub::batch(subscriptions : Array[Sub]) -> Sub

    Sub::none

    fn Sub::none() -> Sub

    TextareaBlurDetail

    pub struct TextareaBlurDetail {
    value : String
    cursor : Int
    }

    Native MiniApp textarea blur payload.

    TouchDetail

    pub struct TouchDetail {
    touches : Array[TouchPoint]
    changed_touches : Array[TouchPoint]
    timestamp : Double
    } derive(Eq,
    Debug
    )

    TouchPoint

    pub struct TouchPoint {
    identifier : Int
    client_x : Double
    client_y : Double
    page_x : Double
    page_y : Double
    } derive(Eq,
    Debug
    )

    Val

    type Val[A]

    Val::assoc

    fn[K : Hash + Eq, V : Eq, C : Eq] Val::assoc(self : Val[
    Vector
    [(K, V)]], build : (K, Val[V]) -> Val[C]) -> Val[
    Vector
    [C]]

    Val::assoc_by

    fn[K : Hash + Eq, V : Eq, C : Eq] Val::assoc_by(self : Val[
    Vector
    [V]], build : (K, Val[V]) -> Val[C], by~ : (V) -> K) -> Val[
    Vector
    [C]]

    Val::constant

    fn[A] Val::constant(value : A) -> Val[A]

    Val::enumerate

    fn[E : Enumerate + Eq, C : Eq] Val::enumerate(self : Val[E], build : (E, Val[E]) -> Val[C]) -> Val[C]

    Val::enumerate_bounded_by

    fn[E : Eq, C : Eq] Val::enumerate_bounded_by(self : Val[E], capacity~ : Int, build~ : (E, Val[E]) -> Val[C], by~ : (E) -> String) -> Val[C]

    Cache at most capacity dynamic branches, evicting the least-recently used inactive branch after a successful candidate commit.

    Val::enumerate_by

    fn[E : Eq, C : Eq] Val::enumerate_by(self : Val[E], build : (E, Val[E]) -> Val[C], by~ : (E) -> String) -> Val[C]

    Val::map

    fn[A : Eq, B] Val::map(self : Val[A], map : (A) -> B) -> Val[B]

    Val::map2

    fn[A : Eq, B : Eq, C] Val::map2(a : Val[A], b : Val[B], map : (A, B) -> C) -> Val[C]

    Val::map3

    fn[A : Eq, B : Eq, C : Eq, D] Val::map3(a : Val[A], b : Val[B], c : Val[C], map : (A, B, C) -> D) -> Val[D]

    Val::map4

    fn[A : Eq, B : Eq, C : Eq, D : Eq, E] Val::map4(a : Val[A], b : Val[B], c : Val[C], d : Val[D], map : (A, B, C, D) -> E) -> Val[E]

    Val::map5

    fn[A : Eq, B : Eq, C : Eq, D : Eq, E : Eq, F] Val::map5(a : Val[A], b : Val[B], c : Val[C], d : Val[D], e : Val[E], map : (A, B, C, D, E) -> F) -> Val[F]

    Val::map6

    fn[A : Eq, B : Eq, C : Eq, D : Eq, E : Eq, F : Eq, G] Val::map6(a : Val[A], b : Val[B], c : Val[C], d : Val[D], e : Val[E], f : Val[F], map : (A, B, C, D, E, F) -> G) -> Val[G]

    Val::map7

    fn[A : Eq, B : Eq, C : Eq, D : Eq, E : Eq, F : Eq, G : Eq, H] Val::map7(a : Val[A], b : Val[B], c : Val[C], d : Val[D], e : Val[E], f : Val[F], g : Val[G], map : (A, B, C, D, E, F, G) -> H) -> Val[H]

    Val::map8

    fn[A : Eq, B : Eq, C : Eq, D : Eq, E : Eq, F : Eq, G : Eq, H : Eq, I] Val::map8(a : Val[A], b : Val[B], c : Val[C], d : Val[D], e : Val[E], f : Val[F], g : Val[G], h : Val[H], map : (A, B, C, D, E, F, G, H) -> I) -> Val[I]

    Val::map9

    fn[A : Eq, B : Eq, C : Eq, D : Eq, E : Eq, F : Eq, G : Eq, H : Eq, I : Eq, J] Val::map9(a : Val[A], b : Val[B], c : Val[C], d : Val[D], e : Val[E], f : Val[F], g : Val[G], h : Val[H], i : Val[I], map : (A, B, C, D, E, F, G, H, I) -> J) -> Val[J]

    Val::switch

    fn[E : Enumerate + Eq, C : Eq] Val::switch(self : Val[E], build : (E, Val[E]) -> Val[C]) -> Val[C]

    Val::switch_by

    fn[E : Eq, C : Eq] Val::switch_by(self : Val[E], build : (E, Val[E]) -> Val[C], by~ : (E) -> String) -> Val[C]

    Val::view

    fn[A : Eq] Val::view(self : Val[A], render : (A) -> Node) -> Val[Node]

    Val::view2

    fn[A : Eq, B : Eq] Val::view2(a : Val[A], b : Val[B], render : (A, B) -> Node) -> Val[Node]

    Val::view3

    fn[A : Eq, B : Eq, C : Eq] Val::view3(a : Val[A], b : Val[B], c : Val[C], render : (A, B, C) -> Node) -> Val[Node]

    Val::view4

    fn[A : Eq, B : Eq, C : Eq, D : Eq] Val::view4(a : Val[A], b : Val[B], c : Val[C], d : Val[D], render : (A, B, C, D) -> Node) -> Val[Node]

    Val::view5

    fn[A : Eq, B : Eq, C : Eq, D : Eq, E : Eq] Val::view5(a : Val[A], b : Val[B], c : Val[C], d : Val[D], e : Val[E], render : (A, B, C, D, E) -> Node) -> Val[Node]

    Val::view6

    fn[A : Eq, B : Eq, C : Eq, D : Eq, E : Eq, F : Eq] Val::view6(a : Val[A], b : Val[B], c : Val[C], d : Val[D], e : Val[E], f : Val[F], render : (A, B, C, D, E, F) -> Node) -> Val[Node]

    Val::view7

    fn[A : Eq, B : Eq, C : Eq, D : Eq, E : Eq, F : Eq, G : Eq] Val::view7(a : Val[A], b : Val[B], c : Val[C], d : Val[D], e : Val[E], f : Val[F], g : Val[G], render : (A, B, C, D, E, F, G) -> Node) -> Val[Node]

    Val::view8

    fn[A : Eq, B : Eq, C : Eq, D : Eq, E : Eq, F : Eq, G : Eq, H : Eq] Val::view8(a : Val[A], b : Val[B], c : Val[C], d : Val[D], e : Val[E], f : Val[F], g : Val[G], h : Val[H], render : (A, B, C, D, E, F, G, H) -> Node) -> Val[Node]

    Val::view9

    fn[A : Eq, B : Eq, C : Eq, D : Eq, E : Eq, F : Eq, G : Eq, H : Eq, I : Eq] Val::view9(a : Val[A], b : Val[B], c : Val[C], d : Val[D], e : Val[E], f : Val[F], g : Val[G], h : Val[H], i : Val[I], render : (A, B, C, D, E, F, G, H, I) -> Node) -> Val[Node]

    WindowMetrics

    pub(all) struct WindowMetrics {
    window_width : Double
    window_height : Double
    screen_width : Double
    screen_height : Double
    screen_top : Double
    status_bar_height : Double
    safe_area : LayoutRect?
    } derive(Eq, ToJson,
    Debug
    )

    Synchronous window information. The safe area may be unavailable.

    app

    fn[Deps] app(build~ : (AppContext) -> Deps, capabilities? : Array[Capability]) -> App[Deps]

    attempt

    fn[A, E : Error] attempt(to_cmd : Emit[Result[A, E]], f : async () -> A raise E) -> Cmd

    batch

    fn batch(commands : Array[Cmd]) -> Cmd

    button

    fn button(on_tap~ : Cmd, event_key? : String, id? : String, class? : String, style? : String, data_section? : String, semantics? : Semantics, disabled? : Bool, label : String) -> Node

    button_children

    fn[C : IsChildren] button_children(on_tap~ : Cmd, event_key? : String, disabled? : Bool, form_type? : FormButtonType, name? : String, id? : String, class? : String, style? : String, data_section? : String, semantics? : Semantics, children : C) -> Node

    Native button with rich children. The existing string-label button is unchanged.

    checkbox

    fn[C : IsChildren] checkbox(value~ : String, checked? : Bool, disabled? : Bool, color? : String, id? : String, class? : String, style? : String, children : C) -> Node

    checkbox_group

    fn[C : IsChildren] checkbox_group(name? : String, on_change~ : Emit[Array[String]], event_key? : String, id? : String, class? : String, style? : String, data_section? : String, children : C) -> Node

    choose_media

    fn choose_media(resolve : Emit[Result[ChooseMediaResult, HostError]]) -> Cmd

    create_pure_state

    fn[Model : Eq, Msg] create_pure_state(initial : Model, update~ : (Model, Msg) -> Model) -> (Val[Model], Emit[Msg])

    create_resource

    fn[T : Eq] create_resource(load : (Emit[Result[T, Error]]) -> Cmd) -> Val[Status[T]]

    create_state

    fn[Model : Eq, Msg] create_state(initial : Model, update~ : (Model, Msg, Emit[Msg]) -> (Model, Cmd), subscriptions? : (Model, Emit[Msg]) -> Sub) -> (Val[Model], Emit[Msg])

    create_state_with_init

    fn[Model : Eq, Msg] create_state_with_init(init~ : (Emit[Msg]) -> (Model, Cmd), update~ : (Model, Msg, Emit[Msg]) -> (Model, Cmd), subscriptions? : (Model, Emit[Msg]) -> Sub) -> (Val[Model], Emit[Msg])

    create_state_with_input

    fn[Model : Eq, Msg, Input : Eq] create_state_with_input(init~ : (Emit[Msg], Input) -> (Model, Cmd), update~ : (Model, Input, Msg, Emit[Msg]) -> (Model, Cmd), subscriptions? : (Model, Input, Emit[Msg]) -> Sub, input~ : Val[Input]) -> (Val[Model], Emit[Msg])

    create_variable

    fn[Model : Eq] create_variable(initial : Model) -> (Val[Model], Emit[(Model) -> Model])

    decode_error

    fn decode_error(message : String) -> DecodeError

    delay

    fn delay(command : Cmd, milliseconds : Int) -> Cmd

    div

    fn[C : IsChildren] div(id? : String, class? : String, style? : String, data_section? : String, semantics? : Semantics, children : C) -> Node

    effect

    fn effect(f : async () -> Unit noraise) -> Cmd

    elmish_page

    fn[Model : Eq, Msg] elmish_page(id~ : String, route~ : Route, title~ : String, model~ : Model, update~ : (Model, Msg, Emit[Msg]) -> (Model, Cmd), view~ : (Model, Emit[Msg]) -> Node, capabilities? : Array[Capability], init? : (Emit[Msg]) -> Cmd, subscriptions? : (PageContext, Model, Emit[Msg]) -> Sub) -> Page

    Build the common Elm-style page shape directly. The application-facing view remains model-first, while subscriptions can use the page-owned lifecycle context without an extra wrapper function.

    form

    fn[C : IsChildren] form(on_submit~ : Emit[Map[String, Json]], on_reset? : Cmd, submit_key? : String, reset_key? : String, id? : String, class? : String, style? : String, children : C) -> Node

    fragment

    fn fragment(children : Array[Node]) -> Node

    get_location

    fn get_location(resolve : Emit[Result[LocationResult, HostError]]) -> Cmd

    get_storage

    fn get_storage(key : String, resolve : Emit[Result[StorageResult, HostError]]) -> Cmd

    fn[C : IsChildren] h1(id? : String, class? : String, style? : String, data_section? : String, semantics? : Semantics, children : C) -> Node

    image

    fn image(src~ : String, alt? : String, mode? : ImageMode, on_load? : Emit[ImageLoadDetail], on_error? : Emit[String], load_key? : String, error_key? : String, id? : String, class? : String, style? : String, data_section? : String, semantics? : Semantics) -> Node

    input

    fn input(value~ : String, on_input~ : Emit[String], input_type? : InputType, maxlength? : Int, password? : Bool, selection_start? : Int, selection_end? : Int, name? : String, event_key? : String, disabled? : Bool, focus? : Bool, on_confirm? : Emit[String], confirm_key? : String, on_focus? : Emit[FocusDetail], focus_key? : String, on_blur? : Emit[InputBlurDetail], blur_key? : String, id? : String, class? : String, style? : String, data_section? : String, placeholder? : String, semantics? : Semantics) -> Node

    keyed

    fn keyed(key : String, node : Node) -> KeyedNode

    keyed_fragment

    fn keyed_fragment(children : Array[KeyedNode]) -> Node

    label

    fn[C : IsChildren] label(for_id~ : String, id? : String, class? : String, style? : String, children : C) -> Node

    layer

    fn[C : IsChildren] layer(id~ : String, children : C) -> Node

    A declarative page layer. Its content must be enclosed by layer_root. Layers remain part of their original Val scope and event ownership; only their host location changes. No registry retains removed branch content.

    layer_root

    fn[C : IsChildren] layer_root(id? : String, class? : String, style? : String, children : C) -> Node

    Place all declarative layers after the content, outside scrolling and clipped containers. Call once at the page's visual root.

    login

    fn login(resolve : Emit[Result[LoginResult, HostError]]) -> Cmd

    measure_nodes

    fn measure_nodes(ids : Array[String], resolve : Emit[Result[Array[NodeRect?], HostError]]) -> Cmd

    Measure at most 128 page-local IDs after the pending render has been acknowledged. IDs are identifiers, never CSS selectors. Declare MeasureNodes on the page.
    fn navigate_back(delta? : Int) -> Cmd

    fn navigate_back_or(fallback~ : Route, delta? : Int) -> Cmd

    fn navigate_to(target : Route) -> Cmd

    fn[C : IsChildren] navigator(target~ : Route, mode? : NavigatorMode, id? : String, class? : String, style? : String, children : C) -> Node

    no_cmd

    fn[Model] no_cmd(model : Model) -> (Model, Cmd)

    none

    let none : Cmd

    nothing

    fn nothing() -> Node

    fn[C : IsChildren] p(id? : String, class? : String, style? : String, data_section? : String, semantics? : Semantics, children : C) -> Node

    page

    fn page(id~ : String, route~ : Route, title~ : String, capabilities? : Array[Capability], build~ : (PageContext) -> Val[Node]) -> Page

    page_with_input

    fn[Input] page_with_input(id~ : String, route~ : Route, title~ : String, capabilities? : Array[Capability], preview_input~ : () -> Input, decode_input~ : (Map[String, String]) -> Result[Input, DecodeError], build~ : (PageContext, Input) -> Val[Node]) -> Page

    perform

    fn[A] perform(to_cmd : Emit[A], f : async () -> A noraise) -> Cmd

    picker_date

    fn[C : IsChildren] picker_date(name? : String, value~ : String, on_change~ : Emit[String], disabled? : Bool, event_key? : String, id? : String, class? : String, style? : String, children : C) -> Node

    picker_region

    fn[C : IsChildren] picker_region(name? : String, value~ : Array[String], on_change~ : Emit[Array[String]], disabled? : Bool, event_key? : String, id? : String, class? : String, style? : String, children : C) -> Node

    picker_selector

    fn[C : IsChildren] picker_selector(name? : String, options~ : Array[String], selected~ : Int, on_change~ : Emit[Int], event_key? : String, disabled? : Bool, id? : String, class? : String, style? : String, children : C) -> Node

    picker_time

    fn[C : IsChildren] picker_time(name? : String, value~ : String, on_change~ : Emit[String], disabled? : Bool, event_key? : String, id? : String, class? : String, style? : String, children : C) -> Node

    progress

    fn progress(percent~ : Int, stroke_width? : Int, show_info? : Bool, active? : Bool, active_color? : String, background_color? : String, id? : String, class? : String, style? : String, semantics? : Semantics) -> Node

    query

    fn query(name : String, value : String) -> Query

    radio

    fn[C : IsChildren] radio(value~ : String, checked? : Bool, disabled? : Bool, color? : String, id? : String, class? : String, style? : String, children : C) -> Node

    radio_group

    fn[C : IsChildren] radio_group(name? : String, on_change~ : Emit[String], event_key? : String, id? : String, class? : String, style? : String, data_section? : String, children : C) -> Node

    redirect_to

    fn redirect_to(target : Route) -> Cmd

    request

    fn request(url : String, resolve : Emit[Result[RequestResult, HostError]], http_method? : HttpMethod, query? : Array[Query], headers? : Map[String, String], body? : RequestBody, timeout_ms? : Int) -> Cmd

    Encodes and snapshots arguments now; delivers validation errors only when run. HTTP error status codes remain successful transport results.

    request_payment

    fn request_payment(params : PaymentParams, resolve : Emit[Result[Unit, HostError]]) -> Cmd

    route

    fn route(path : String) -> Route

    runtime_api_version

    fn runtime_api_version() -> Int

    scroll_view

    fn[C : IsChildren] scroll_view(scroll_x? : Bool, scroll_y? : Bool, scroll_top? : Int, scroll_left? : Int, scroll_top_px? : Double, scroll_left_px? : Double, scroll_into_view? : String, upper_threshold? : Int, lower_threshold? : Int, on_scroll? : Emit[ScrollDetail], scroll_key? : String, on_upper? : Cmd, upper_key? : String, on_lower? : Cmd, lower_key? : String, id? : String, class? : String, style? : String, data_section? : String, children : C) -> Node

    semantics

    fn semantics(role? : SemanticRole, label? : String, expanded? : Bool, selected? : Bool, disabled? : Bool, hidden? : Bool, checked? : Bool, modal? : Bool, controls? : String, labelled_by? : String, described_by? : String, orientation? : String, has_popup? : String, required? : Bool, invalid? : Bool, busy? : Bool, live? : String, value_min? : Int, value_max? : Int, value_now? : Int, value_text? : String) -> Semantics

    set_storage

    fn set_storage(key : String, value : Json, resolve : Emit[Result[Unit, HostError]]) -> Cmd

    show_toast

    fn show_toast(title : String, resolve : Emit[Result[Unit, HostError]]) -> Cmd

    slider

    fn slider(value~ : Int, on_change~ : Emit[Int], on_changing? : Emit[Int], min? : Int, max? : Int, step? : Int, disabled? : Bool, show_value? : Bool, active_color? : String, background_color? : String, block_color? : String, block_size? : Int, name? : String, event_key? : String, changing_key? : String, id? : String, class? : String, style? : String, semantics? : Semantics) -> Node

    span

    fn[C : IsChildren] span(id? : String, class? : String, style? : String, data_section? : String, semantics? : Semantics, children : C) -> Node

    swiper

    fn[C : IsChildren] swiper(current? : Int, vertical? : Bool, autoplay? : Bool, circular? : Bool, interval? : Int, duration? : Int, on_change? : Emit[Int], event_key? : String, id? : String, class? : String, style? : String, children : C) -> Node

    swiper_item

    fn[C : IsChildren] swiper_item(item_id? : String, id? : String, class? : String, style? : String, children : C) -> Node

    switch

    fn switch(name? : String, checked~ : Bool, on_change~ : Emit[Bool], event_key? : String, disabled? : Bool, color? : String, id? : String, class? : String, style? : String, data_section? : String, semantics? : Semantics) -> Node

    switch_tab

    fn switch_tab(target : Route) -> Cmd

    Switch to a configured native Tab page. Native Tab routes have no query.

    tap_view

    fn[C : IsChildren] tap_view(on_tap~ : Cmd, event_key? : String, id? : String, class? : String, style? : String, data_section? : String, semantics? : Semantics, children : C) -> Node

    A tappable MiniApp view. Use this for non-button hit surfaces such as modal overlays and menu dismissal layers.

    text

    fn text(value : String) -> Node

    textarea

    fn textarea(name? : String, value~ : String, on_input~ : Emit[String], input_key? : String, placeholder? : String, maxlength? : Int, disabled? : Bool, focus? : Bool, on_confirm? : Emit[String], confirm_key? : String, on_focus? : Emit[FocusDetail], focus_key? : String, on_blur? : Emit[TextareaBlurDetail], blur_key? : String, id? : String, class? : String, style? : String, data_section? : String, semantics? : Semantics) -> Node

    touch_view

    fn[C : IsChildren] touch_view(on_tap? : Cmd, on_long_press? : Emit[TouchDetail], on_touch_start? : Emit[TouchDetail], on_touch_move? : Emit[TouchDetail], on_touch_end? : Emit[TouchDetail], on_touch_cancel? : Emit[TouchDetail], catch_move? : Bool, event_key? : String, id? : String, class? : String, style? : String, data_section? : String, semantics? : Semantics, children : C) -> Node

    with_cmd

    fn[Model] with_cmd(model : Model, command : Cmd) -> (Model, Cmd)

    with_cmds

    fn[Model] with_cmds(model : Model, commands : Array[Cmd]) -> (Model, Cmd)