Base abstract trigger component for React that manages popup behavior and positioning with hover, click, focus actions and precise alignment.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Comprehensive event system supporting multiple trigger actions with customizable delays and behaviors. The event system handles various user interactions including click, hover, focus, and context menu actions.
Core action types and configuration for controlling when popups show and hide.
/**
* Available trigger action types
*/
type ActionType = string; // Common actions: 'click', 'hover', 'focus', 'contextMenu', 'mouseEnter', 'mouseLeave', 'blur'
interface TriggerProps {
/** Primary trigger actions (both show and hide) */
action?: ActionType | ActionType[];
/** Specific actions that show the popup (overrides action) */
showAction?: ActionType[];
/** Specific actions that hide the popup (overrides action) */
hideAction?: ActionType[];
}Customizable delays for different action types to improve user experience.
interface TriggerProps {
/** Delay in seconds before showing popup on mouse enter */
mouseEnterDelay?: number; // default: 0
/** Delay in seconds before hiding popup on mouse leave */
mouseLeaveDelay?: number; // default: 0.1
/** Delay in seconds before showing popup on focus */
focusDelay?: number; // default: 0
/** Delay in seconds before hiding popup on blur */
blurDelay?: number; // default: 0.15
}Callbacks for handling popup and trigger events.
interface TriggerProps {
/** Called when popup visibility changes */
onPopupVisibleChange?: (visible: boolean) => void;
/** Called after popup visibility change animation completes */
afterPopupVisibleChange?: (visible: boolean) => void;
/** Called when popup is clicked */
onPopupClick?: React.MouseEventHandler<HTMLDivElement>;
/** Called when popup alignment is complete */
onPopupAlign?: (element: HTMLElement, align: AlignType) => void;
}Usage Examples:
import React, { useState } from "react";
import Trigger from "rc-trigger";
// Click trigger
function ClickTrigger() {
return (
<Trigger
action={['click']}
popup={<div>Click to toggle</div>}
onPopupVisibleChange={(visible) => {
console.log('Popup is now:', visible ? 'visible' : 'hidden');
}}
>
<button>Click me</button>
</Trigger>
);
}
// Hover trigger with delays
function HoverTrigger() {
return (
<Trigger
action={['hover']}
popup={<div>Hover popup with delays</div>}
mouseEnterDelay={0.2} // 200ms delay before showing
mouseLeaveDelay={0.5} // 500ms delay before hiding
>
<div style={{ padding: 20, background: '#f0f0f0' }}>
Hover over me
</div>
</Trigger>
);
}
// Focus trigger
function FocusTrigger() {
return (
<Trigger
action={['focus']}
popup={<div>Focus popup</div>}
focusDelay={0.1}
blurDelay={0.2}
>
<input placeholder="Focus on this input" />
</Trigger>
);
}
// Context menu trigger
function ContextMenuTrigger() {
return (
<Trigger
action={['contextMenu']}
popup={
<ul style={{ margin: 0, padding: 8, listStyle: 'none', background: 'white', border: '1px solid #ccc' }}>
<li>Copy</li>
<li>Paste</li>
<li>Delete</li>
</ul>
}
alignPoint={true}
>
<div style={{ padding: 20, background: '#f9f9f9' }}>
Right-click for context menu
</div>
</Trigger>
);
}
// Multiple actions
function MultiActionTrigger() {
return (
<Trigger
action={['click', 'hover']}
popup={<div>Works with both click and hover</div>}
mouseEnterDelay={0.1}
mouseLeaveDelay={0.3}
>
<button>Click or hover</button>
</Trigger>
);
}
// Different show/hide actions
function AsymmetricActions() {
return (
<Trigger
showAction={['click']}
hideAction={['click', 'hover']}
popup={<div>Click to show, click or hover away to hide</div>}
mouseLeaveDelay={0.1}
>
<button>Asymmetric actions</button>
</Trigger>
);
}
// Event callbacks
function EventCallbacks() {
const [events, setEvents] = useState([]);
const addEvent = (event) => {
setEvents(prev => [...prev.slice(-4), `${new Date().toLocaleTimeString()}: ${event}`]);
};
return (
<div>
<Trigger
action={['click']}
popup={
<div onClick={() => addEvent('Popup clicked')}>
Click inside popup
</div>
}
onPopupVisibleChange={(visible) => {
addEvent(`Visibility changed: ${visible}`);
}}
afterPopupVisibleChange={(visible) => {
addEvent(`Animation completed: ${visible}`);
}}
onPopupClick={() => {
addEvent('Popup click event');
}}
onPopupAlign={(element, align) => {
addEvent(`Popup aligned: ${align.points?.join(' to ')}`);
}}
>
<button>Click to see events</button>
</Trigger>
<div style={{ marginTop: 20 }}>
<h4>Events:</h4>
{events.map((event, index) => (
<div key={index}>{event}</div>
))}
</div>
</div>
);
}mouseEnterDelay and mouseLeaveDelayfocusDelay and blurDelayalignPoint={true} to position at cursorfunction ControlledTrigger() {
const [visible, setVisible] = useState(false);
const handleVisibilityChange = (newVisible) => {
// Custom logic before changing visibility
if (newVisible && !isUserLoggedIn()) {
showLoginDialog();
return;
}
setVisible(newVisible);
};
return (
<Trigger
popupVisible={visible}
onPopupVisibleChange={handleVisibilityChange}
popup={<div>Controlled popup</div>}
>
<button>Controlled trigger</button>
</Trigger>
);
}function ConditionalActions() {
const [isDisabled, setIsDisabled] = useState(false);
return (
<Trigger
action={isDisabled ? [] : ['click', 'hover']}
popup={<div>Conditional popup</div>}
>
<button disabled={isDisabled}>
{isDisabled ? 'Disabled' : 'Active'} trigger
</button>
</Trigger>
);
}function NestedTriggers() {
return (
<Trigger
action={['click']}
popup={
<div>
<p>Outer popup</p>
<Trigger
action={['click']}
popup={<div>Inner popup</div>}
>
<button>Inner trigger</button>
</Trigger>
</div>
}
>
<button>Outer trigger</button>
</Trigger>
);
}Install with Tessl CLI
npx tessl i tessl/npm-rc-trigger