zui docs v0.0.5
GitHub ↗
Zui guide · 03

Events and commands

Handle native interaction, schedule work, and run bounded external commands without leaving Ruby.

Updated for Zui 0.0.5·2 minutes read

Handle intent with blocks

High-level component helpers register their primary event automatically. Pass external commands as argument arrays, and set explicit time and output bounds.

require "zui"

Zui.app do
  state :loading, false
  state :output, "Select Refresh to inspect the service."

  app :main, title: "Service status", width: 760, height: 520 do
    column spacing: 16 do
      button "Refresh", icon: :refresh do
        state.loading = true

        async do
          result = run_command(
            ["systemctl", "--user", "status", "example.service"],
            timeout: 5,
            max_output_bytes: 65_536
          )
          state.output = result.success? ? result.stdout : result.stderr
        rescue Zui::CommandTimeout => error
          state.output = error.message
        ensure
          state.loading = false
        end
      end

      text { state.loading ? "Loading…" : state.output }
    end
  end
end

Subscribe to any declared event

Keep the node returned by a component helper, then subscribe with an event declared by that component.

require "zui"

Zui.app do
  state :selected_index, nil
  values = [18, 42, 31, 76, 58, 91]

  app :main, title: "Traffic", width: 760, height: 520 do
    column spacing: 16 do
      chart = line_chart values, show_points: true, width: 680, height: 320

      on chart, :select do |payload|
        state.selected_index = payload["index"]
      end

      text { "Selected point: #{state.selected_index || "none"}" }
    end
  end
end

Schedule without blocking the UI

Use every for recurring work and after for a one-shot update. Intervals are expressed in seconds.

require "zui"

Zui.app do
  state :sample, 0.0
  state :notice, "Starting sampler…"

  every 5, immediate: true do
    state.sample = Process.clock_gettime(Process::CLOCK_MONOTONIC).round(2)
  end

  after 0.25 do
    state.notice = "Sampler ready"
  end

  app :main, title: "Sampler", width: 640, height: 420 do
    column spacing: 12 do
      label { state.notice }
      text { "Monotonic sample: #{state.sample}" }
    end
  end
end

Event names and properties are validated against the catalog before they reach the native protocol.