用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/julianoczkowski/create-trimble-app --skill fix-modus-component-event-issues命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
基于 SOC 职业分类
正在显示 SKILL.md
| name | fix-modus-component-event-issues |
| description | Debug and fix common event handling problems with Modus web components |
Debug and fix common event handling problems with Modus web components.
Use this skill when:
Symptoms: Click handlers, change handlers, or other events don't fire.
Causes:
Solution:
// ✅ CORRECT: Proper event listener setup
useEffect(() => {
const component = componentRef.current;
if (!component) return;
const handleEvent = (event: Event) => {
onEvent?.(event as CustomEvent<EventDetailType>);
};
if (onEvent) {
component.addEventListener("eventName", handleEvent);
}
return () => {
if (onEvent) {
component.removeEventListener("eventName", handleEvent);
}
};
}, [onEvent]); // ✅ Include handler in dependencies
Checklist:
const componentRef = useRef<HTMLModusWcComponentElement>(null)<ModusWcComponent ref={componentRef} />useEffectSymptoms: Memory leaks, events firing multiple times, component errors after unmount.
Solution:
useEffect(() => {
const component = componentRef.current;
if (!component) return;
const handleEvent = (event: Event) => {
onEvent?.(event as CustomEvent<EventDetailType>);
};
component.addEventListener("eventName", handleEvent);
// ✅ CRITICAL: Always return cleanup function
return () => {
component.removeEventListener("eventName", handleEvent);
};
}, [onEvent]);
Symptoms: Events never fire, wrong event type received.
Common Event Names:
| Component | Event Name | Detail Type |
|---|---|---|
| Checkbox | inputChange | InputEvent |
| TextInput | inputChange | InputEvent |
| DropdownMenu | itemSelect | { value: string } |
| DropdownMenu | menuVisibilityChange | { isVisible: boolean } |
| Navbar | searchClick | MouseEvent | KeyboardEvent |
| Accordion | expandedChange | { expanded: boolean; index: number } |
Solution: Check Modus documentation for exact event names. They're case-sensitive.
Symptoms: Cannot read property 'addEventListener' of null, events don't attach.
Solution:
// ✅ CORRECT: Ref setup
const componentRef = useRef<HTMLModusWcComponentElement>(null);
useEffect(() => {
const component = componentRef.current;
if (!component) return; // ✅ Check before use
// Set up listeners
}, []);
return (
<ModusWcComponent ref={componentRef} /> // ✅ Pass ref
);
Symptoms: Stale closures, handlers use old values.
Solution:
useEffect(() => {
const component = componentRef.current;
if (!component) return;
const handleEvent = (event: Event) => {
onEvent?.(event as CustomEvent<EventDetailType>);
};
if (onEvent) {
component.addEventListener("eventName", handleEvent);
}
return () => {
if (onEvent) {
component.removeEventListener("eventName", handleEvent);
}
};
}, [onEvent]); // ✅ Include handler in dependencies
Symptoms: Can't access component properties, wrong value extracted.
Solution:
// ✅ CORRECT: Cast to proper element type
const handleInputChange = (event: Event) => {
const customEvent = event as CustomEvent<InputEvent>;
const value = (customEvent.target as HTMLModusWcTextInputElement).value;
onInputChange?.(value);
};
// ❌ WRONG: Don't use event.detail for input values
const handleInputChange = (event: Event) => {
const value = event.detail; // Wrong for input components!
};
Symptoms: Events fire multiple times, duplicate handlers.
Solution:
// ✅ CORRECT: Conditional attachment
if (onEvent) {
component.addEventListener("eventName", handleEvent);
}
// ✅ CORRECT: Remove in cleanup
return () => {
if (onEvent) {
component.removeEventListener("eventName", handleEvent);
}
};
When events aren't working, check:
Ref Setup
useRef is created with correct typeif (!component) return)Event Listener Setup
useEffectCleanup
useEffectDependencies
Event Handling
CustomEvent typetarget.value vs detail)useEffect(() => {
const component = componentRef.current;
if (!component) {
console.error("Component ref is null");
return;
}
console.log("Setting up event listener for:", component);
const handleEvent = (event: Event) => {
console.log("Event fired:", event);
console.log("Event type:", event.type);
console.log("Event target:", event.target);
onEvent?.(event as CustomEvent<EventDetailType>);
};
component.addEventListener("eventName", handleEvent);
console.log("Event listener attached");
return () => {
console.log("Cleaning up event listener");
component.removeEventListener("eventName", handleEvent);
};
}, [onEvent]);
// ✅ Verify this pattern
const componentRef = useRef<HTMLModusWcComponentElement>(null);
useEffect(() => {
const component = componentRef.current;
if (!component) return;
const handleEvent = (event: Event) => {
onEvent?.(event as CustomEvent<EventDetailType>);
};
if (onEvent) {
component.addEventListener("eventName", handleEvent);
}
return () => {
if (onEvent) {
component.removeEventListener("eventName", handleEvent);
}
};
}, [onEvent]);
return <ModusWcComponent ref={componentRef} />;
// ✅ Verify all events are set up
useEffect(() => {
const component = componentRef.current;
if (!component) return;
const handleEvent1 = (event: Event) => {
onEvent1?.(event as CustomEvent<Type1>);
};
const handleEvent2 = (event: Event) => {
onEvent2?.(event as CustomEvent<Type2>);
};
if (onEvent1) component.addEventListener("event1", handleEvent1);
if (onEvent2) component.addEventListener("event2", handleEvent2);
return () => {
if (onEvent1) component.removeEventListener("event1", handleEvent1);
if (onEvent2) component.removeEventListener("event2", handleEvent2);
};
}, [onEvent1, onEvent2]); // ✅ All handlers in dependencies
console.log(componentRef.current)target.value vs detailsrc/components/ModusCheckbox.tsx - Event handling examplesrc/components/ModusDropdownMenu.tsx - Multiple events examplesrc/components/ModusNavbar.tsx - Complex event handling.cursor/rules/modus-react-integration.mdc - Integration patterns