Skip to main content Skills Marketplace Découvrez et explorez les compétences IA créées par la communauté.
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Copier le promptAfficher les détails du prompt Une commande directe contourne le prompt de vérification. Examinez la source avant de l'exécuter.
npx skills add https://github.com/BEKO2210/Firstbrain --skill robius-event-actionLa commande reste sur une seule ligne. Faites défiler horizontalement pour la vérifier avant de la copier.
Vous préférez une copie locale ? Téléchargez les fichiers actuellement disponibles dans SkillsMP.
Télécharger Zip Téléchargement... Métiers associés SOC
Basé sur la classification professionnelle SOC
name robius-event-action description | type skill created 2026-02-27T00:00:00.000Z domain productivity category developer-experience risk unknown source community tags ["skill","productivity","developer-experience","robius","event","action"]
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
use makepad_widgets::*;
#[derive(Clone, DefaultNone, Debug)]
pub enum MessageAction {
React { details: MessageDetails, reaction: String },
Reply (MessageDetails),
Edit (MessageDetails),
Delete (MessageDetails),
OpenContextMenu { details: MessageDetails, abs_pos: DVec2 },
None ,
}
#[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 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 () {
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 impl MatchEvent for App {
fn handle_startup (&mut self , cx: &mut Cx) {
self .initialize (cx);
}
fn handle_actions (&mut self , cx: &mut Cx, actions: &Actions) {
for action in 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 ;
}
if let MessageAction ::OpenContextMenu { details, abs_pos } =
action.as_widget_action ().cast ()
{
self .show_context_menu (cx, details, abs_pos);
continue ;
}
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 ;
}
_ => {}
}
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) {
self .match_event (cx, event);
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:
cx.widget_action (
self .widget_uid (),
&scope.path,
MyAction::Something,
);
if let MyAction ::Something = action.as_widget_action ().cast () {
}
if let Some (uid) = action.as_widget_action ().widget_uid () {
if uid == my_expected_uid {
if let MyAction ::Something = action.as_widget_action ().cast () {
}
}
}
Posted Actions (From Async) Posted from async tasks, received in next event cycle:
Cx::post_action (DataFetchedAction { data });
SignalToUI::set_ui_signal ();
if let Some (action) = action.downcast_ref::<DataFetchedAction>() {
self .process_data (&action.data);
}
Global Actions For app-wide state changes:
cx.action (NavigationAction::GoBack);
if let Some (NavigationAction::GoBack) = action.downcast_ref () {
self .navigate_back (cx);
}
Event Handling Patterns
Hit Testing 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);
}
Hit::FingerUp (fe) => {
if fe.is_over && fe.is_primary_hit () {
if fe.was_tap () {
}
if fe.was_long_press () {
}
}
}
Hit::FingerMove (fe) => {
}
Hit::FingerHoverIn (_) => {
self .animator_play (cx, id!(hover.on));
}
Hit::FingerHoverOut (_) => {
self .animator_play (cx, id!(hover.off));
}
Hit::FingerScroll (se) => {
}
_ => {}
}
}
}
Keyboard Events 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:
fn handle_event (&mut self , cx: &mut Cx, event: &Event, scope: &mut Scope) {
if let Event ::Signal = event {
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:
cx.widget_action (
self .widget_uid (),
&scope.path,
ItemAction::Selected (item_id),
);
if let ItemAction ::Selected (item_id) = action.as_widget_action ().cast () {
cx.widget_action (
self .widget_uid (),
&scope.path,
ListAction::ItemSelected {
list_id: self .list_id.clone (),
item_id,
},
);
}
Best Practices
Use DefaultNone derive : All action enums must have a None variant
Use continue after handling : Prevents unnecessary processing
Downcast pattern for async actions : Posted actions are not widget actions
Widget action cast for UI actions : Use as_widget_action().cast()
Always call SignalToUI::set_ui_signal() : After posting actions from async
Centralize in App::handle_actions : Keep action handling in one place
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
Connections
Domain: [[Produktivitaet & Werkzeuge]]
Kategorie: [[Developer Experience]]
Navigation: [[Skills Uebersicht]], [[Home]]