Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsCommunityBlog
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

Back to skills

Antigravity Robius Event Action

ASecurity

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, 事件处理, 自定义动作

2 stars
0 votes
0 copies
0 views
Added 9/19/2026
code-qualityrustgoreacttesting

Works with

cli

Security Analysis

A100/100

Scanned 9/19/2026

Install to Claude Code

$npx -y skills add ibragimov-oasis/oasis-languages-jp --skill antigravity-robius-event-action --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Antigravity Robius Event Action?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Antigravity Robius Event Action
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/ibragimov-oasis-antigravity-robius-event-action/badge)](https://www.skillsdirectory.com/skills/ibragimov-oasis-antigravity-robius-event-action)

More formats (shields.io, HTML) on the badges page.

Download Zip
Files
SKILL.md
---
name: robius-event-action
description: |
  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,
  事件处理, 自定义动作
risk: unknown
source: community
tags:
  - domain/skills
  - artifact/skill
  - source/skills-antigravity
---

# 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

## Triggers

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

## 🔗 Связи

- [[MOC - Skills]] — Skills library
- [[skills/skills-antigravity]] — Category: skills-antigravity

Attribution

ibragimov-oasisibragimov-oasis
View sourceMore from ibragimov-oasis →
SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Related Skills

Caveman Commit

Ultra-compressed commit message generator. Cuts noise from commit messages while preserving intent and reasoning. Conventional Commits format. Subject ≤50 chars, body only when "why" isn't obvious. Use when user says "write a commit", "commit message", "generate commit", "/commit", or invokes /caveman-commit. Auto-triggers when staging changes.

1023331 votes

Caveman Review

Ultra-compressed code review comments. Cuts noise from PR feedback while preserving the actionable signal. Each comment is one line: location, problem, fix. Use when user says "review this PR", "code review", "review the diff", "/review", or invokes /caveman-review. Auto-triggers when reviewing pull requests.

1023331 votes

Springboot Verification

Verification loop for Spring Boot projects: build, static analysis, tests with coverage, security scans, and diff review before release or PR.

2456590 votes

Verification Loop

一个全面的 Claude Code 会话验证系统。

2456590 votes

Django Verification

Verification loop for Django projects: migrations, linting, tests with coverage, security scans, and deployment readiness checks before release or PR.

2456590 votes
View all in code-quality →