Shared DSL entity definitions used by both Lavash.Dsl (LiveView) and Lavash.Component.Dsl.
This module provides common entity definitions to reduce duplication between the two DSLs. Each DSL imports the entities it needs and may extend schemas with runtime-specific options.
Summary
Functions
Base schema for action entities.
Base schema for calculate entities.
Base schema for form entities.
Base schema fields shared by all state entities.
Effect entity for actions - runs a side effect function.
MapBy entity for actions — key-based array mutations.
PreRun entity for actions — pre-cascade socket-shaped run.
Argument entity for read and derive blocks.
Run entity for actions — post-cascade socket-shaped run.
Set entity for actions - assigns a value to a state field.
Submit entity for actions - submits a form.
Functions
Base schema for action entities.
Base schema for calculate entities.
Base schema for form entities.
Base schema fields shared by all state entities.
Strictly layer-1/2 keys: name, type, default. Storage-source keys
(from:, setter:, encode:, decode:, etc.) are appended by
the LiveView and Component DSLs at their layer-2 build sites.
Layer-4 keys (optimistic:, animated:) come from
Lavash.Optimistic.SchemaExtension.state_schema/0 and are
concatenated alongside.
This split is the layering carving from
docs/ARCHITECTURE.md punchlist item #3: the base DSL surface
shouldn't advertise optimism keys when the user hasn't opted in
to layer 4.
Effect entity for actions - runs a side effect function.
MapBy entity for actions — key-based array mutations.
Finds items in an array by a key field and applies a transformation.
The @item variable references the matched item in the rx() expression.
Return :remove to filter the item out.
PreRun entity for actions — pre-cascade socket-shaped run.
Runs BEFORE the reactive cascade. Use when you need imperative Elixir to compute a state value that downstream calcs depend on:
action :submit do
pre_run fn socket ->
# Imperative validation / preprocessing before mutation
if socket.assigns.form_valid? do
socket
|> Lavash.Socket.put_state(:submitted, true)
|> Lavash.Socket.put_state(:submitted_at, DateTime.utc_now())
else
socket
end
end
endAfter the body returns, the action runtime extracts
socket.assigns.__changed__ to populate lavash's dirty set, so
the cascade sees what changed and recomputes precisely. So you
can use raw Phoenix.Component.assign/3 if you prefer — the
cascade will still see the write.
For most state mutation, prefer the declarative set :foo, rx(...).
Argument entity for read and derive blocks.
Run entity for actions — post-cascade socket-shaped run.
Runs AFTER the reactive cascade. Reads settled state; can do socket-level LV ops or external side effects:
action :send do
run fn socket ->
new_msg = %{id: next_id(), summary: socket.assigns.summary}
Phoenix.LiveView.stream_insert(socket, :messages, new_msg)
end
endUse for socket-level LV ops (stream_insert/4, allow_upload/3,
consume_uploaded_entries/3, cancel_upload/3) or anything that
needs the post-cascade view.
Writes from run land in assigns and __changed__ is updated
for Phoenix's render diff. BUT lavash does NOT re-fire the
cascade — calcs depending on what run wrote are stale until
the next event. If you need a derived value of a write, write it
in pre_run instead.
Set entity for actions - assigns a value to a state field.
The value can use @field syntax to reference state fields and params,
aligned with template syntax:
action :increment do
set :count, @count + 1
end
action :add_item do
params [:name]
set :items, @items ++ [@name]
endThe expression is captured at compile time and can be transpiled to JavaScript for optimistic client-side updates.
Submit entity for actions - submits a form.