Skip to content

exstruct/rondo

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

53 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

rondo Build Status Hex.pm Hex.pm

component rendering library

Installation

Rondo is available in Hex and can be installed as:

  1. Add rondo your list of dependencies in mix.exs:
def deps do
  [{:rondo, "~> 0.1.0"}]
end

Usage

Start by creating a store

defmodule MyApp.Store do
  defstruct [stores: %{}]

  defimpl Rondo.State.Store do
    def mount(%{stores: stores} = store, %{props: initial, type: :ephemeral} = descriptor) do
      stores = Map.put_new(stores, descriptor, initial)
      {Map.get(stores, descriptor), %{store | stores: stores}}
    end

    def handle_info(store, _info) do
      store
    end

    def handle_action(store, descriptor, update_fn) do
      {prev, store} = mount(store, descriptor)
      value = update_fn.(prev)
      stores = Map.put(store.stores, descriptor, value)
      {:ok, %{store | stores: stores}}
    end

    def encode(%{stores: stores}) do
      stores
      |> :erlang.term_to_binary()
      |> Base.url_encode64()
    end

    def decode_into(store, bin) do
      stores = bin
      |> Base.url_decode64!()
      |> :erlang.binary_to_term()
      %{store | stores: stores}
    end
  end
end

Now define an action with an affordance (in jsonschema format)

defmodule MyApp.Action.Increment do
  def affordance(_props) do
    %{
      "type" => ["integer", "null"]
    }
  end

  def action(_props, state, input) do
    state + (input || 0)
  end
end

And a component to use the action

defmodule MyApp.Component do
  use Rondo.Component
  alias MyApp.Action.Increment

  def state(_props, _context) do
    %{
      counter: create_store(0)
    }
  end

  def render(%{counter: counter}) do
    el("Text", %{
      "increment" => ref([:counter]) |> action(Increment)
    }, [
      counter
    ])
  end
end

We can now render the app

# Set up our store and app
store = %MyApp.Store{}
app = Rondo.create_application(MyApp.Component)

# Perform the initial render
{app, store} = Rondo.render(app, store)

# Assert that the counter is initialized and being sent as the first child
{:ok, 0} = Rondo.Test.fetch_path(app, [0])

# We need to get the action ref to submit a form
{:ok, %{props: %{"increment" => %{ref: action_ref}}}} =
  Rondo.Test.fetch_path(app, [])

# If we submit an invalid action it should let us know
{:invalid, errors, app, store} =
  Rondo.submit_action(app, store, action_ref, "Invalid type")

# We now submit a valid action and it goes through
{:ok, app, store} =
  Rondo.submit_action(app, store, action_ref, 1)

# Trigger a render
{app, store} = Rondo.render(app, store)

# We now have the incremented value!
{:ok, 1} = Rondo.Test.fetch_path(app, [0])

About

component rendering library

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published