# `Mob.Sigil`
[🔗](https://github.com/genericjam/mob/blob/master/lib/mob/sigil.ex#L1)

The `~MOB` sigil for declarative native UI.

Compiles a tag template to a `Mob.Renderer`-compatible node map **at compile
time** using NimbleParsec. Expressions in `{...}` are evaluated in the
caller's scope at runtime.

Use `~MOB(...)` for single nodes or `~MOB"""..."""` for nested layouts.

## Examples

    import Mob.Sigil

    # Self-closing
    ~MOB(<Text text="Hello" />)
    #=> %{type: :text, props: %{text: "Hello"}, children: []}

    # Nested layout
    ~MOB"""
    <Column padding={:space_md}>
      <Text text="Title" text_size={:xl} />
      <Button text="OK" on_tap={{self(), :ok}} />
    </Column>
    """

    # Expression child — inject any node map or list of maps
    ~MOB"""
    <Column>
      {Enum.map(items, fn i -> ~MOB(<Text text={i} />) end)}
    </Column>
    """

## Tag whitelist

Tags are validated against `priv/tags/ios.txt` and `priv/tags/android.txt` at
compile time. Unknown tags emit a warning but still pass through — the type
atom is derived by converting PascalCase to snake_case (e.g. `TabBar` →
`:tab_bar`). This allows new native tags to be used before the whitelist is
updated.

# `brace_content`

```elixir
@spec brace_content(binary(), keyword()) ::
  {:ok, [term()], rest, context, line, byte_offset}
  | {:error, reason, rest, context, line, byte_offset}
when line: {pos_integer(), byte_offset},
     byte_offset: non_neg_integer(),
     rest: binary(),
     reason: String.t(),
     context: map()
```

Parses the given `binary` as brace_content.

Returns `{:ok, [token], rest, context, position, byte_offset}` or
`{:error, reason, rest, context, line, byte_offset}` where `position`
describes the location of the brace_content (start position) as `{line, offset_to_start_of_line}`.

To column where the error occurred can be inferred from `byte_offset - offset_to_start_of_line`.

## Options

  * `:byte_offset` - the byte offset for the whole binary, defaults to 0
  * `:line` - the line and the byte offset into that line, defaults to `{1, byte_offset}`
  * `:context` - the initial context value. It will be converted to a map

# `node`

```elixir
@spec node(binary(), keyword()) ::
  {:ok, [term()], rest, context, line, byte_offset}
  | {:error, reason, rest, context, line, byte_offset}
when line: {pos_integer(), byte_offset},
     byte_offset: non_neg_integer(),
     rest: binary(),
     reason: String.t(),
     context: map()
```

Parses the given `binary` as node.

Returns `{:ok, [token], rest, context, position, byte_offset}` or
`{:error, reason, rest, context, line, byte_offset}` where `position`
describes the location of the node (start position) as `{line, offset_to_start_of_line}`.

To column where the error occurred can be inferred from `byte_offset - offset_to_start_of_line`.

## Options

  * `:byte_offset` - the byte offset for the whole binary, defaults to 0
  * `:line` - the line and the byte offset into that line, defaults to `{1, byte_offset}`
  * `:context` - the initial context value. It will be converted to a map

# `parse_template`

```elixir
@spec parse_template(binary(), keyword()) ::
  {:ok, [term()], rest, context, line, byte_offset}
  | {:error, reason, rest, context, line, byte_offset}
when line: {pos_integer(), byte_offset},
     byte_offset: non_neg_integer(),
     rest: binary(),
     reason: String.t(),
     context: map()
```

Parses the given `binary` as parse_template.

Returns `{:ok, [token], rest, context, position, byte_offset}` or
`{:error, reason, rest, context, line, byte_offset}` where `position`
describes the location of the parse_template (start position) as `{line, offset_to_start_of_line}`.

To column where the error occurred can be inferred from `byte_offset - offset_to_start_of_line`.

## Options

  * `:byte_offset` - the byte offset for the whole binary, defaults to 0
  * `:line` - the line and the byte offset into that line, defaults to `{1, byte_offset}`
  * `:context` - the initial context value. It will be converted to a map

# `sigil_MOB`
*macro* 

Compiles a `~MOB(...)` or `~MOB"""..."""` template into a native UI node map.
Parsed at compile time; `{expr}` values evaluated at runtime in the caller's scope.

# `wrap_child`

```elixir
@spec wrap_child(list() | map()) :: list()
```

Normalizes a `{expr}` child's value to a list of UI-node maps for
the surrounding sigil. Single nodes wrap into a one-element list;
lists pass through. Public so the sigil-generated AST can call it
by FQ name; not part of the application API.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
