1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 | import {chain} from './chain';
|
14 | import clsx from 'clsx';
|
15 | import {mergeIds} from './useId';
|
16 |
|
17 | interface Props {
|
18 | [key: string]: any
|
19 | }
|
20 |
|
21 |
|
22 | type TupleTypes<T> = { [P in keyof T]: T[P] } extends { [key: number]: infer V } ? V : never;
|
23 |
|
24 | type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;
|
25 |
|
26 | /**
|
27 | * Merges multiple props objects together. Event handlers are chained,
|
28 | * classNames are combined, and ids are deduplicated - different ids
|
29 | * will trigger a side-effect and re-render components hooked up with `useId`.
|
30 | * For all other props, the last prop object overrides all previous ones.
|
31 | * @param args - Multiple sets of props to merge together.
|
32 | */
|
33 | export function mergeProps<T extends Props[]>(...args: T): UnionToIntersection<TupleTypes<T>> {
|
34 | // Start with a base clone of the first argument. This is a lot faster than starting
|
35 | // with an empty object and adding properties as we go.
|
36 | let result: Props = {...args[0]};
|
37 | for (let i = 1; i < args.length; i++) {
|
38 | let props = args[i];
|
39 | for (let key in props) {
|
40 | let a = result[key];
|
41 | let b = props[key];
|
42 |
|
43 | // Chain events
|
44 | if (
|
45 | typeof a === 'function' &&
|
46 | typeof b === 'function' &&
|
47 |
|
48 | key[0] === 'o' &&
|
49 | key[1] === 'n' &&
|
50 | key.charCodeAt(2) >= 65 &&
|
51 | key.charCodeAt(2) <= 90
|
52 | ) {
|
53 | result[key] = chain(a, b);
|
54 |
|
55 | // Merge classnames, sometimes classNames are empty string which eval to false, so we just need to do a type check
|
56 | } else if (
|
57 | (key === 'className' || key === 'UNSAFE_className') &&
|
58 | typeof a === 'string' &&
|
59 | typeof b === 'string'
|
60 | ) {
|
61 | result[key] = clsx(a, b);
|
62 | } else if (key === 'id' && a && b) {
|
63 | result.id = mergeIds(a, b);
|
64 | // Override others
|
65 | } else {
|
66 | result[key] = b !== undefined ? b : a;
|
67 | }
|
68 | }
|
69 | }
|
70 |
|
71 | return result as UnionToIntersection<TupleTypes<T>>;
|
72 | }
|
73 |
|
\ | No newline at end of file |