robius-event-action
CRITICAL: Use for Robius event and action patterns. Triggers on: custom action, MatchEvent, post_action, cx.widget_action, handle_actions, DefaultNone, widget action, event handling, 事件处理, 自定义动作
Best use case
robius-event-action is best used when you need a repeatable AI agent workflow instead of a one-off prompt. It is especially useful for teams working in multi. CRITICAL: Use for Robius event and action patterns. Triggers on: custom action, MatchEvent, post_action, cx.widget_action, handle_actions, DefaultNone, widget action, event handling, 事件处理, 自定义动作
CRITICAL: Use for Robius event and action patterns. Triggers on: custom action, MatchEvent, post_action, cx.widget_action, handle_actions, DefaultNone, widget action, event handling, 事件处理, 自定义动作
Users should expect a more consistent workflow output, faster repeated execution, and less time spent rewriting prompts from scratch.
Practical example
Example input
Use the "robius-event-action" skill to help with this workflow task. Context: CRITICAL: Use for Robius event and action patterns. Triggers on: custom action, MatchEvent, post_action, cx.widget_action, handle_actions, DefaultNone, widget action, event handling, 事件处理, 自定义动作
Example output
A structured workflow result with clearer steps, more consistent formatting, and an output that is easier to reuse in the next run.
When to use this skill
- Use this skill when you want a reusable workflow rather than writing the same prompt again and again.
When not to use this skill
- Do not use this when you only need a one-off answer and do not need a reusable workflow.
- Do not use it if you cannot install or maintain the related files, repository context, or supporting tools.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/robius-event-action/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How robius-event-action Compares
| Feature / Agent | robius-event-action | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
CRITICAL: Use for Robius event and action patterns. Triggers on: custom action, MatchEvent, post_action, cx.widget_action, handle_actions, DefaultNone, widget action, event handling, 事件处理, 自定义动作
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
Related Guides
AI Agents for Marketing
Discover AI agents for marketing workflows, from SEO and content production to campaign research, outreach, and analytics.
AI Agents for Startups
Explore AI agent skills for startup validation, product research, growth experiments, documentation, and fast execution with small teams.
AI Agents for Coding
Browse AI agent skills for coding, debugging, testing, refactoring, code review, and developer workflows across Claude, Cursor, and Codex.
SKILL.md Source
# Robius Event and Action Patterns Skill
Best practices for event handling and action patterns in Makepad applications based on Robrix and Moly codebases.
**Source codebases:**
- **Robrix**: Matrix chat client - MessageAction, RoomsListAction, AppStateAction
- **Moly**: AI chat application - StoreAction, ChatAction, NavigationAction, Timer patterns
## When to Use
Use this skill when:
- Implementing custom actions in Makepad
- Handling events in widgets
- Centralizing action handling in App
- Widget-to-widget communication
- Keywords: makepad action, makepad event, widget action, handle_actions, cx.widget_action
## Custom Action Pattern
### Defining Domain-Specific Actions
```rust
use makepad_widgets::*;
/// Actions emitted by the Message widget
#[derive(Clone, DefaultNone, Debug)]
pub enum MessageAction {
/// User wants to react to a message
React { details: MessageDetails, reaction: String },
/// User wants to reply to a message
Reply(MessageDetails),
/// User wants to edit a message
Edit(MessageDetails),
/// User wants to delete a message
Delete(MessageDetails),
/// User requested to open context menu
OpenContextMenu { details: MessageDetails, abs_pos: DVec2 },
/// Required default variant
None,
}
/// Data associated with a message action
#[derive(Clone, Debug)]
pub struct MessageDetails {
pub room_id: OwnedRoomId,
pub event_id: OwnedEventId,
pub content: String,
pub sender_id: OwnedUserId,
}
```
### Emitting Actions from Widgets
```rust
impl Widget for Message {
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
self.view.handle_event(cx, event, scope);
let area = self.view.area();
match event.hits(cx, area) {
Hit::FingerDown(_fe) => {
cx.set_key_focus(area);
}
Hit::FingerUp(fe) => {
if fe.is_over && fe.is_primary_hit() && fe.was_tap() {
// Emit widget action
cx.widget_action(
self.widget_uid(),
&scope.path,
MessageAction::Reply(self.get_details()),
);
}
}
Hit::FingerLongPress(lpe) => {
cx.widget_action(
self.widget_uid(),
&scope.path,
MessageAction::OpenContextMenu {
details: self.get_details(),
abs_pos: lpe.abs,
},
);
}
_ => {}
}
}
}
```
## Centralized Action Handling in App
### Using MatchEvent Trait
```rust
impl MatchEvent for App {
fn handle_startup(&mut self, cx: &mut Cx) {
// Called once on app startup
self.initialize(cx);
}
fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions) {
for action in actions {
// Pattern 1: Direct downcast for non-widget actions
if let Some(action) = action.downcast_ref::<LoginAction>() {
match action {
LoginAction::LoginSuccess => {
self.app_state.logged_in = true;
self.update_ui_visibility(cx);
}
LoginAction::LoginFailure(error) => {
self.show_error(cx, error);
}
}
continue; // Action handled
}
// Pattern 2: Widget action cast
if let MessageAction::OpenContextMenu { details, abs_pos } =
action.as_widget_action().cast()
{
self.show_context_menu(cx, details, abs_pos);
continue;
}
// Pattern 3: Match on downcast_ref for enum variants
match action.downcast_ref() {
Some(AppStateAction::RoomFocused(room)) => {
self.app_state.selected_room = Some(room.clone());
continue;
}
Some(AppStateAction::NavigateToRoom { destination }) => {
self.navigate_to_room(cx, destination);
continue;
}
_ => {}
}
// Pattern 4: Modal actions
match action.downcast_ref() {
Some(ModalAction::Open { kind }) => {
self.ui.modal(ids!(my_modal)).open(cx);
continue;
}
Some(ModalAction::Close { was_internal }) => {
if *was_internal {
self.ui.modal(ids!(my_modal)).close(cx);
}
continue;
}
_ => {}
}
}
}
}
impl AppMain for App {
fn handle_event(&mut self, cx: &mut Cx, event: &Event) {
// Forward to MatchEvent
self.match_event(cx, event);
// Pass events to widget tree
let scope = &mut Scope::with_data(&mut self.app_state);
self.ui.handle_event(cx, event, scope);
}
}
```
## Action Types
### Widget Actions (UI Thread)
Emitted by widgets, handled in the same frame:
```rust
// Emitting
cx.widget_action(
self.widget_uid(),
&scope.path,
MyAction::Something,
);
// Handling (two patterns)
// Pattern A: Direct cast for widget actions
if let MyAction::Something = action.as_widget_action().cast() {
// handle...
}
// Pattern B: With widget UID matching
if let Some(uid) = action.as_widget_action().widget_uid() {
if uid == my_expected_uid {
if let MyAction::Something = action.as_widget_action().cast() {
// handle...
}
}
}
```
### Posted Actions (From Async)
Posted from async tasks, received in next event cycle:
```rust
// In async task
Cx::post_action(DataFetchedAction { data });
SignalToUI::set_ui_signal(); // Wake UI thread
// Handling in App (NOT widget actions)
if let Some(action) = action.downcast_ref::<DataFetchedAction>() {
self.process_data(&action.data);
}
```
### Global Actions
For app-wide state changes:
```rust
// Using cx.action() for global actions
cx.action(NavigationAction::GoBack);
// Handling
if let Some(NavigationAction::GoBack) = action.downcast_ref() {
self.navigate_back(cx);
}
```
## Event Handling Patterns
### Hit Testing
```rust
impl Widget for MyWidget {
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
let area = self.view.area();
match event.hits(cx, area) {
Hit::FingerDown(fe) => {
cx.set_key_focus(area);
// Start drag, capture, etc.
}
Hit::FingerUp(fe) => {
if fe.is_over && fe.is_primary_hit() {
if fe.was_tap() {
// Single tap
}
if fe.was_long_press() {
// Long press
}
}
}
Hit::FingerMove(fe) => {
// Drag handling
}
Hit::FingerHoverIn(_) => {
self.animator_play(cx, id!(hover.on));
}
Hit::FingerHoverOut(_) => {
self.animator_play(cx, id!(hover.off));
}
Hit::FingerScroll(se) => {
// Scroll handling
}
_ => {}
}
}
}
```
### Keyboard Events
```rust
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
if let Event::KeyDown(ke) = event {
match ke.key_code {
KeyCode::Return if !ke.modifiers.shift => {
self.submit(cx);
}
KeyCode::Escape => {
self.cancel(cx);
}
KeyCode::KeyC if ke.modifiers.control || ke.modifiers.logo => {
self.copy_to_clipboard(cx);
}
_ => {}
}
}
}
```
### Signal Events
For handling async updates:
```rust
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
if let Event::Signal = event {
// Poll update queues
while let Some(update) = PENDING_UPDATES.pop() {
self.apply_update(cx, update);
}
}
}
```
## Action Chaining Pattern
Widget emits action → Parent catches and re-emits with more context:
```rust
// In child widget
cx.widget_action(
self.widget_uid(),
&scope.path,
ItemAction::Selected(item_id),
);
// In parent widget's handle_event
if let ItemAction::Selected(item_id) = action.as_widget_action().cast() {
// Add context and forward to App
cx.widget_action(
self.widget_uid(),
&scope.path,
ListAction::ItemSelected {
list_id: self.list_id.clone(),
item_id,
},
);
}
```
## Best Practices
1. **Use `DefaultNone` derive**: All action enums must have a `None` variant
2. **Use `continue` after handling**: Prevents unnecessary processing
3. **Downcast pattern for async actions**: Posted actions are not widget actions
4. **Widget action cast for UI actions**: Use `as_widget_action().cast()`
5. **Always call `SignalToUI::set_ui_signal()`**: After posting actions from async
6. **Centralize in App::handle_actions**: Keep action handling in one place
7. **Use descriptive action names**: `MessageAction::Reply` not `MessageAction::Action1`
## Reference Files
- `references/action-patterns.md` - Additional action patterns (Robrix)
- `references/event-handling.md` - Event handling reference (Robrix)
- `references/moly-action-patterns.md` - Moly-specific patterns
- Store-based action forwarding
- Timer-based retry pattern
- Radio button navigation
- External link handling
- Platform-conditional actions (#[cfg])
- UiRunner event handling
## Limitations
- Use this skill only when the task clearly matches the scope described above.
- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.
- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.Related Skills
event-sourcing-architect
Expert in event sourcing, CQRS, and event-driven architecture patterns. Masters event store design, projection building, saga orchestration, and eventual consistency patterns. Use PROACTIVELY for event-sourced systems, audit trail requirements, or complex domain modeling with temporal queries.
churn-prevention
Reduce voluntary and involuntary churn with cancel flows, save offers, dunning, win-back tactics, and retention strategy. Use when users are cancelling, failed payments are rising, or subscription retention needs improvement.
azure-eventhub-java
Build real-time streaming applications with Azure Event Hubs SDK for Java. Use when implementing event streaming, high-throughput data ingestion, or building event-driven architectures.
threejs-interaction
Three.js interaction - raycasting, controls, mouse/touch input, object selection. Use when handling user input, implementing click detection, adding camera controls, or creating interactive 3D experiences.
security-requirement-extraction
Derive security requirements from threat models and business context. Use when translating threats into actionable requirements, creating security user stories, or building security test cases.
robius-widget-patterns
CRITICAL: Use for Robius widget patterns. Triggers on: apply_over, TextOrImage, modal, 可复用, 模态, collapsible, drag drop, reusable widget, widget design, pageflip, 组件设计, 组件模式
robius-state-management
CRITICAL: Use for Robius state management patterns. Triggers on: AppState, persistence, theme switch, 状态管理, Scope::with_data, save state, load state, serde, 状态持久化, 主题切换
robius-matrix-integration
CRITICAL: Use for Matrix SDK integration with Makepad. Triggers on: Matrix SDK, sliding sync, MatrixRequest, timeline, matrix-sdk, matrix client, robrix, matrix room, Matrix 集成, 聊天客户端
robius-app-architecture
CRITICAL: Use for Robius app architecture patterns. Triggers on: Tokio, async, submit_async_request, 异步, 架构, SignalToUI, Cx::post_action, worker task, app structure, MatchEvent, handle_startup
agentic-actions-auditor
Audits GitHub Actions workflows for security vulnerabilities in AI agent integrations including Claude Code Action, Gemini CLI, OpenAI Codex, and GitHub AI Inference. Detects attack vectors where attacker-controlled input reaches. AI agents running in CI/CD pipelines.
github-actions-templates
Production-ready GitHub Actions workflow patterns for testing, building, and deploying applications.
nextjs-best-practices
Next.js App Router principles. Server Components, data fetching, routing patterns.