Sign in

    This version of the module is deprecated: Use moonbit-community/rabbita instead.

    #Html

    This package provides the helper functions to build Html.

    Here are some design choices:

    • Guide Users with Type Definitions

      This package defines specific types for arguments instead of relying on a potentially confusing String type. These types serve as documentation, helping users understand how to correctly provide arguments.

    • Seamless HTML EDSL

      Instead of relying on a precompiler to process JSX-like syntax, this EDSL allows users to leverage the full power of Moonbit's syntax and toolchain.

      You can embed expressions in views without needing escape characters like property={expression} or :property=expression. For cases where the property name matches the variable name, you can use the convenient name-punning syntax, such as property? or property~.

      In this early stage, we need to focus on improving the functionality of Rabbit-TEA. Language extensions like JSX may be considered after the 1.0 release.

    • Keep it simple

      No compile-time code translation or runtime reflection magic.

    #Using the Html EDSL

    We are trying to define wrapper functions for each HTML element. They all follow a form like this:

    pub fn div[M](
    style~ : Array[String] = [],
    id? : String,
    klass? : String,
    click? : M,
    childrens : Array[Html[M]]
    ) -> Html[M]

    #The text element

    To represent text in HTML, use the text function.

    let html = p([text("hello world")])

    #The special nothing element

    There is a special nothing element that does not represent an actual HTML element, it simply represents "nothing". This is particularly useful for handling multiple Option types in your model:

    fn bar(path : Path, tag : Option[Tag]){
    let path = foo(path)
    let tag = match tag {
    None => []
    Some(x) => [view(x)] // Yuck!
    }
    div([path] + tag) // Don't do this
    }

    fn bar(path : Path, tag : Option[Tag]){
    let path = foo(path)
    let tag = match tag {
    None => nothing()
    Some(x) => view(x)
    }
    div([path, tag]) // Use @html.nothing
    }

    #Advanced Usage

    The wrapper functions and properties provided here may not cover all possible use cases. If you encounter missing functionality, feel free to file an issue or use the node() function as a workaround. The node() function allows you to manually specify the tag name, attributes, and children for your HTML element, offering flexibility for advanced or uncommon scenarios.

    let html = node(
    "div",
    [style("key","value"), property("id","key")],
    [child1, child2],
    )

    Contributions to help us finish the missing wrappers or arguments are also welcome.

    typealias Html as T

    Attribute

    type Attribute[Msg]

    AutoComplete

    pub(all) enum AutoComplete {
    On
    Off
    }

    Html

    pub(all) type Html[Msg]
    Node
    [Msg]

    Html::inner

    fn[Msg] Html::inner(self : Html[Msg]) ->
    Node
    [Msg]
    Convert newtype to its underlying type, automatically derived.

    Html::map

    fn[A, B] Html::map(self : Html[A], f : (A) -> B) -> Html[B]
    Convert msg type of Html.

    This is a expensive operation and should be used rarely.

    Html::to_virtual_dom

    fn[Msg] Html::to_virtual_dom(self : Html[Msg]) ->
    Node
    [Msg]

    InputType

    pub(all) enum InputType {
    Button
    Checkbox
    Color
    Date
    DateTimeLocal
    Email
    File
    Hidden
    Image
    Month
    Number
    Password
    Radio
    Range
    Reset
    Search
    Submit
    Tel
    Text
    Time
    Url
    Week
    }

    Mouse

    type Mouse

    Mouse::client_pos

    fn Mouse::client_pos(self : Mouse) -> Pos

    Mouse::offset_pos

    fn Mouse::offset_pos(self : Mouse) -> Pos

    Mouse::screen_pos

    fn Mouse::screen_pos(self : Mouse) -> Pos

    Pos

    pub(all) struct Pos {
    x : Int
    y : Int
    }

    Scope

    pub(all) enum Scope {
    Row
    Col
    RowGroup
    ColGroup
    }

    Scroll

    type Scroll

    Scroll::height

    fn Scroll::height(self : Scroll) -> Int

    Scroll::offset_pos

    fn Scroll::offset_pos(self : Scroll) -> Pos

    Scroll::width

    fn Scroll::width(self : Scroll) -> Int

    Target

    pub(all) enum Target {
    Self
    Blank
    }

    fn[M] a(style~ : Array[String] = .., id? : String, class? : String, href~ : String, target~ : Target = .., childrens : Array[Html[M]], escape~ : Bool = ..) -> Html[M]
    Create a element.

    Parameters

    • escape: an optional boolean that determines whether the link should be escaped. By default, it is set to false.

      When escape is set to true, clicking the escaped link will cause the browser to immediately navigate to the href target, bypassing any interception logic. As a result, the UrlRequest message will not be triggered.

    • target: an optional Target that specifies where to open the link.

    If the user holds the ctrl key (or the command key on macOS) while clicking the link, the click event will be handled by the browser, and the UrlRequest will not be triggered either.

    attribute

    fn[Msg] attribute(key : String, value : String) -> Attribute[Msg]

    fn[M] b(style~ : Array[String] = .., id? : String, class? : String, childrens : Array[Html[M]]) -> Html[M]

    blockquote

    fn[M] blockquote(style~ : Array[String] = .., id? : String, class? : String, childrens : Array[Html[M]]) -> Html[M]

    fn[M] br(style~ : Array[String] = .., id? : String, class? : String) -> Html[M]

    button

    fn[M] button(style~ : Array[String] = .., id? : String, class? : String, click? : M, childrens : Array[Html[M]]) -> Html[M]

    caption

    fn[M] caption(style~ : Array[String] = .., id? : String, class? : String, childrens : Array[Html[M]]) -> Html[M]

    code

    fn[M] code(style~ : Array[String] = .., id? : String, class? : String, childrens : Array[Html[M]]) -> Html[M]

    col

    fn[M] col(style~ : Array[String] = .., id? : String, span? : Int, class? : String, childrens : Array[Html[M]]) -> Html[M]

    colgroup

    fn[M] colgroup(style~ : Array[String] = .., id? : String, span? : Int, class? : String, childrens : Array[Html[M]]) -> Html[M]

    fn[M] dd(style~ : Array[String] = .., id? : String, class? : String, childrens : Array[Html[M]]) -> Html[M]

    dialog

    fn[M] dialog(style~ : Array[String] = .., id? : String, class? : String, open? : Bool, close? : (String) -> M, cancel? : M, childrens : Array[Html[M]]) -> Html[M]
    Dialog element.

    Hint: You can use the show and close commands in the @dialog package to manipulate the dialog.

    Attributes

    • open: indicates whether the dialog is open or closed by default.

    Messages

    • close: triggered when the dialog is closed.

      The string payload of the close message is the return value of the dialog.

    • cancel: triggered when the user instructs the browser that they wish to dismiss the current open dialog.

      It can be triggered when the user presses esc or uses the request_close command.

      If the cancel argument is provided, the dialog will not close automatically after this message is triggered. You can use the @dialog.close command to close it or @cmd.none to keep it open.

    Example

    typealias Model = String

    enum Msg {
    Open
    Closed(String)
    YesNo(Bool)
    }

    fn update(msg : Msg, model : Model) -> (Cmd[Msg], Model) {
    match msg {
    Open => (@dialog.show("confirm"), model)
    YesNo(answer) => (@dialog.close("confirm", return_value=answer.to_string()), model)
    Closed(value) => (none(), value)
    }
    }

    fn view(model : Model) -> Html[Msg] {
    div([
    h1([text(model)]),
    button(click=Msg::Open, [text("open")]),
    dialog(id="confirm", close=Msg::Closed, [
    p([text("Are you sure?")]),
    button(click=YesNo(true), [text("Yes")]),
    button(click=YesNo(false), [text("No")]),
    ]),
    ])
    }

    div

    fn[M] div(style~ : Array[String] = .., id? : String, class? : String, click? : M, childrens : Array[Html[M]]) -> Html[M]

    fn[M] dl(style~ : Array[String] = .., id? : String, class? : String, childrens : Array[Html[M]]) -> Html[M]

    fn[M] dt(style~ : Array[String] = .., id? : String, class? : String, childrens : Array[Html[M]]) -> Html[M]

    fn[M] em(style~ : Array[String] = .., id? : String, class? : String, childrens : Array[Html[M]]) -> Html[M]

    external

    fn[Msg] external(node :
    Node
    , attrs : Ref[Array[Attribute[Msg]]?], width~ : Int, height~ : Int) -> Html[Msg]

    form

    fn[M] form(style~ : Array[String] = .., id? : String, class? : String, action? : String, name? : String, childrens : Array[Html[M]]) -> Html[M]

    fn[M] h1(style~ : Array[String] = .., id? : String, class? : String, childrens : Array[Html[M]]) -> Html[M]

    fn[M] h2(style~ : Array[String] = .., id? : String, class? : String, childrens : Array[Html[M]]) -> Html[M]

    fn[M] h3(style~ : Array[String] = .., id? : String, class? : String, childrens : Array[Html[M]]) -> Html[M]

    fn[M] h4(style~ : Array[String] = .., id? : String, class? : String, childrens : Array[Html[M]]) -> Html[M]

    fn[M] h5(style~ : Array[String] = .., id? : String, class? : String, childrens : Array[Html[M]]) -> Html[M]

    fn[M] h6(style~ : Array[String] = .., id? : String, class? : String, childrens : Array[Html[M]]) -> Html[M]

    fn[M] hr(style~ : Array[String] = .., id? : String, class? : String, childrens~ : Array[Html[M]] = ..) -> Html[M]

    href

    fn[Msg] href(value : String) -> Attribute[Msg]

    fn[M] i(style~ : Array[String] = .., id? : String, class? : String, childrens : Array[Html[M]]) -> Html[M]

    iframe

    fn[M] iframe(style~ : Array[String] = .., id? : String, class? : String, src? : String, title? : String, width? : Int, height? : Int) -> Html[M]

    img

    fn[M] img(style~ : Array[String] = .., id? : String, class? : String, src? : String, alt? : String, title? : String, width? : Int, height? : Int, border? : Int, childrens : Array[Html[M]]) -> Html[M]

    input

    fn[M] input(input_type~ : InputType = .., name? : String, value? : String, checked? : Bool, read_only? : Bool, multiple? : Bool, accept? : String, placeholder? : String, auto_complete? : AutoComplete, style~ : Array[String] = .., max? : Int, min? : Int, step? : Int, maxlength? : Int, minlength? : Int, pattern? : String, size? : Int, width? : Int, height? : Int, id? : String, class? : String, childrens~ : Array[Html[M]] = .., change? : (String) -> M, input? : (String) -> M) -> Html[M]

    label

    fn[M] label(style~ : Array[String] = .., id? : String, class? : String, for_? : String, childrens : Array[Html[M]]) -> Html[M]

    fn[M] li(style~ : Array[String] = .., value? : Int, id? : String, class? : String, click? : M, childrens : Array[Html[M]]) -> Html[M]

    node

    fn[Msg] node(tag : String, attributes : Array[Attribute[Msg]], childrens : Array[Html[Msg]]) -> Html[Msg]

    nothing

    fn[M] nothing() -> Html[M]
    Represents an empty element
    fn[M] ol(style~ : Array[String] = .., reversed? : Bool, start? : Int, id? : String, class? : String, childrens : Array[Html[M]]) -> Html[M]
    Notice that the type attribute for ol is not important for the browser now. If you want to change the type of the list, you should use the list-style-type property in CSS.

    on_change

    fn[Msg] on_change(msg : (String) -> Msg) -> Attribute[Msg]

    on_click

    fn[Msg] on_click(msg : (Mouse) -> Msg) -> Attribute[Msg]

    on_double_click

    fn[Msg] on_double_click(msg : (Mouse) -> Msg) -> Attribute[Msg]

    on_input

    fn[Msg] on_input(msg : (String) -> Msg) -> Attribute[Msg]

    on_mouse_down

    fn[Msg] on_mouse_down(msg : (Mouse) -> Msg) -> Attribute[Msg]

    on_mouse_enter

    fn[Msg] on_mouse_enter(msg : (Mouse) -> Msg) -> Attribute[Msg]

    on_mouse_leave

    fn[Msg] on_mouse_leave(msg : (Mouse) -> Msg) -> Attribute[Msg]

    on_mouse_move

    fn[Msg] on_mouse_move(msg : (Mouse) -> Msg) -> Attribute[Msg]

    on_mouse_out

    fn[Msg] on_mouse_out(msg : (Mouse) -> Msg) -> Attribute[Msg]

    on_mouse_over

    fn[Msg] on_mouse_over(msg : (Mouse) -> Msg) -> Attribute[Msg]

    on_mouse_up

    fn[Msg] on_mouse_up(msg : (Mouse) -> Msg) -> Attribute[Msg]

    on_scroll

    fn[M] on_scroll(msg : (Scroll) -> M) -> Attribute[M]

    option

    fn[M] option(style~ : Array[String] = .., id? : String, class? : String, disabled? : Bool, value? : String, selected~ : Bool = .., childrens : Array[Html[M]]) -> Html[M]

    fn[M] p(style~ : Array[String] = .., id? : String, class? : String, childrens : Array[Html[M]]) -> Html[M]

    pre

    fn[M] pre(style~ : Array[String] = .., id? : String, class? : String, childrens : Array[Html[M]]) -> Html[M]

    property

    fn[M] property(key : String, value :
    Variant
    ) -> Attribute[M]

    section

    fn[M] section(style~ : Array[String] = .., id? : String, class? : String, childrens : Array[Html[M]]) -> Html[M]

    select

    fn[M] select(style~ : Array[String] = .., id? : String, class? : String, disabled? : Bool, name? : String, change? : (String) -> M, childrens : Array[Html[M]]) -> Html[M]

    span

    fn[M] span(style~ : Array[String] = .., id? : String, class? : String, childrens : Array[Html[M]]) -> Html[M]

    strong

    fn[M] strong(style~ : Array[String] = .., id? : String, class? : String, childrens : Array[Html[M]]) -> Html[M]

    style

    fn[Msg] style(key : String, value : String) -> Attribute[Msg]
    Specify an style

    sub

    fn[M] sub(style~ : Array[String] = .., id? : String, class? : String, childrens : Array[Html[M]]) -> Html[M]

    sup

    fn[M] sup(style~ : Array[String] = .., id? : String, class? : String, childrens : Array[Html[M]]) -> Html[M]

    table

    fn[M] table(style~ : Array[String] = .., id? : String, class? : String, childrens : Array[Html[M]]) -> Html[M]

    target

    fn[Msg] target(value : Target) -> Attribute[Msg]

    tbody

    fn[M] tbody(style~ : Array[String] = .., id? : String, class? : String, childrens : Array[Html[M]]) -> Html[M]

    fn[M] td(style~ : Array[String] = .., id? : String, colspan? : Int, rowspan? : Int, headers? : String, class? : String, childrens : Array[Html[M]]) -> Html[M]

    text

    fn[Msg] text(str : String) -> Html[Msg]

    tfoot

    fn[M] tfoot(style~ : Array[String] = .., id? : String, class? : String, childrens : Array[Html[M]]) -> Html[M]

    fn[M] th(style~ : Array[String] = .., id? : String, abbr? : String, colspan? : Int, rowspan? : Int, headers? : String, scope? : Scope, class? : String, childrens : Array[Html[M]]) -> Html[M]

    thead

    fn[M] thead(style~ : Array[String] = .., id? : String, class? : String, childrens : Array[Html[M]]) -> Html[M]

    fn[M] tr(style~ : Array[String] = .., id? : String, class? : String, childrens : Array[Html[M]]) -> Html[M]

    fn[M] u(style~ : Array[String] = .., id? : String, class? : String, childrens : Array[Html[M]]) -> Html[M]

    fn[M] ul(style~ : Array[String] = .., id? : String, class? : String, click? : M, childrens : Array[Html[M]]) -> Html[M]