make-event-props
Version:
Returns an object with on-event callback props curried with provided args.
251 lines (236 loc) • 5.82 kB
text/typescript
// As defined on the list of supported events: https://reactjs.org/docs/events.html
export const clipboardEvents = ['onCopy', 'onCut', 'onPaste'] as const;
export const compositionEvents = [
'onCompositionEnd',
'onCompositionStart',
'onCompositionUpdate',
] as const;
export const focusEvents = ['onFocus', 'onBlur'] as const;
export const formEvents = ['onInput', 'onInvalid', 'onReset', 'onSubmit'] as const;
export const imageEvents = ['onLoad', 'onError'] as const;
export const keyboardEvents = ['onKeyDown', 'onKeyPress', 'onKeyUp'] as const;
export const mediaEvents = [
'onAbort',
'onCanPlay',
'onCanPlayThrough',
'onDurationChange',
'onEmptied',
'onEncrypted',
'onEnded',
'onError',
'onLoadedData',
'onLoadedMetadata',
'onLoadStart',
'onPause',
'onPlay',
'onPlaying',
'onProgress',
'onRateChange',
'onSeeked',
'onSeeking',
'onStalled',
'onSuspend',
'onTimeUpdate',
'onVolumeChange',
'onWaiting',
] as const;
export const mouseEvents = [
'onClick',
'onContextMenu',
'onDoubleClick',
'onMouseDown',
'onMouseEnter',
'onMouseLeave',
'onMouseMove',
'onMouseOut',
'onMouseOver',
'onMouseUp',
] as const;
export const dragEvents = [
'onDrag',
'onDragEnd',
'onDragEnter',
'onDragExit',
'onDragLeave',
'onDragOver',
'onDragStart',
'onDrop',
] as const;
export const selectionEvents = ['onSelect'] as const;
export const touchEvents = ['onTouchCancel', 'onTouchEnd', 'onTouchMove', 'onTouchStart'] as const;
export const pointerEvents = [
'onPointerDown',
'onPointerMove',
'onPointerUp',
'onPointerCancel',
'onGotPointerCapture',
'onLostPointerCapture',
'onPointerEnter',
'onPointerLeave',
'onPointerOver',
'onPointerOut',
] as const;
export const uiEvents = ['onScroll'] as const;
export const wheelEvents = ['onWheel'] as const;
export const animationEvents = [
'onAnimationStart',
'onAnimationEnd',
'onAnimationIteration',
] as const;
export const transitionEvents = ['onTransitionEnd'] as const;
export const otherEvents = ['onToggle'] as const;
export const changeEvents = ['onChange'] as const;
export const allEvents: readonly [
'onCopy',
'onCut',
'onPaste',
'onCompositionEnd',
'onCompositionStart',
'onCompositionUpdate',
'onFocus',
'onBlur',
'onInput',
'onInvalid',
'onReset',
'onSubmit',
'onLoad',
'onError',
'onKeyDown',
'onKeyPress',
'onKeyUp',
'onAbort',
'onCanPlay',
'onCanPlayThrough',
'onDurationChange',
'onEmptied',
'onEncrypted',
'onEnded',
'onError',
'onLoadedData',
'onLoadedMetadata',
'onLoadStart',
'onPause',
'onPlay',
'onPlaying',
'onProgress',
'onRateChange',
'onSeeked',
'onSeeking',
'onStalled',
'onSuspend',
'onTimeUpdate',
'onVolumeChange',
'onWaiting',
'onClick',
'onContextMenu',
'onDoubleClick',
'onMouseDown',
'onMouseEnter',
'onMouseLeave',
'onMouseMove',
'onMouseOut',
'onMouseOver',
'onMouseUp',
'onDrag',
'onDragEnd',
'onDragEnter',
'onDragExit',
'onDragLeave',
'onDragOver',
'onDragStart',
'onDrop',
'onSelect',
'onTouchCancel',
'onTouchEnd',
'onTouchMove',
'onTouchStart',
'onPointerDown',
'onPointerMove',
'onPointerUp',
'onPointerCancel',
'onGotPointerCapture',
'onLostPointerCapture',
'onPointerEnter',
'onPointerLeave',
'onPointerOver',
'onPointerOut',
'onScroll',
'onWheel',
'onAnimationStart',
'onAnimationEnd',
'onAnimationIteration',
'onTransitionEnd',
'onChange',
'onToggle',
] = [
...clipboardEvents,
...compositionEvents,
...focusEvents,
...formEvents,
...imageEvents,
...keyboardEvents,
...mediaEvents,
...mouseEvents,
...dragEvents,
...selectionEvents,
...touchEvents,
...pointerEvents,
...uiEvents,
...wheelEvents,
...animationEvents,
...transitionEvents,
...changeEvents,
...otherEvents,
] as const;
type AllEvents = (typeof allEvents)[number];
// biome-ignore lint/suspicious/noExplicitAny: Impossible to type
type EventHandler<ArgsType> = (event: any, args: ArgsType) => void;
// Creates inferred type for event handler without args.
type EventHandlerWithoutArgs<ArgsType, OriginalEventHandler> = OriginalEventHandler extends (
event: infer Event,
args: ArgsType,
) => void
? (event: Event) => void
: never;
export type EventProps<ArgsType> = {
[K in AllEvents]?: EventHandler<ArgsType>;
};
type Props<ArgsType> = Record<string, unknown> & EventProps<ArgsType>;
type EventPropsWithoutArgs<ArgsType, PropsType> = {
[K in keyof PropsType as K extends AllEvents ? K : never]: EventHandlerWithoutArgs<
ArgsType,
PropsType[K]
>;
};
type GetArgs<ArgsType> = (eventName: string) => ArgsType;
/**
* Returns an object with on-event callback props curried with provided args.
*
* @template ArgsType Type of arguments to curry on-event callbacks with.
* @param {PropsType} props Props passed to a component.
* @param {GetArgs<ArgsType>} [getArgs] A function that returns argument(s) on-event callbacks
* shall be curried with.
*/
export default function makeEventProps<
ArgsType,
PropsType extends Props<ArgsType> = Props<ArgsType>,
>(props: PropsType, getArgs?: GetArgs<ArgsType>): EventPropsWithoutArgs<ArgsType, PropsType> {
const eventProps: EventPropsWithoutArgs<ArgsType, PropsType> = {} as EventPropsWithoutArgs<
ArgsType,
PropsType
>;
for (const eventName of allEvents) {
type EventHandlerType = EventPropsWithoutArgs<ArgsType, PropsType>[typeof eventName];
const eventHandler = props[eventName];
if (!eventHandler) {
continue;
}
if (getArgs) {
eventProps[eventName] = ((event) =>
eventHandler(event, getArgs(eventName))) as EventHandlerType;
} else {
eventProps[eventName] = eventHandler as EventHandlerType;
}
}
return eventProps;
}