Skip to main content

Actions Registry

Register and call event handlers using dot-notation paths.

Overview

Actions are nested functions for handling events, commands, and side effects. They're perfect for decoupling event handling from UI code.

// Register
uizy.on({
user: {
login: (credentials) => authenticate(credentials),
logout: () => clearSession(),
},
cart: {
add: (item) => addToCart(item),
remove: (id) => removeFromCart(id),
},
});

// Emit
uizy.emit("user.login", { email: "user@example.com", password: "..." });
uizy.emit("cart.add", { id: 123, name: "Product", qty: 1 });

Registration

Via start()

uizy.start({
actions: {
auth: {
login: async (data) => {
const user = await api.login(data);
return user;
},
logout: () => {
api.logout();
window.location.href = "/";
},
},
notification: {
show: (message) => toast.success(message),
error: (message) => toast.error(message),
},
},
});

Via uizy.on()

uizy.on({
modal: {
open: (id) => document.getElementById(id)?.showModal(),
close: (id) => document.getElementById(id)?.close(),
},
});

Calling Actions

Basic Call

uizy.emit("notification.show", "Item saved!");

With Payload

uizy.emit("user.login", {
email: "user@example.com",
password: "secret",
});

Async Actions

uizy.on({
data: {
fetch: async (url) => {
const response = await fetch(url);
return response.json();
},
},
});

const data = await uizy.emit("data.fetch", "/api/users");

Silent Mode

Returns undefined instead of throwing if action doesn't exist:

uizy.emit("nonexistent.action", null, { silent: true }); // undefined

API Reference

uizy.emit(path, payload?, options?)

Call an action by its dot-notation path.

ParameterTypeDescription
pathstringDot-notation path (e.g., "user.login")
payloadunknownData to pass to the action
options.silentbooleanReturn undefined instead of throwing

uizy.on(items)

Register actions. Merges with existing actions.

uizy.on({
newAction: (data) => handleData(data),
});

uizy.actions.has(path)

Check if an action exists.

uizy.actions.has("user.login"); // true
uizy.actions.has("nonexistent"); // false

uizy.actions.paths()

Get all registered action paths.

uizy.actions.paths();
// ["user.login", "user.logout", "cart.add", ...]

uizy.actions.clear()

Remove all registered actions.

uizy.actions.clear();

uizy.actions.getTree()

Get the raw action tree (readonly).

const tree = uizy.actions.getTree();

Examples

Event Handling

uizy.start({
actions: {
ui: {
drawer: {
toggle: (side) => {
const app = uizy.get("app");
app?.action(side, ({ set }) => set());
},
open: (side) => {
const app = uizy.get("app");
app?.action(side, ({ set }) => set(true));
},
close: (side) => {
const app = uizy.get("app");
app?.action(side, ({ set }) => set(false));
},
},
},
},
});

// Usage in HTML
<button onclick="uizy.emit('ui.drawer.toggle', 'left')">Toggle Menu</button>;

Form Handling

uizy.on({
form: {
submit: async (formData) => {
try {
const response = await api.post("/submit", formData);
uizy.emit("notification.success", "Form submitted!");
return response;
} catch (error) {
uizy.emit("notification.error", error.message);
throw error;
}
},
validate: (data) => {
const errors = {};
if (!data.email) errors.email = "Email is required";
if (!data.password) errors.password = "Password is required";
return Object.keys(errors).length ? errors : null;
},
reset: (formId) => {
document.getElementById(formId)?.reset();
},
},
});

Analytics

uizy.on({
analytics: {
track: (event, data) => {
gtag("event", event, data);
},
page: (path) => {
gtag("config", "GA_ID", { page_path: path });
},
},
});

// Track button clicks
<button onclick="uizy.emit('analytics.track', 'click', { button: 'signup' })">
Sign Up
</button>;

API Layer

const API_BASE = "/api/v1";

uizy.on({
api: {
get: async (endpoint) => {
const response = await fetch(`${API_BASE}${endpoint}`);
if (!response.ok) throw new Error(response.statusText);
return response.json();
},
post: async ({ endpoint, data }) => {
const response = await fetch(`${API_BASE}${endpoint}`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data),
});
if (!response.ok) throw new Error(response.statusText);
return response.json();
},
delete: async (endpoint) => {
const response = await fetch(`${API_BASE}${endpoint}`, {
method: "DELETE",
});
if (!response.ok) throw new Error(response.statusText);
return response.ok;
},
},
});

// Usage
const users = await uizy.emit("api.get", "/users");
await uizy.emit("api.post", { endpoint: "/users", data: { name: "John" } });
await uizy.emit("api.delete", "/users/123");

Combining with Stores

uizy.start({
stores: {
user: {
current: uizy.store.atom(null),
isLoading: uizy.store.atom(false),
},
},
actions: {
user: {
fetch: async () => {
uizy.$("user.isLoading", { raw: true }).set(true);
try {
const user = await api.getCurrentUser();
uizy.$("user.current", { raw: true }).set(user);
} finally {
uizy.$("user.isLoading", { raw: true }).set(false);
}
},
},
},
});