Numerous Bug Fixes
Some checks failed
Automated Container Build / build-and-push (push) Failing after 8s
Some checks failed
Automated Container Build / build-and-push (push) Failing after 8s
This commit is contained in:
parent
02eefdac0e
commit
267d429122
959 changed files with 145571 additions and 221 deletions
21
frontend/node_modules/make-event-props/LICENSE
generated
vendored
Normal file
21
frontend/node_modules/make-event-props/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2018–2024 Wojciech Maj
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
40
frontend/node_modules/make-event-props/README.md
generated
vendored
Normal file
40
frontend/node_modules/make-event-props/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
[](https://www.npmjs.com/package/make-event-props)  [](https://github.com/wojtekmaj/make-event-props/actions)
|
||||
|
||||
# Make-Event-Props
|
||||
|
||||
A function that, given props, returns an object of event callback props optionally curried with additional arguments.
|
||||
|
||||
This package allows you to pass event callback props to a rendered DOM element without the risk of applying any invalid props that could cause unwanted side effects.
|
||||
|
||||
## tl;dr
|
||||
|
||||
- Install by executing `npm install make-event-props` or `yarn add make-event-props`.
|
||||
- Import by adding `import makeEventProps from 'make-event-props'`.
|
||||
- Create your event props object:
|
||||
```ts
|
||||
const eventProps = useMemo(
|
||||
() => makeEventProps(props, (eventName) => additionalArgs),
|
||||
[additionalArgs],
|
||||
);
|
||||
```
|
||||
- Use your event props:
|
||||
```tsx
|
||||
return <div {...eventProps} />;
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
The MIT License.
|
||||
|
||||
## Author
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td >
|
||||
<img src="https://avatars.githubusercontent.com/u/5426427?v=4&s=128" width="64" height="64" alt="Wojciech Maj">
|
||||
</td>
|
||||
<td>
|
||||
<a href="https://github.com/wojtekmaj">Wojciech Maj</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
58
frontend/node_modules/make-event-props/package.json
generated
vendored
Normal file
58
frontend/node_modules/make-event-props/package.json
generated
vendored
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
{
|
||||
"name": "make-event-props",
|
||||
"version": "2.0.0",
|
||||
"description": "Returns an object with on-event callback props curried with provided args.",
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
"main": "./dist/index.js",
|
||||
"source": "./src/index.ts",
|
||||
"types": "./dist/index.d.ts",
|
||||
"exports": {
|
||||
".": "./dist/index.js",
|
||||
"./*": "./*"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc --project tsconfig.build.json",
|
||||
"clean": "rimraf dist",
|
||||
"format": "biome format",
|
||||
"lint": "biome lint",
|
||||
"prepack": "yarn clean && yarn build",
|
||||
"test": "yarn lint && yarn tsc && yarn format && yarn unit",
|
||||
"tsc": "tsc",
|
||||
"unit": "vitest --typecheck"
|
||||
},
|
||||
"keywords": [
|
||||
"react",
|
||||
"event",
|
||||
"event props"
|
||||
],
|
||||
"author": {
|
||||
"name": "Wojciech Maj",
|
||||
"email": "kontakt@wojtekmaj.pl"
|
||||
},
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "1.9.0",
|
||||
"@types/react": "*",
|
||||
"husky": "^9.0.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"rimraf": "^6.0.0",
|
||||
"typescript": "^5.5.2",
|
||||
"vitest": "^3.0.5"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"provenance": true
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"src"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/wojtekmaj/make-event-props.git"
|
||||
},
|
||||
"funding": "https://github.com/wojtekmaj/make-event-props?sponsor=1",
|
||||
"packageManager": "yarn@4.3.1"
|
||||
}
|
||||
86
frontend/node_modules/make-event-props/src/__snapshots__/index.spec.tsx.snap
generated
vendored
Normal file
86
frontend/node_modules/make-event-props/src/__snapshots__/index.spec.tsx.snap
generated
vendored
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`allEvents > should contain all events 1`] = `
|
||||
Set {
|
||||
"onAbort",
|
||||
"onAnimationEnd",
|
||||
"onAnimationIteration",
|
||||
"onAnimationStart",
|
||||
"onBlur",
|
||||
"onCanPlay",
|
||||
"onCanPlayThrough",
|
||||
"onChange",
|
||||
"onClick",
|
||||
"onCompositionEnd",
|
||||
"onCompositionStart",
|
||||
"onCompositionUpdate",
|
||||
"onContextMenu",
|
||||
"onCopy",
|
||||
"onCut",
|
||||
"onDoubleClick",
|
||||
"onDrag",
|
||||
"onDragEnd",
|
||||
"onDragEnter",
|
||||
"onDragExit",
|
||||
"onDragLeave",
|
||||
"onDragOver",
|
||||
"onDragStart",
|
||||
"onDrop",
|
||||
"onDurationChange",
|
||||
"onEmptied",
|
||||
"onEncrypted",
|
||||
"onEnded",
|
||||
"onError",
|
||||
"onFocus",
|
||||
"onGotPointerCapture",
|
||||
"onInput",
|
||||
"onInvalid",
|
||||
"onKeyDown",
|
||||
"onKeyPress",
|
||||
"onKeyUp",
|
||||
"onLoad",
|
||||
"onLoadStart",
|
||||
"onLoadedData",
|
||||
"onLoadedMetadata",
|
||||
"onLostPointerCapture",
|
||||
"onMouseDown",
|
||||
"onMouseEnter",
|
||||
"onMouseLeave",
|
||||
"onMouseMove",
|
||||
"onMouseOut",
|
||||
"onMouseOver",
|
||||
"onMouseUp",
|
||||
"onPaste",
|
||||
"onPause",
|
||||
"onPlay",
|
||||
"onPlaying",
|
||||
"onPointerCancel",
|
||||
"onPointerDown",
|
||||
"onPointerEnter",
|
||||
"onPointerLeave",
|
||||
"onPointerMove",
|
||||
"onPointerOut",
|
||||
"onPointerOver",
|
||||
"onPointerUp",
|
||||
"onProgress",
|
||||
"onRateChange",
|
||||
"onReset",
|
||||
"onScroll",
|
||||
"onSeeked",
|
||||
"onSeeking",
|
||||
"onSelect",
|
||||
"onStalled",
|
||||
"onSubmit",
|
||||
"onSuspend",
|
||||
"onTimeUpdate",
|
||||
"onToggle",
|
||||
"onTouchCancel",
|
||||
"onTouchEnd",
|
||||
"onTouchMove",
|
||||
"onTouchStart",
|
||||
"onTransitionEnd",
|
||||
"onVolumeChange",
|
||||
"onWaiting",
|
||||
"onWheel",
|
||||
}
|
||||
`;
|
||||
229
frontend/node_modules/make-event-props/src/index.spec.tsx
generated
vendored
Normal file
229
frontend/node_modules/make-event-props/src/index.spec.tsx
generated
vendored
Normal file
|
|
@ -0,0 +1,229 @@
|
|||
import { assertType, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import makeEventProps, { allEvents } from './index.js';
|
||||
|
||||
describe('makeEventProps()', () => {
|
||||
const fakeEvent = {};
|
||||
|
||||
it('returns object with valid and only valid event callbacks', () => {
|
||||
const props = {
|
||||
onClick: vi.fn(),
|
||||
someInvalidProp: vi.fn(),
|
||||
};
|
||||
const result = makeEventProps(props);
|
||||
|
||||
expect(result).toMatchObject({ onClick: expect.any(Function) });
|
||||
});
|
||||
|
||||
it('calls getArgs function on event invoke if given', () => {
|
||||
const props = {
|
||||
onClick: vi.fn(),
|
||||
someInvalidProp: vi.fn(),
|
||||
};
|
||||
const getArgs = vi.fn();
|
||||
const result = makeEventProps(props, getArgs);
|
||||
|
||||
// getArgs shall not be invoked before a given event is fired
|
||||
expect(getArgs).not.toHaveBeenCalled();
|
||||
|
||||
result.onClick(fakeEvent);
|
||||
|
||||
expect(getArgs).toHaveBeenCalledTimes(1);
|
||||
expect(getArgs).toHaveBeenCalledWith('onClick');
|
||||
});
|
||||
|
||||
it('properly calls callbacks given in props given no getArgs function', () => {
|
||||
const props = {
|
||||
onClick: vi.fn(),
|
||||
};
|
||||
const result = makeEventProps(props);
|
||||
|
||||
result.onClick(fakeEvent);
|
||||
|
||||
expect(props.onClick).toHaveBeenCalledWith(fakeEvent);
|
||||
});
|
||||
|
||||
it('properly calls callbacks given in props given getArgs function', () => {
|
||||
const props = {
|
||||
onClick: vi.fn(),
|
||||
};
|
||||
const getArgs = vi.fn();
|
||||
const args = {};
|
||||
getArgs.mockReturnValue(args);
|
||||
const result = makeEventProps(props, getArgs);
|
||||
|
||||
result.onClick(fakeEvent);
|
||||
|
||||
expect(props.onClick).toHaveBeenCalledWith(fakeEvent, args);
|
||||
});
|
||||
|
||||
it('should not filter out valid event props', () => {
|
||||
const props = {
|
||||
onClick: vi.fn(),
|
||||
};
|
||||
|
||||
const result = makeEventProps(props);
|
||||
|
||||
assertType<React.MouseEventHandler>(result.onClick);
|
||||
});
|
||||
|
||||
it('should filter out invalid event props', () => {
|
||||
const props = {
|
||||
someInvalidProp: vi.fn(),
|
||||
};
|
||||
|
||||
const result = makeEventProps(props);
|
||||
|
||||
expect(result).not.toHaveProperty('someInvalidProp');
|
||||
});
|
||||
|
||||
it('should allow valid onClick handler to be passed', () => {
|
||||
const props = {
|
||||
onClick: (_event: React.MouseEvent) => {
|
||||
// Intentionally empty
|
||||
},
|
||||
};
|
||||
|
||||
// @ts-expect-no-error
|
||||
makeEventProps(props);
|
||||
});
|
||||
|
||||
it('should not allow invalid onClick handler to be passed', () => {
|
||||
const props = {
|
||||
onClick: 'potato',
|
||||
};
|
||||
|
||||
// @ts-expect-error-next-line
|
||||
makeEventProps(props);
|
||||
});
|
||||
|
||||
it('should allow onClick handler with extra args to be passed if getArgs is provided', () => {
|
||||
const props = {
|
||||
onClick: (_event: React.MouseEvent, _args: string) => {
|
||||
// Intentionally empty
|
||||
},
|
||||
};
|
||||
|
||||
// @ts-expect-no-error
|
||||
makeEventProps(props, () => 'hello');
|
||||
});
|
||||
|
||||
it('should not allow onClick handler with extra args to be passed if getArgs is not provided', () => {
|
||||
const props = {
|
||||
onClick: (_event: React.MouseEvent, _args: string) => {
|
||||
// Intentionally empty
|
||||
},
|
||||
};
|
||||
|
||||
// @ts-expect-error-next-line
|
||||
makeEventProps(props);
|
||||
});
|
||||
|
||||
it('should not allow onClick handler with extra args to be passed if getArgs is provided but returns different type', () => {
|
||||
const props = {
|
||||
onClick: (_event: React.MouseEvent, _args: string) => {
|
||||
// Intentionally empty
|
||||
},
|
||||
};
|
||||
|
||||
// @ts-expect-error-next-line
|
||||
makeEventProps(props, () => 5);
|
||||
});
|
||||
|
||||
it('should allow div onClick handler to be passed to div', () => {
|
||||
const props = {
|
||||
onClick: (_event: React.MouseEvent<HTMLDivElement>) => {
|
||||
// Intentionally empty
|
||||
},
|
||||
};
|
||||
|
||||
const result = makeEventProps(props);
|
||||
|
||||
// @ts-expect-no-error
|
||||
// biome-ignore lint/a11y/useKeyWithClickEvents: This is only a test
|
||||
<div onClick={result.onClick} />;
|
||||
});
|
||||
|
||||
it('should not allow div onClick handler to be passed to button', () => {
|
||||
const props = {
|
||||
onClick: (_event: React.MouseEvent<HTMLDivElement>) => {
|
||||
// Intentionally empty
|
||||
},
|
||||
};
|
||||
|
||||
const result = makeEventProps(props);
|
||||
|
||||
// @ts-expect-error-next-line
|
||||
<button onClick={result.onClick} type="submit" />;
|
||||
});
|
||||
|
||||
it('should allow div onClick handler with extra args to be passed to div if getArgs is provided', () => {
|
||||
const props = {
|
||||
onClick: (_event: React.MouseEvent<HTMLDivElement>, _args: string) => {
|
||||
// Intentionally empty
|
||||
},
|
||||
};
|
||||
|
||||
const result = makeEventProps(props, () => 'hello');
|
||||
|
||||
// @ts-expect-no-error
|
||||
// biome-ignore lint/a11y/useKeyWithClickEvents: This is only a test
|
||||
<div onClick={result.onClick} />;
|
||||
});
|
||||
|
||||
it('should not allow div onClick handler with extra args to be passed to button if getArgs is provided', () => {
|
||||
const props = {
|
||||
onClick: (_event: React.MouseEvent<HTMLDivElement>, _args: string) => {
|
||||
// Intentionally empty
|
||||
},
|
||||
};
|
||||
|
||||
const result = makeEventProps(props, () => 'hello');
|
||||
|
||||
// @ts-expect-error-next-line
|
||||
<button onClick={result.onClick} type="submit" />;
|
||||
});
|
||||
|
||||
it('should allow onClick handler with valid extra args to be passed with args explicitly typed', () => {
|
||||
const props = {
|
||||
onClick: (_event: React.MouseEvent<HTMLDivElement>, _args: string) => {
|
||||
// Intentionally empty
|
||||
},
|
||||
};
|
||||
|
||||
// @ts-expect-no-error
|
||||
makeEventProps<string>(props, () => 'hello');
|
||||
});
|
||||
|
||||
it('should not allow onClick handler with invalid extra args to be passed with args explicitly typed', () => {
|
||||
const props = {
|
||||
onClick: (_event: React.MouseEvent<HTMLDivElement>, _args: number) => {
|
||||
// Intentionally empty
|
||||
},
|
||||
};
|
||||
|
||||
// @ts-expect-error-next-line
|
||||
makeEventProps<string>(props, () => 'hello');
|
||||
});
|
||||
|
||||
it('should allow getArgs returning valid type to be passed with args explicitly typed', () => {
|
||||
const props = {};
|
||||
|
||||
// @ts-expect-no-error
|
||||
makeEventProps<string>(props, () => 'hello');
|
||||
});
|
||||
|
||||
it('should not allow getArgs returning invalid type to be passed with args explicitly typed', () => {
|
||||
const props = {};
|
||||
|
||||
// @ts-expect-error-next-line
|
||||
makeEventProps<string>(props, () => 5);
|
||||
});
|
||||
});
|
||||
|
||||
describe('allEvents', () => {
|
||||
it('should contain all events', () => {
|
||||
const sortedAllEvents = new Set([...allEvents].sort());
|
||||
expect(sortedAllEvents).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
250
frontend/node_modules/make-event-props/src/index.ts
generated
vendored
Normal file
250
frontend/node_modules/make-event-props/src/index.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,250 @@
|
|||
// 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;
|
||||
}
|
||||
Reference in a new issue