Timer · API
Machine API: start, pause, resume, reset, restart, and read state from LiveView or the client.
Controls (client binding)
<.action phx-click={Corex.Timer.start("timer-api-controls-client")} class="button button--sm">Start</.action>
<.action phx-click={Corex.Timer.pause("timer-api-controls-client")} class="button button--sm">Pause</.action>
<.action phx-click={Corex.Timer.resume("timer-api-controls-client")} class="button button--sm">Resume</.action>
<.action phx-click={Corex.Timer.reset("timer-api-controls-client")} class="button button--sm">Reset</.action>
<.action phx-click={Corex.Timer.restart("timer-api-controls-client")} class="button button--sm">Restart</.action>
<.timer id="timer-api-controls-client" countdown start_ms={60_000} target_ms={0} auto_start={false} class="timer">
<:start_trigger><.heroicon name="hero-play" /></:start_trigger>
<:pause_trigger><.heroicon name="hero-pause" /></:pause_trigger>
<:resume_trigger><.heroicon name="hero-play" /></:resume_trigger>
<:reset_trigger><.heroicon name="hero-arrow-path" /></:reset_trigger>
</.timer>
Controls (client JS)
<.action phx-click={JS.dispatch("corex:timer:start", to: "#timer-api-controls-js", bubbles: false)} class="button button--sm">Start</.action>
<.action phx-click={JS.dispatch("corex:timer:pause", to: "#timer-api-controls-js", bubbles: false)} class="button button--sm">Pause</.action>
<.action phx-click={JS.dispatch("corex:timer:resume", to: "#timer-api-controls-js", bubbles: false)} class="button button--sm">Resume</.action>
<.action phx-click={JS.dispatch("corex:timer:reset", to: "#timer-api-controls-js", bubbles: false)} class="button button--sm">Reset</.action>
<.action phx-click={JS.dispatch("corex:timer:restart", to: "#timer-api-controls-js", bubbles: false)} class="button button--sm">Restart</.action>
<.timer id="timer-api-controls-js" countdown start_ms={60_000} target_ms={0} auto_start={false} class="timer">
<:start_trigger><.heroicon name="hero-play" /></:start_trigger>
<:pause_trigger><.heroicon name="hero-pause" /></:pause_trigger>
<:resume_trigger><.heroicon name="hero-play" /></:resume_trigger>
<:reset_trigger><.heroicon name="hero-arrow-path" /></:reset_trigger>
</.timer>
const el = document.getElementById("timer-api-controls-js");
el?.dispatchEvent(new CustomEvent("corex:timer:start", { bubbles: false }));
el?.dispatchEvent(new CustomEvent("corex:timer:pause", { bubbles: false }));
el?.dispatchEvent(new CustomEvent("corex:timer:resume", { bubbles: false }));
el?.dispatchEvent(new CustomEvent("corex:timer:reset", { bubbles: false }));
el?.dispatchEvent(new CustomEvent("corex:timer:restart", { bubbles: false }));
const el: HTMLElement | null = document.getElementById("timer-api-controls-js");
el?.dispatchEvent(new CustomEvent("corex:timer:start", { bubbles: false }));
el?.dispatchEvent(new CustomEvent("corex:timer:pause", { bubbles: false }));
el?.dispatchEvent(new CustomEvent("corex:timer:resume", { bubbles: false }));
el?.dispatchEvent(new CustomEvent("corex:timer:reset", { bubbles: false }));
el?.dispatchEvent(new CustomEvent("corex:timer:restart", { bubbles: false }));
Controls (server)
<.action phx-click="api_timer_start_server" class="button button--sm">Start</.action>
<.action phx-click="api_timer_pause_server" class="button button--sm">Pause</.action>
<.action phx-click="api_timer_resume_server" class="button button--sm">Resume</.action>
<.action phx-click="api_timer_reset_server" class="button button--sm">Reset</.action>
<.action phx-click="api_timer_restart_server" class="button button--sm">Restart</.action>
<.timer id="timer-api-controls-server" countdown start_ms={60_000} target_ms={0} auto_start={false} class="timer">
<:start_trigger><.heroicon name="hero-play" /></:start_trigger>
<:pause_trigger><.heroicon name="hero-pause" /></:pause_trigger>
<:resume_trigger><.heroicon name="hero-play" /></:resume_trigger>
<:reset_trigger><.heroicon name="hero-arrow-path" /></:reset_trigger>
</.timer>
def handle_event("api_timer_start_server", _params, socket) do
{:noreply, Corex.Timer.start(socket, "timer-api-controls-server")}
end
def handle_event("api_timer_pause_server", _params, socket) do
{:noreply, Corex.Timer.pause(socket, "timer-api-controls-server")}
end
def handle_event("api_timer_resume_server", _params, socket) do
{:noreply, Corex.Timer.resume(socket, "timer-api-controls-server")}
end
def handle_event("api_timer_reset_server", _params, socket) do
{:noreply, Corex.Timer.reset(socket, "timer-api-controls-server")}
end
def handle_event("api_timer_restart_server", _params, socket) do
{:noreply, Corex.Timer.restart(socket, "timer-api-controls-server")}
end
State (client binding)
<.action phx-click={Corex.Timer.state("timer-api-state-client")} class="button button--sm">
Read state
</.action>
<.timer id="timer-api-state-client" countdown start_ms={60_000} target_ms={0} auto_start={false} class="timer">
<:start_trigger><.heroicon name="hero-play" /></:start_trigger>
<:pause_trigger><.heroicon name="hero-pause" /></:pause_trigger>
<:resume_trigger><.heroicon name="hero-play" /></:resume_trigger>
<:reset_trigger><.heroicon name="hero-arrow-path" /></:reset_trigger>
</.timer>
State (server)
<.action phx-click="api_timer_state_server" class="button button--sm">
Read state
</.action>
<.timer id="timer-api-state-server" countdown start_ms={60_000} target_ms={0} auto_start={false} class="timer">
<:start_trigger><.heroicon name="hero-play" /></:start_trigger>
<:pause_trigger><.heroicon name="hero-pause" /></:pause_trigger>
<:resume_trigger><.heroicon name="hero-play" /></:resume_trigger>
<:reset_trigger><.heroicon name="hero-arrow-path" /></:reset_trigger>
</.timer>
def handle_event("api_timer_state_server", _params, socket) do
{:noreply, Corex.Timer.state(socket, "timer-api-state-server")}
end
State (client JS)
<.action
phx-click={JS.dispatch("corex:timer:state", to: "#timer-api-state-js", detail: %{}, bubbles: false)}
class="button button--sm"
>
Read state
</.action>
<.timer id="timer-api-state-js" countdown start_ms={60_000} target_ms={0} auto_start={false} class="timer">
<:start_trigger><.heroicon name="hero-play" /></:start_trigger>
<:pause_trigger><.heroicon name="hero-pause" /></:pause_trigger>
<:resume_trigger><.heroicon name="hero-play" /></:resume_trigger>
<:reset_trigger><.heroicon name="hero-arrow-path" /></:reset_trigger>
</.timer>
const el = document.getElementById("timer-api-state-js");
el?.dispatchEvent(new CustomEvent("corex:timer:state", { bubbles: false, detail: {} }));
const el = document.getElementById("timer-api-state-js");
el?.addEventListener("timer-state", (event: Event) => {
console.log((event as CustomEvent).detail);
});
el?.dispatchEvent(new CustomEvent("corex:timer:state", { bubbles: false, detail: {} }));
Configuration: countdown range
<.timer
id="t-countdown"
countdown
start_ms={60_000}
target_ms={0}
class="timer"
>
<:start_trigger><.heroicon name="hero-play" /></:start_trigger>
<:pause_trigger><.heroicon name="hero-pause" /></:pause_trigger>
<:resume_trigger><.heroicon name="hero-play" /></:resume_trigger>
<:reset_trigger><.heroicon name="hero-arrow-path" /></:reset_trigger>
</.timer>
Configuration: interval and auto start
<.timer id="t-interval" start_ms={60_000} interval={1000} auto_start class="timer">
<:start_trigger><.heroicon name="hero-play" /></:start_trigger>
<:pause_trigger><.heroicon name="hero-pause" /></:pause_trigger>
<:resume_trigger><.heroicon name="hero-play" /></:resume_trigger>
<:reset_trigger><.heroicon name="hero-arrow-path" /></:reset_trigger>
</.timer>
Configuration: direction and orientation
<.timer id="t-dir" start_ms={0} target_ms={30_000} dir="rtl" class="timer">
<:start_trigger><.heroicon name="hero-play" /></:start_trigger>
<:pause_trigger><.heroicon name="hero-pause" /></:pause_trigger>
<:resume_trigger><.heroicon name="hero-play" /></:resume_trigger>
<:reset_trigger><.heroicon name="hero-arrow-path" /></:reset_trigger>
</.timer>
Tick and complete
Interactive log live on Timer · Events.
<.timer
countdown
start_ms={3_600_000}
target_ms={0}
class="timer"
on_tick="timer_tick"
on_tick_client="timer-tick"
on_complete="timer_complete"
on_complete_client="timer-complete"
>
<:start_trigger><.heroicon name="hero-play"/></:start_trigger>
<:pause_trigger><.heroicon name="hero-pause"/></:pause_trigger>
<:resume_trigger><.heroicon name="hero-play"/></:resume_trigger>
<:reset_trigger><.heroicon name="hero-arrow-path"/></:reset_trigger>
</.timer>
def handle_event("timer_tick", %{"id" => id} = params, socket) do
IO.inspect(params, label: "timer_tick")
{:noreply, socket}
end
def handle_event("timer_complete", %{"id" => id} = params, socket) do
IO.inspect(params, label: "timer_complete")
{:noreply, socket}
end
const el = document.getElementById("timer-events-live")
if (!el) return
el.addEventListener("timer-tick", (event) => {
const d = event.detail
console.log(d?.formattedTime, d?.id)
})
el.addEventListener("timer-complete", (event) => {
console.log(event.detail?.id)
})