@zayne-labs/toolkit-react 0.9.46 → 0.9.47
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/hooks/index.d.ts +2 -199
- package/dist/esm/hooks/index.js +3 -3
- package/dist/esm/hooks-cJL0eNIo.js +575 -0
- package/dist/esm/hooks-cJL0eNIo.js.map +1 -0
- package/dist/esm/index-DeDvIi3X.d.ts +277 -0
- package/dist/esm/utils/index.d.ts +22 -9
- package/dist/esm/utils/index.js +115 -108
- package/dist/esm/utils/index.js.map +1 -1
- package/dist/esm/zustand/index.d.ts +35 -28
- package/dist/esm/zustand/index.js +48 -50
- package/dist/esm/zustand/index.js.map +1 -1
- package/package.json +6 -6
- package/dist/esm/chunk-KFK5FGDY.js +0 -495
- package/dist/esm/chunk-KFK5FGDY.js.map +0 -1
- package/dist/esm/createCustomContext-C57O-oeR.d.ts +0 -22
- package/dist/esm/hooks/index.js.map +0 -1
@@ -0,0 +1,277 @@
|
|
1
|
+
import { AnyFunction, CallbackFn, NonEmptyArray, Prettify, SelectorFn } from "@zayne-labs/toolkit-type-helpers";
|
2
|
+
import * as react5 from "react";
|
3
|
+
import * as react12 from "react";
|
4
|
+
import * as react19 from "react";
|
5
|
+
import { RefCallback, useEffect } from "react";
|
6
|
+
import * as _zayne_labs_toolkit_core7 from "@zayne-labs/toolkit-core";
|
7
|
+
import * as _zayne_labs_toolkit_core17 from "@zayne-labs/toolkit-core";
|
8
|
+
import * as _zayne_labs_toolkit_core21 from "@zayne-labs/toolkit-core";
|
9
|
+
import { AnimationIntervalOptions, LocationInfo, LocationStoreApi, LocationStoreOptions, ScrollObserverOptions, StorageOptions, StorageStoreApi, StoreApi, URLSearchParamsInit } from "@zayne-labs/toolkit-core";
|
10
|
+
|
11
|
+
//#region src/hooks/createCustomContext.d.ts
|
12
|
+
declare class ContextError extends Error {
|
13
|
+
name: string;
|
14
|
+
constructor(...args: Parameters<typeof Error>);
|
15
|
+
}
|
16
|
+
declare const getErrorMessage: (hook: string, provider: string) => string;
|
17
|
+
type CustomContextOptions<TContextValue, TStrict extends boolean> = {
|
18
|
+
defaultValue?: TContextValue | null;
|
19
|
+
errorMessage?: string;
|
20
|
+
extension?: (contextValue: NoInfer<TContextValue> | null) => TContextValue | null;
|
21
|
+
hookName?: string;
|
22
|
+
name?: string;
|
23
|
+
providerName?: string;
|
24
|
+
strict?: TStrict;
|
25
|
+
};
|
26
|
+
type UseCustomContextResult<TContextValue, TStrict extends boolean> = TStrict extends true ? TContextValue : TContextValue | null;
|
27
|
+
declare const createCustomContext: <TContextValue, TStrict extends boolean = true>(options?: CustomContextOptions<TContextValue, TStrict>) => [react5.Context<TContextValue | null>, () => UseCustomContextResult<TContextValue, TStrict>] & {
|
28
|
+
"~inferredUnion": react5.Context<TContextValue | null> | (() => UseCustomContextResult<TContextValue, TStrict>);
|
29
|
+
};
|
30
|
+
|
31
|
+
//#endregion
|
32
|
+
//#region src/hooks/effects/useAfterMountEffect.d.ts
|
33
|
+
declare const useAfterMountEffect: typeof useEffect;
|
34
|
+
|
35
|
+
//#endregion
|
36
|
+
//#region src/hooks/effects/useAsyncEffect.d.ts
|
37
|
+
declare function useAsyncEffect(effect: () => Promise<ReturnType<React.EffectCallback>>, deps?: React.DependencyList): void;
|
38
|
+
|
39
|
+
//#endregion
|
40
|
+
//#region src/hooks/effects/useEffectOnce.d.ts
|
41
|
+
declare const useEffectOnce: (callBackFn: React.EffectCallback) => void;
|
42
|
+
|
43
|
+
//#endregion
|
44
|
+
//#region src/hooks/effects/useLifeCycle.d.ts
|
45
|
+
type Destructor = ReturnType<React.EffectCallback>;
|
46
|
+
type LifeCycleOptions = {
|
47
|
+
onMount?: () => void;
|
48
|
+
onUnmount?: Destructor;
|
49
|
+
};
|
50
|
+
declare const useLifeCycle: ({
|
51
|
+
onMount,
|
52
|
+
onUnmount
|
53
|
+
}: LifeCycleOptions) => void;
|
54
|
+
|
55
|
+
//#endregion
|
56
|
+
//#region src/hooks/effects/useMountEffect.d.ts
|
57
|
+
declare const useMountEffect: (callBackFn: () => void) => void;
|
58
|
+
|
59
|
+
//#endregion
|
60
|
+
//#region src/hooks/effects/useUnMountEffect.d.ts
|
61
|
+
declare const useUnmountEffect: (cleanUpFn: Destructor) => void;
|
62
|
+
|
63
|
+
//#endregion
|
64
|
+
//#region src/hooks/useAnimateElementRefs.d.ts
|
65
|
+
type ElementsInfoArray<TTargetElement extends string> = NonEmptyArray<{
|
66
|
+
animationClass: string;
|
67
|
+
targetElement: TTargetElement;
|
68
|
+
}>;
|
69
|
+
/**
|
70
|
+
* This is a custom React hook that adds and removes animation classes to specified HTML elements.
|
71
|
+
* @param elementsInfoArray - An array of objects that contain information about the animation class and the target HTML element.
|
72
|
+
* @returns - An object containing the refs of the animated elements and a function to handle the initiation and removal animation.
|
73
|
+
*/
|
74
|
+
declare const useAnimateElementRefs: <TTargetElement extends string>(elementsInfoArray: ElementsInfoArray<TTargetElement>) => {
|
75
|
+
animatedElements: Record<TTargetElement, HTMLElement | null>;
|
76
|
+
handleElementsAnimation: () => void;
|
77
|
+
};
|
78
|
+
|
79
|
+
//#endregion
|
80
|
+
//#region src/hooks/useAnimationInterval.d.ts
|
81
|
+
type AnimationOptions = Prettify<AnimationIntervalOptions & {
|
82
|
+
intervalDuration: number | null;
|
83
|
+
onAnimation: () => void;
|
84
|
+
}>;
|
85
|
+
declare const useAnimationInterval: (options: AnimationOptions) => {
|
86
|
+
start: () => void;
|
87
|
+
stop: () => void;
|
88
|
+
};
|
89
|
+
|
90
|
+
//#endregion
|
91
|
+
//#region src/hooks/useCallbackRef.d.ts
|
92
|
+
/**
|
93
|
+
* Returns a stable function that always points to the latest version of the callback function.
|
94
|
+
* @param callbackFn - The function to reference
|
95
|
+
* @returns a stable function that always points to the latest version of the callback function
|
96
|
+
*/
|
97
|
+
declare const useCallbackRef: <TCallback = AnyFunction>(callbackFn: TCallback | undefined) => TCallback;
|
98
|
+
|
99
|
+
//#endregion
|
100
|
+
//#region src/hooks/useClickOutside.d.ts
|
101
|
+
type UseClickOutsideOptions = {
|
102
|
+
enabled?: boolean;
|
103
|
+
};
|
104
|
+
declare const useClickOutside: <TElement extends HTMLElement>(refOrRefArray: Array<React.RefObject<TElement>> | React.RefObject<TElement>, callback: (event: MouseEvent | TouchEvent) => void, options?: UseClickOutsideOptions) => void;
|
105
|
+
|
106
|
+
//#endregion
|
107
|
+
//#region src/hooks/useConstant.d.ts
|
108
|
+
declare const useConstant: <TResult>(initCallbackFn: () => TResult) => TResult;
|
109
|
+
|
110
|
+
//#endregion
|
111
|
+
//#region src/hooks/useCopyToClipboard.d.ts
|
112
|
+
declare const useCopyToClipboard: () => {
|
113
|
+
copiedValue: string;
|
114
|
+
handleCopy: (value: string) => void;
|
115
|
+
};
|
116
|
+
|
117
|
+
//#endregion
|
118
|
+
//#region src/hooks/useDebounce.d.ts
|
119
|
+
declare const useDebouncedFn: <TParams>(callBackFn: CallbackFn<TParams>, delay: number | undefined) => {
|
120
|
+
(...params: TParams[]): void;
|
121
|
+
(params: TParams | TParams[], overrideOptions: {
|
122
|
+
$delay: number;
|
123
|
+
}): void;
|
124
|
+
cancel: () => void;
|
125
|
+
cancelMaxWait(): void;
|
126
|
+
};
|
127
|
+
declare const useDebouncedState: <TValue>(defaultValue: TValue, delay: number | undefined) => readonly [TValue, {
|
128
|
+
(...params: react12.SetStateAction<TValue>[]): void;
|
129
|
+
(params: react12.SetStateAction<TValue> | react12.SetStateAction<TValue>[], overrideOptions: {
|
130
|
+
$delay: number;
|
131
|
+
}): void;
|
132
|
+
cancel: () => void;
|
133
|
+
cancelMaxWait(): void;
|
134
|
+
}, react12.Dispatch<react12.SetStateAction<TValue>>];
|
135
|
+
|
136
|
+
//#endregion
|
137
|
+
//#region src/hooks/useDisclosure.d.ts
|
138
|
+
type DisclosureOptions = {
|
139
|
+
hasScrollControl?: boolean;
|
140
|
+
initialState?: boolean | (() => boolean);
|
141
|
+
};
|
142
|
+
declare const useDisclosure: (options?: DisclosureOptions) => {
|
143
|
+
isOpen: boolean;
|
144
|
+
onClose: () => void;
|
145
|
+
onOpen: () => void;
|
146
|
+
onToggle: <TValue>(value?: TValue) => void;
|
147
|
+
};
|
148
|
+
|
149
|
+
//#endregion
|
150
|
+
//#region src/hooks/useIsServer.d.ts
|
151
|
+
/**
|
152
|
+
* @description Returns whether the component is currently being server side rendered or
|
153
|
+
* hydrated on the client. Can be used to delay browser-specific rendering
|
154
|
+
* until after hydration.
|
155
|
+
*/
|
156
|
+
declare const useIsServer: () => boolean;
|
157
|
+
|
158
|
+
//#endregion
|
159
|
+
//#region src/hooks/useLocationState.d.ts
|
160
|
+
type UseLocationResult<TSlice> = [state: TSlice, actions: LocationStoreApi];
|
161
|
+
declare const createUseLocationState: (options?: LocationStoreOptions) => Omit<_zayne_labs_toolkit_core7.StoreApi<_zayne_labs_toolkit_core7.URLInfoObject>, "setState" | "resetState"> & {
|
162
|
+
push: (url: string | _zayne_labs_toolkit_core7.PartialURLInfo, options?: {
|
163
|
+
state?: _zayne_labs_toolkit_core7.PartialURLInfo["state"];
|
164
|
+
}) => void;
|
165
|
+
replace: LocationStoreApi["push"];
|
166
|
+
triggerPopstateEvent: (nextLocationState?: LocationInfo["state"]) => void;
|
167
|
+
} & (<TSlice = _zayne_labs_toolkit_core7.URLInfoObject>(selector?: SelectorFn<LocationInfo, TSlice>) => UseLocationResult<TSlice>);
|
168
|
+
declare const useLocationState: <TSlice = LocationInfo>(selector?: SelectorFn<LocationInfo, TSlice>, options?: LocationStoreOptions) => UseLocationResult<TSlice>;
|
169
|
+
|
170
|
+
//#endregion
|
171
|
+
//#region src/hooks/useToggle.d.ts
|
172
|
+
type InitialState = boolean | (() => boolean);
|
173
|
+
declare const useToggle: (initialValue?: InitialState) => readonly [boolean, <TValue>(newValue?: TValue) => void];
|
174
|
+
|
175
|
+
//#endregion
|
176
|
+
//#region src/hooks/usePresence/types.d.ts
|
177
|
+
type UsePresenceOptions<TDuration extends number | undefined> = {
|
178
|
+
defaultValue?: boolean;
|
179
|
+
/**
|
180
|
+
* @description The duration of the animation or transition
|
181
|
+
*/
|
182
|
+
duration?: TDuration;
|
183
|
+
/**
|
184
|
+
* @description A callback function that will be called when the animation or transition ends
|
185
|
+
*/
|
186
|
+
onExitComplete?: () => void;
|
187
|
+
};
|
188
|
+
type UsePresenceResult<TElement, TDuration> = Prettify<(TDuration extends undefined ? {
|
189
|
+
elementRef: React.RefObject<TElement>;
|
190
|
+
} : unknown) & {
|
191
|
+
isPresent: boolean;
|
192
|
+
isVisible: boolean;
|
193
|
+
toggleVisibility: ReturnType<typeof useToggle>[1];
|
194
|
+
}>;
|
195
|
+
type TypeOption = {
|
196
|
+
/**
|
197
|
+
* @description The type of animation, whether animation or transition
|
198
|
+
* @default "transition"
|
199
|
+
*/
|
200
|
+
type?: "animation" | "transition";
|
201
|
+
};
|
202
|
+
type UsePresence = <TElement extends HTMLElement, TDuration extends number | undefined = undefined>(options?: Prettify<TypeOption & UsePresenceOptions<TDuration>>) => UsePresenceResult<TElement, TDuration>;
|
203
|
+
|
204
|
+
//#endregion
|
205
|
+
//#region src/hooks/usePresence/usePresence.d.ts
|
206
|
+
/**
|
207
|
+
* usePresence hook provides a way to animate an element, before removing it from the DOM.
|
208
|
+
* @param defaultValue - The default value for the presence state. Defaults to `true`.
|
209
|
+
* @param options - The options for the usePresence hook.
|
210
|
+
* @returns A object containing the boolean that should be used to conditionally render the element (isPresent), another boolean used to toggle the animation classes, and a function to toggle the state.
|
211
|
+
*/
|
212
|
+
declare const usePresence: UsePresence;
|
213
|
+
|
214
|
+
//#endregion
|
215
|
+
//#region src/hooks/useScrollObserver.d.ts
|
216
|
+
declare const useScrollObserver: <TElement extends HTMLElement>(options?: ScrollObserverOptions) => {
|
217
|
+
isScrolled: boolean;
|
218
|
+
observedElementRef: RefCallback<TElement>;
|
219
|
+
};
|
220
|
+
|
221
|
+
//#endregion
|
222
|
+
//#region src/hooks/useSearch.d.ts
|
223
|
+
declare const useSearch: <TData>(initialData: TData[], delay?: number) => {
|
224
|
+
data: TData[];
|
225
|
+
isLoading: boolean;
|
226
|
+
query: string;
|
227
|
+
setQuery: react19.Dispatch<react19.SetStateAction<string>>;
|
228
|
+
};
|
229
|
+
|
230
|
+
//#endregion
|
231
|
+
//#region src/hooks/useSearchParams.d.ts
|
232
|
+
type UseSearchParamsOptions = LocationStoreOptions & {
|
233
|
+
action?: "push" | "replace";
|
234
|
+
};
|
235
|
+
declare const useSearchParams: <TSearchParams extends URLSearchParamsInit>(options?: UseSearchParamsOptions) => readonly [URLSearchParams, {
|
236
|
+
(newQueryParams: TSearchParams | ((prev: URLSearchParams) => TSearchParams)): void;
|
237
|
+
triggerPopstateEvent: (nextLocationState?: _zayne_labs_toolkit_core17.LocationInfo["state"]) => void;
|
238
|
+
}];
|
239
|
+
declare const useSearchParamsObject: <TSearchParams extends Record<string, string>>(options?: UseSearchParamsOptions) => readonly [TSearchParams, {
|
240
|
+
(newQueryParams: TSearchParams | ((prev: TSearchParams) => TSearchParams)): void;
|
241
|
+
triggerPopstateEvent: (nextLocationState?: _zayne_labs_toolkit_core17.LocationInfo["state"]) => void;
|
242
|
+
}];
|
243
|
+
|
244
|
+
//#endregion
|
245
|
+
//#region src/hooks/useStorageState.d.ts
|
246
|
+
type UseStorageResult<TState, TSlice = TState> = [state: TSlice, actions: StorageStoreApi<TState>];
|
247
|
+
/**
|
248
|
+
* @description Creates a custom hook that returns a storage state and actions to modify it. You can use this if you need shared options.
|
249
|
+
* @note You must use this if you want to be able to prevent syncing state across tabs.
|
250
|
+
*/
|
251
|
+
declare const createUseStorageState: <TState>(baseOptions: StorageOptions<TState>) => _zayne_labs_toolkit_core21.StoreApi<TState> & {
|
252
|
+
removeState: () => void;
|
253
|
+
} & (<TSlice = TState>(selector?: SelectorFn<TState, TSlice>) => UseStorageResult<TState, TSlice>);
|
254
|
+
type UseStorageStateOptions<TValue> = Omit<StorageOptions<TValue>, "initialValue" | "key">;
|
255
|
+
declare const useStorageState: <TValue, TSlice = TValue>(key: string, initialValue?: TValue, options?: UseStorageStateOptions<TValue> & {
|
256
|
+
select?: SelectorFn<TValue, TSlice>;
|
257
|
+
}) => UseStorageResult<TValue, TSlice>;
|
258
|
+
|
259
|
+
//#endregion
|
260
|
+
//#region src/hooks/useStore.d.ts
|
261
|
+
declare const useStore: <TState, TSlice>(store: StoreApi<TState>, selector?: SelectorFn<TState, TSlice>) => TSlice;
|
262
|
+
|
263
|
+
//#endregion
|
264
|
+
//#region src/hooks/useThrottle.d.ts
|
265
|
+
declare const useThrottleBySetTimeout: <TParams>(callbackFn: CallbackFn<TParams>, delay: number) => {
|
266
|
+
(...params: TParams[]): void;
|
267
|
+
cancelTimeout(): void;
|
268
|
+
};
|
269
|
+
declare const useThrottleByTimer: <TParams>(callbackFn: CallbackFn<TParams>, delay: number) => (...params: TParams[]) => void;
|
270
|
+
declare const useThrottleByFrame: <TParams>(callbackFn: CallbackFn<TParams>) => {
|
271
|
+
(...params: TParams[]): void;
|
272
|
+
cancelAnimation(): void;
|
273
|
+
};
|
274
|
+
|
275
|
+
//#endregion
|
276
|
+
export { ContextError as ContextError$1, CustomContextOptions, createCustomContext as createCustomContext$1, createUseLocationState as createUseLocationState$1, createUseStorageState as createUseStorageState$1, getErrorMessage as getErrorMessage$1, useAfterMountEffect as useAfterMountEffect$1, useAnimateElementRefs as useAnimateElementRefs$1, useAnimationInterval as useAnimationInterval$1, useAsyncEffect as useAsyncEffect$1, useCallbackRef as useCallbackRef$1, useClickOutside as useClickOutside$1, useConstant as useConstant$1, useCopyToClipboard as useCopyToClipboard$1, useDebouncedFn as useDebouncedFn$1, useDebouncedState as useDebouncedState$1, useDisclosure as useDisclosure$1, useEffectOnce as useEffectOnce$1, useIsServer as useIsServer$1, useLifeCycle as useLifeCycle$1, useLocationState as useLocationState$1, useMountEffect as useMountEffect$1, usePresence as usePresence$1, useScrollObserver as useScrollObserver$1, useSearch as useSearch$1, useSearchParams as useSearchParams$1, useSearchParamsObject as useSearchParamsObject$1, useStorageState as useStorageState$1, useStore as useStore$1, useThrottleByFrame as useThrottleByFrame$1, useThrottleBySetTimeout as useThrottleBySetTimeout$1, useThrottleByTimer as useThrottleByTimer$1, useToggle as useToggle$1, useUnmountEffect as useUnmountEffect$1 };
|
277
|
+
//# sourceMappingURL=index-DeDvIi3X.d.ts.map
|
@@ -1,6 +1,7 @@
|
|
1
|
-
import {
|
2
|
-
import {
|
1
|
+
import { AnyFunction, AnyObject, Prettify, UnionDiscriminator } from "@zayne-labs/toolkit-type-helpers";
|
2
|
+
import { RefCallback } from "react";
|
3
3
|
|
4
|
+
//#region src/utils/composeRefs.d.ts
|
4
5
|
type PossibleRef<TRef extends HTMLElement> = React.Ref<TRef> | undefined;
|
5
6
|
/**
|
6
7
|
* @description Set a given ref to a given value.
|
@@ -14,10 +15,14 @@ declare const setRef: <TRef extends HTMLElement>(ref: PossibleRef<TRef>, node: T
|
|
14
15
|
declare const composeRefs: <TRef extends HTMLElement>(...refs: Array<PossibleRef<TRef>>) => RefCallback<TRef>;
|
15
16
|
declare const useComposeRefs: <TRef extends HTMLElement>(...refs: Array<PossibleRef<TRef>>) => () => RefCallback<TRef>;
|
16
17
|
|
18
|
+
//#endregion
|
19
|
+
//#region src/utils/composeEventHandlers.d.ts
|
17
20
|
declare const composeTwoEventHandlers: (formerHandler: AnyFunction | undefined, latterHandler: AnyFunction | undefined) => (event: unknown) => unknown;
|
18
21
|
declare const composeEventHandlers: (...eventHandlerArray: Array<AnyFunction | undefined>) => (event: unknown) => unknown;
|
19
22
|
|
20
|
-
|
23
|
+
//#endregion
|
24
|
+
//#region src/utils/mergeProps.d.ts
|
25
|
+
type UnionToIntersection<TUnion> = (TUnion extends unknown ? (param: TUnion) => void : "") extends ((param: infer TParam) => void) ? TParam : "";
|
21
26
|
/**
|
22
27
|
* Merges multiple sets of React props.
|
23
28
|
*
|
@@ -34,15 +39,19 @@ type UnionToIntersection<TUnion> = (TUnion extends unknown ? (param: TUnion) =>
|
|
34
39
|
*/
|
35
40
|
declare const mergeProps: <TProps extends Record<never, never>>(...propsObjectArray: Array<TProps | undefined>) => UnionToIntersection<TProps>;
|
36
41
|
|
42
|
+
//#endregion
|
43
|
+
//#region src/utils/mergeTwoProps.d.ts
|
37
44
|
declare const mergeTwoProps: <TProps extends Record<never, never>>(formerProps: TProps | undefined, latterProps: TProps | undefined) => TProps;
|
38
45
|
|
46
|
+
//#endregion
|
47
|
+
//#region src/utils/types/common.d.ts
|
39
48
|
type ForwardedRefType<TComponent extends HTMLElement | React.ElementType> = TComponent extends React.ElementType ? React.ForwardedRef<React.Ref<TComponent>> : React.ForwardedRef<TComponent>;
|
40
49
|
type InferProps<TComponent extends HTMLElement | React.ElementType> = TComponent extends React.ElementType ? React.ComponentPropsWithRef<TComponent> : React.HTMLAttributes<TComponent>;
|
41
50
|
type StateSetter<TSetter = unknown> = React.Dispatch<React.SetStateAction<TSetter>>;
|
42
51
|
type CssWithCustomProperties<TExtra extends Record<string, string> = NonNullable<unknown>> = React.CSSProperties & Record<`--${string}`, string> & TExtra;
|
43
52
|
type DefaultPossibleMessages = {
|
44
|
-
|
45
|
-
|
53
|
+
children: "Hey, Sorry but the children prop is redundant since you're currently using the render prop";
|
54
|
+
render: "Hey, Sorry but the render prop is redundant since you're currently using the children prop";
|
46
55
|
};
|
47
56
|
/**
|
48
57
|
* @description Represents a set of props that can be used to render a component conditionally based on a discriminated union type.
|
@@ -51,16 +60,20 @@ type DefaultPossibleMessages = {
|
|
51
60
|
* @template TErrorMessages An object of custom messages to display on the disallowed property.
|
52
61
|
*/
|
53
62
|
type DiscriminatedRenderProps<TRenderPropType, TErrorMessages extends Record<"children" | "render", string> = DefaultPossibleMessages> = UnionDiscriminator<[{
|
54
|
-
|
63
|
+
children: TRenderPropType;
|
55
64
|
}, {
|
56
|
-
|
65
|
+
render: TRenderPropType;
|
57
66
|
}], TErrorMessages>;
|
58
67
|
|
68
|
+
//#endregion
|
69
|
+
//#region src/utils/types/polymorphism.d.ts
|
59
70
|
type AsProp<TElement extends React.ElementType> = {
|
60
|
-
|
71
|
+
as?: TElement;
|
61
72
|
};
|
62
73
|
type InferRemainingProps<TElement extends React.ElementType, TProps> = Omit<InferProps<TElement>, keyof TProps>;
|
63
74
|
type MergedGivenPropsWithAs<TElement extends React.ElementType, TProps> = Prettify<Omit<AsProp<TElement>, keyof TProps> & TProps>;
|
64
75
|
type PolymorphicProps<TElement extends React.ElementType, TProps extends AnyObject = NonNullable<unknown>> = MergedGivenPropsWithAs<TElement, TProps> & InferRemainingProps<TElement, TProps>;
|
65
76
|
|
66
|
-
|
77
|
+
//#endregion
|
78
|
+
export { AsProp, CssWithCustomProperties, DiscriminatedRenderProps, ForwardedRefType, InferProps, PolymorphicProps, StateSetter, composeEventHandlers, composeRefs, composeTwoEventHandlers, mergeProps, mergeTwoProps, setRef, useComposeRefs };
|
79
|
+
//# sourceMappingURL=index.d.ts.map
|
package/dist/esm/utils/index.js
CHANGED
@@ -1,123 +1,130 @@
|
|
1
|
-
import { isFunction, isObject } from
|
2
|
-
import { useCallback } from
|
1
|
+
import { isFunction, isObject } from "@zayne-labs/toolkit-type-helpers";
|
2
|
+
import { useCallback } from "react";
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
4
|
+
//#region src/utils/composeRefs.ts
|
5
|
+
/**
|
6
|
+
* @description Set a given ref to a given value.
|
7
|
+
*
|
8
|
+
* This utility takes care of different types of refs: callback refs and RefObject(s)
|
9
|
+
*/
|
10
|
+
const setRef = (ref, node) => {
|
11
|
+
if (!ref) return;
|
12
|
+
if (isFunction(ref)) return ref(node);
|
13
|
+
ref.current = node;
|
11
14
|
};
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
15
|
+
/**
|
16
|
+
* @description A utility to combine refs. Accepts callback refs and RefObject(s)
|
17
|
+
*/
|
18
|
+
const composeRefs = (...refs) => {
|
19
|
+
const mergedRefCallBack = (node) => {
|
20
|
+
const cleanupFnArray = refs.map((ref) => setRef(ref, node));
|
21
|
+
const cleanupFn = () => cleanupFnArray.forEach((cleanup) => cleanup?.());
|
22
|
+
return cleanupFn;
|
23
|
+
};
|
24
|
+
return mergedRefCallBack;
|
19
25
|
};
|
20
|
-
|
21
|
-
|
22
|
-
|
26
|
+
const useComposeRefs = (...refs) => {
|
27
|
+
const mergedRef = useCallback(() => composeRefs(...refs), refs);
|
28
|
+
return mergedRef;
|
23
29
|
};
|
24
|
-
|
25
|
-
|
30
|
+
|
31
|
+
//#endregion
|
32
|
+
//#region src/utils/composeEventHandlers.ts
|
33
|
+
const isSyntheticEvent = (event) => {
|
34
|
+
return isObject(event) && Object.hasOwn(event, "nativeEvent");
|
26
35
|
};
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
};
|
40
|
-
return mergedEventHandler;
|
36
|
+
const composeTwoEventHandlers = (formerHandler, latterHandler) => {
|
37
|
+
const mergedEventHandler = (event) => {
|
38
|
+
if (isSyntheticEvent(event)) {
|
39
|
+
const result$1 = latterHandler?.(event);
|
40
|
+
if (!event.defaultPrevented) formerHandler?.(event);
|
41
|
+
return result$1;
|
42
|
+
}
|
43
|
+
const result = latterHandler?.(event);
|
44
|
+
formerHandler?.(event);
|
45
|
+
return result;
|
46
|
+
};
|
47
|
+
return mergedEventHandler;
|
41
48
|
};
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
};
|
55
|
-
return mergedEventHandler;
|
49
|
+
const composeEventHandlers = (...eventHandlerArray) => {
|
50
|
+
const mergedEventHandler = (event) => {
|
51
|
+
if (eventHandlerArray.length === 0) return;
|
52
|
+
if (eventHandlerArray.length === 1) return eventHandlerArray[0]?.(event);
|
53
|
+
let accumulatedHandlers;
|
54
|
+
for (const eventHandler of eventHandlerArray) {
|
55
|
+
if (!eventHandler) continue;
|
56
|
+
accumulatedHandlers = composeTwoEventHandlers(accumulatedHandlers, eventHandler);
|
57
|
+
}
|
58
|
+
return accumulatedHandlers?.(event);
|
59
|
+
};
|
60
|
+
return mergedEventHandler;
|
56
61
|
};
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
62
|
+
|
63
|
+
//#endregion
|
64
|
+
//#region src/utils/mergeTwoProps.ts
|
65
|
+
const isEventHandler = (key, value) => {
|
66
|
+
const thirdCharCode = key.codePointAt(2);
|
67
|
+
if (!isFunction(value) || thirdCharCode === void 0) return false;
|
68
|
+
const isHandler = key.startsWith("on") && thirdCharCode >= 65 && thirdCharCode <= 90;
|
69
|
+
return isHandler;
|
64
70
|
};
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
}
|
69
|
-
return formerClassName + " " + latterClassName;
|
71
|
+
const mergeTwoClassNames = (formerClassName, latterClassName) => {
|
72
|
+
if (!latterClassName || !formerClassName) return latterClassName || formerClassName;
|
73
|
+
return formerClassName + " " + latterClassName;
|
70
74
|
};
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
formerPropValue,
|
96
|
-
latterPropValue
|
97
|
-
);
|
98
|
-
continue;
|
99
|
-
}
|
100
|
-
propsAccumulator[latterPropName] = latterPropValue;
|
101
|
-
}
|
102
|
-
return propsAccumulator;
|
75
|
+
const mergeTwoProps = (formerProps, latterProps) => {
|
76
|
+
if (!latterProps || !formerProps) return latterProps ?? formerProps ?? {};
|
77
|
+
const propsAccumulator = { ...formerProps };
|
78
|
+
for (const latterPropName of Object.keys(latterProps)) {
|
79
|
+
const formerPropValue = formerProps[latterPropName];
|
80
|
+
const latterPropValue = latterProps[latterPropName];
|
81
|
+
if (latterPropName === "className" || latterPropName === "class") {
|
82
|
+
propsAccumulator[latterPropName] = mergeTwoClassNames(formerPropValue, latterPropValue);
|
83
|
+
continue;
|
84
|
+
}
|
85
|
+
if (latterPropName === "style") {
|
86
|
+
propsAccumulator[latterPropName] = {
|
87
|
+
...formerPropValue,
|
88
|
+
...latterPropValue
|
89
|
+
};
|
90
|
+
continue;
|
91
|
+
}
|
92
|
+
if (isEventHandler(latterPropName, latterPropValue)) {
|
93
|
+
propsAccumulator[latterPropName] = composeTwoEventHandlers(formerPropValue, latterPropValue);
|
94
|
+
continue;
|
95
|
+
}
|
96
|
+
propsAccumulator[latterPropName] = latterPropValue;
|
97
|
+
}
|
98
|
+
return propsAccumulator;
|
103
99
|
};
|
104
100
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
101
|
+
//#endregion
|
102
|
+
//#region src/utils/mergeProps.ts
|
103
|
+
/**
|
104
|
+
* Merges multiple sets of React props.
|
105
|
+
*
|
106
|
+
* - It follows the Object.assign pattern where the rightmost object's fields overwrite
|
107
|
+
* the conflicting ones from others. This doesn't apply to event handlers, `className` and `style` props.
|
108
|
+
* - Event handlers are merged such that they are called in sequence (the rightmost one being called first),
|
109
|
+
* and allows the user to prevent the previous event handlers from being executed by calling the `preventDefault` method.
|
110
|
+
* - It also merges the `className` and `style` props, whereby the classes are concatenated
|
111
|
+
* and the rightmost styles overwrite the previous ones.
|
112
|
+
*
|
113
|
+
* @important **`ref` is not merged.**
|
114
|
+
* @param props props to merge.
|
115
|
+
* @returns the merged props.
|
116
|
+
*/
|
117
|
+
const mergeProps = (...propsObjectArray) => {
|
118
|
+
if (propsObjectArray.length === 0) return {};
|
119
|
+
if (propsObjectArray.length === 1) return propsObjectArray[0];
|
120
|
+
let accumulatedProps = {};
|
121
|
+
for (const propsObject of propsObjectArray) {
|
122
|
+
if (!propsObject) continue;
|
123
|
+
accumulatedProps = mergeTwoProps(accumulatedProps, propsObject);
|
124
|
+
}
|
125
|
+
return accumulatedProps;
|
119
126
|
};
|
120
127
|
|
128
|
+
//#endregion
|
121
129
|
export { composeEventHandlers, composeRefs, composeTwoEventHandlers, mergeProps, mergeTwoProps, setRef, useComposeRefs };
|
122
|
-
//# sourceMappingURL=index.js.map
|
123
130
|
//# sourceMappingURL=index.js.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["../../../src/utils/composeRefs.ts","../../../src/utils/composeEventHandlers.ts","../../../src/utils/mergeTwoProps.ts","../../../src/utils/mergeProps.ts"],"names":["result","isFunction"],"mappings":"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","file":"index.js","sourcesContent":["import { isFunction } from \"@zayne-labs/toolkit-type-helpers\";\nimport { type RefCallback, useCallback } from \"react\";\n\ntype PossibleRef<TRef extends HTMLElement> = React.Ref<TRef> | undefined;\n\n/**\n * @description Set a given ref to a given value.\n *\n * This utility takes care of different types of refs: callback refs and RefObject(s)\n */\nexport const setRef = <TRef extends HTMLElement>(\n\tref: PossibleRef<TRef>,\n\tnode: TRef | null\n): ReturnType<RefCallback<TRef>> => {\n\tif (!ref) return;\n\n\tif (isFunction(ref)) {\n\t\treturn ref(node);\n\t}\n\n\t// eslint-disable-next-line no-param-reassign -- Mutation is needed here\n\tref.current = node;\n};\n\n/**\n * @description A utility to combine refs. Accepts callback refs and RefObject(s)\n */\nexport const composeRefs = <TRef extends HTMLElement>(\n\t...refs: Array<PossibleRef<TRef>>\n): RefCallback<TRef> => {\n\tconst mergedRefCallBack: RefCallback<TRef> = (node) => {\n\t\tconst cleanupFnArray = refs.map((ref) => setRef(ref, node));\n\n\t\tconst cleanupFn = () => cleanupFnArray.forEach((cleanup) => cleanup?.());\n\n\t\treturn cleanupFn;\n\t};\n\n\treturn mergedRefCallBack;\n};\n\nexport const useComposeRefs = <TRef extends HTMLElement>(...refs: Array<PossibleRef<TRef>>) => {\n\t// eslint-disable-next-line react-hooks/exhaustive-deps -- Allow\n\tconst mergedRef = useCallback(() => composeRefs(...refs), refs);\n\n\treturn mergedRef;\n};\n","import { type AnyFunction, isObject } from \"@zayne-labs/toolkit-type-helpers\";\n\nconst isSyntheticEvent = (event: unknown): event is React.SyntheticEvent => {\n\treturn isObject(event) && Object.hasOwn(event, \"nativeEvent\");\n};\n\nexport const composeTwoEventHandlers = (\n\tformerHandler: AnyFunction | undefined,\n\tlatterHandler: AnyFunction | undefined\n) => {\n\tconst mergedEventHandler = (event: unknown) => {\n\t\tif (isSyntheticEvent(event)) {\n\t\t\tconst result = latterHandler?.(event) as unknown;\n\n\t\t\tif (!event.defaultPrevented) {\n\t\t\t\tformerHandler?.(event);\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\n\t\tconst result = latterHandler?.(event) as unknown;\n\t\tformerHandler?.(event);\n\t\treturn result;\n\t};\n\n\treturn mergedEventHandler;\n};\n\nexport const composeEventHandlers = (...eventHandlerArray: Array<AnyFunction | undefined>) => {\n\tconst mergedEventHandler = (event: unknown) => {\n\t\tif (eventHandlerArray.length === 0) return;\n\n\t\tif (eventHandlerArray.length === 1) {\n\t\t\treturn eventHandlerArray[0]?.(event) as unknown;\n\t\t}\n\n\t\tlet accumulatedHandlers: AnyFunction | undefined;\n\n\t\tfor (const eventHandler of eventHandlerArray) {\n\t\t\tif (!eventHandler) continue;\n\n\t\t\taccumulatedHandlers = composeTwoEventHandlers(accumulatedHandlers, eventHandler);\n\t\t}\n\n\t\treturn accumulatedHandlers?.(event) as unknown;\n\t};\n\n\treturn mergedEventHandler;\n};\n","import { type AnyFunction, isFunction } from \"@zayne-labs/toolkit-type-helpers\";\nimport { composeTwoEventHandlers } from \"./composeEventHandlers\";\n\n// == This approach is more efficient than using a regex.\nconst isEventHandler = (key: string, value: unknown): value is AnyFunction => {\n\tconst thirdCharCode = key.codePointAt(2);\n\n\tif (!isFunction(value) || thirdCharCode === undefined) {\n\t\treturn false;\n\t}\n\n\tconst isHandler = key.startsWith(\"on\") && thirdCharCode >= 65 /* A */ && thirdCharCode <= 90; /* Z */\n\n\treturn isHandler;\n};\n\nconst mergeTwoClassNames = (formerClassName: string | undefined, latterClassName: string | undefined) => {\n\tif (!latterClassName || !formerClassName) {\n\t\t// eslint-disable-next-line ts-eslint/prefer-nullish-coalescing -- Logical OR is fit for this case\n\t\treturn latterClassName || formerClassName;\n\t}\n\n\t// eslint-disable-next-line prefer-template -- String concatenation is more performant than template literals in this case\n\treturn formerClassName + \" \" + latterClassName;\n};\n\nexport const mergeTwoProps = <TProps extends Record<never, never>>(\n\tformerProps: TProps | undefined,\n\tlatterProps: TProps | undefined\n): TProps => {\n\t// == If no props are provided, return an empty object\n\tif (!latterProps || !formerProps) {\n\t\treturn latterProps ?? formerProps ?? ({} as TProps);\n\t}\n\n\tconst propsAccumulator = { ...formerProps } as Record<string, unknown>;\n\n\tfor (const latterPropName of Object.keys(latterProps)) {\n\t\tconst formerPropValue = (formerProps as Record<string, unknown>)[latterPropName];\n\t\tconst latterPropValue = (latterProps as Record<string, unknown>)[latterPropName];\n\n\t\t// == If the prop is `className` or `class`, we merge them\n\t\tif (latterPropName === \"className\" || latterPropName === \"class\") {\n\t\t\tpropsAccumulator[latterPropName] = mergeTwoClassNames(\n\t\t\t\tformerPropValue as string,\n\t\t\t\tlatterPropValue as string\n\t\t\t);\n\t\t\tcontinue;\n\t\t}\n\n\t\t// == If the prop is `style`, we merge them\n\t\tif (latterPropName === \"style\") {\n\t\t\tpropsAccumulator[latterPropName] = {\n\t\t\t\t...(formerPropValue as object),\n\t\t\t\t...(latterPropValue as object),\n\t\t\t};\n\t\t\tcontinue;\n\t\t}\n\n\t\t// == If the handler exists on both, we compose them\n\t\tif (isEventHandler(latterPropName, latterPropValue)) {\n\t\t\tpropsAccumulator[latterPropName] = composeTwoEventHandlers(\n\t\t\t\tformerPropValue as AnyFunction | undefined,\n\t\t\t\tlatterPropValue\n\t\t\t);\n\n\t\t\tcontinue;\n\t\t}\n\n\t\t// == latterProps override by default\n\t\tpropsAccumulator[latterPropName] = latterPropValue;\n\t}\n\n\treturn propsAccumulator as TProps;\n};\n","import { mergeTwoProps } from \"./mergeTwoProps\";\n\ntype UnionToIntersection<TUnion> = (TUnion extends unknown ? (param: TUnion) => void : \"\") extends (\n\tparam: infer TParam\n) => void\n\t? TParam\n\t: \"\";\n\n/**\n * Merges multiple sets of React props.\n *\n * - It follows the Object.assign pattern where the rightmost object's fields overwrite\n * the conflicting ones from others. This doesn't apply to event handlers, `className` and `style` props.\n * - Event handlers are merged such that they are called in sequence (the rightmost one being called first),\n * and allows the user to prevent the previous event handlers from being executed by calling the `preventDefault` method.\n * - It also merges the `className` and `style` props, whereby the classes are concatenated\n * and the rightmost styles overwrite the previous ones.\n *\n * @important **`ref` is not merged.**\n * @param props props to merge.\n * @returns the merged props.\n */\n\nconst mergeProps = <TProps extends Record<never, never>>(\n\t...propsObjectArray: Array<TProps | undefined>\n): UnionToIntersection<TProps> => {\n\tif (propsObjectArray.length === 0) {\n\t\treturn {} as never;\n\t}\n\n\tif (propsObjectArray.length === 1) {\n\t\treturn propsObjectArray[0] as never;\n\t}\n\n\tlet accumulatedProps: Record<string, unknown> = {};\n\n\tfor (const propsObject of propsObjectArray) {\n\t\tif (!propsObject) continue;\n\n\t\taccumulatedProps = mergeTwoProps(accumulatedProps, propsObject);\n\t}\n\n\treturn accumulatedProps as never;\n};\n\nexport { mergeProps };\n"]}
|
1
|
+
{"version":3,"file":"index.js","names":["ref: PossibleRef<TRef>","node: TRef | null","mergedRefCallBack: RefCallback<TRef>","event: unknown","formerHandler: AnyFunction | undefined","latterHandler: AnyFunction | undefined","result","accumulatedHandlers: AnyFunction | undefined","key: string","value: unknown","formerClassName: string | undefined","latterClassName: string | undefined","formerProps: TProps | undefined","latterProps: TProps | undefined","accumulatedProps: Record<string, unknown>"],"sources":["../../../src/utils/composeRefs.ts","../../../src/utils/composeEventHandlers.ts","../../../src/utils/mergeTwoProps.ts","../../../src/utils/mergeProps.ts"],"sourcesContent":["import { isFunction } from \"@zayne-labs/toolkit-type-helpers\";\nimport { type RefCallback, useCallback } from \"react\";\n\ntype PossibleRef<TRef extends HTMLElement> = React.Ref<TRef> | undefined;\n\n/**\n * @description Set a given ref to a given value.\n *\n * This utility takes care of different types of refs: callback refs and RefObject(s)\n */\nexport const setRef = <TRef extends HTMLElement>(\n\tref: PossibleRef<TRef>,\n\tnode: TRef | null\n): ReturnType<RefCallback<TRef>> => {\n\tif (!ref) return;\n\n\tif (isFunction(ref)) {\n\t\treturn ref(node);\n\t}\n\n\t// eslint-disable-next-line no-param-reassign -- Mutation is needed here\n\tref.current = node;\n};\n\n/**\n * @description A utility to combine refs. Accepts callback refs and RefObject(s)\n */\nexport const composeRefs = <TRef extends HTMLElement>(\n\t...refs: Array<PossibleRef<TRef>>\n): RefCallback<TRef> => {\n\tconst mergedRefCallBack: RefCallback<TRef> = (node) => {\n\t\tconst cleanupFnArray = refs.map((ref) => setRef(ref, node));\n\n\t\tconst cleanupFn = () => cleanupFnArray.forEach((cleanup) => cleanup?.());\n\n\t\treturn cleanupFn;\n\t};\n\n\treturn mergedRefCallBack;\n};\n\nexport const useComposeRefs = <TRef extends HTMLElement>(...refs: Array<PossibleRef<TRef>>) => {\n\t// eslint-disable-next-line react-hooks/exhaustive-deps -- Allow\n\tconst mergedRef = useCallback(() => composeRefs(...refs), refs);\n\n\treturn mergedRef;\n};\n","import { type AnyFunction, isObject } from \"@zayne-labs/toolkit-type-helpers\";\n\nconst isSyntheticEvent = (event: unknown): event is React.SyntheticEvent => {\n\treturn isObject(event) && Object.hasOwn(event, \"nativeEvent\");\n};\n\nexport const composeTwoEventHandlers = (\n\tformerHandler: AnyFunction | undefined,\n\tlatterHandler: AnyFunction | undefined\n) => {\n\tconst mergedEventHandler = (event: unknown) => {\n\t\tif (isSyntheticEvent(event)) {\n\t\t\tconst result = latterHandler?.(event) as unknown;\n\n\t\t\tif (!event.defaultPrevented) {\n\t\t\t\tformerHandler?.(event);\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\n\t\tconst result = latterHandler?.(event) as unknown;\n\t\tformerHandler?.(event);\n\t\treturn result;\n\t};\n\n\treturn mergedEventHandler;\n};\n\nexport const composeEventHandlers = (...eventHandlerArray: Array<AnyFunction | undefined>) => {\n\tconst mergedEventHandler = (event: unknown) => {\n\t\tif (eventHandlerArray.length === 0) return;\n\n\t\tif (eventHandlerArray.length === 1) {\n\t\t\treturn eventHandlerArray[0]?.(event) as unknown;\n\t\t}\n\n\t\tlet accumulatedHandlers: AnyFunction | undefined;\n\n\t\tfor (const eventHandler of eventHandlerArray) {\n\t\t\tif (!eventHandler) continue;\n\n\t\t\taccumulatedHandlers = composeTwoEventHandlers(accumulatedHandlers, eventHandler);\n\t\t}\n\n\t\treturn accumulatedHandlers?.(event) as unknown;\n\t};\n\n\treturn mergedEventHandler;\n};\n","import { type AnyFunction, isFunction } from \"@zayne-labs/toolkit-type-helpers\";\nimport { composeTwoEventHandlers } from \"./composeEventHandlers\";\n\n// == This approach is more efficient than using a regex.\nconst isEventHandler = (key: string, value: unknown): value is AnyFunction => {\n\tconst thirdCharCode = key.codePointAt(2);\n\n\tif (!isFunction(value) || thirdCharCode === undefined) {\n\t\treturn false;\n\t}\n\n\tconst isHandler = key.startsWith(\"on\") && thirdCharCode >= 65 /* A */ && thirdCharCode <= 90; /* Z */\n\n\treturn isHandler;\n};\n\nconst mergeTwoClassNames = (formerClassName: string | undefined, latterClassName: string | undefined) => {\n\tif (!latterClassName || !formerClassName) {\n\t\t// eslint-disable-next-line ts-eslint/prefer-nullish-coalescing -- Logical OR is fit for this case\n\t\treturn latterClassName || formerClassName;\n\t}\n\n\t// eslint-disable-next-line prefer-template -- String concatenation is more performant than template literals in this case\n\treturn formerClassName + \" \" + latterClassName;\n};\n\nexport const mergeTwoProps = <TProps extends Record<never, never>>(\n\tformerProps: TProps | undefined,\n\tlatterProps: TProps | undefined\n): TProps => {\n\t// == If no props are provided, return an empty object\n\tif (!latterProps || !formerProps) {\n\t\treturn latterProps ?? formerProps ?? ({} as TProps);\n\t}\n\n\tconst propsAccumulator = { ...formerProps } as Record<string, unknown>;\n\n\tfor (const latterPropName of Object.keys(latterProps)) {\n\t\tconst formerPropValue = (formerProps as Record<string, unknown>)[latterPropName];\n\t\tconst latterPropValue = (latterProps as Record<string, unknown>)[latterPropName];\n\n\t\t// == If the prop is `className` or `class`, we merge them\n\t\tif (latterPropName === \"className\" || latterPropName === \"class\") {\n\t\t\tpropsAccumulator[latterPropName] = mergeTwoClassNames(\n\t\t\t\tformerPropValue as string,\n\t\t\t\tlatterPropValue as string\n\t\t\t);\n\t\t\tcontinue;\n\t\t}\n\n\t\t// == If the prop is `style`, we merge them\n\t\tif (latterPropName === \"style\") {\n\t\t\tpropsAccumulator[latterPropName] = {\n\t\t\t\t...(formerPropValue as object),\n\t\t\t\t...(latterPropValue as object),\n\t\t\t};\n\t\t\tcontinue;\n\t\t}\n\n\t\t// == If the handler exists on both, we compose them\n\t\tif (isEventHandler(latterPropName, latterPropValue)) {\n\t\t\tpropsAccumulator[latterPropName] = composeTwoEventHandlers(\n\t\t\t\tformerPropValue as AnyFunction | undefined,\n\t\t\t\tlatterPropValue\n\t\t\t);\n\n\t\t\tcontinue;\n\t\t}\n\n\t\t// == latterProps override by default\n\t\tpropsAccumulator[latterPropName] = latterPropValue;\n\t}\n\n\treturn propsAccumulator as TProps;\n};\n","import { mergeTwoProps } from \"./mergeTwoProps\";\n\ntype UnionToIntersection<TUnion> = (TUnion extends unknown ? (param: TUnion) => void : \"\") extends (\n\tparam: infer TParam\n) => void\n\t? TParam\n\t: \"\";\n\n/**\n * Merges multiple sets of React props.\n *\n * - It follows the Object.assign pattern where the rightmost object's fields overwrite\n * the conflicting ones from others. This doesn't apply to event handlers, `className` and `style` props.\n * - Event handlers are merged such that they are called in sequence (the rightmost one being called first),\n * and allows the user to prevent the previous event handlers from being executed by calling the `preventDefault` method.\n * - It also merges the `className` and `style` props, whereby the classes are concatenated\n * and the rightmost styles overwrite the previous ones.\n *\n * @important **`ref` is not merged.**\n * @param props props to merge.\n * @returns the merged props.\n */\n\nconst mergeProps = <TProps extends Record<never, never>>(\n\t...propsObjectArray: Array<TProps | undefined>\n): UnionToIntersection<TProps> => {\n\tif (propsObjectArray.length === 0) {\n\t\treturn {} as never;\n\t}\n\n\tif (propsObjectArray.length === 1) {\n\t\treturn propsObjectArray[0] as never;\n\t}\n\n\tlet accumulatedProps: Record<string, unknown> = {};\n\n\tfor (const propsObject of propsObjectArray) {\n\t\tif (!propsObject) continue;\n\n\t\taccumulatedProps = mergeTwoProps(accumulatedProps, propsObject);\n\t}\n\n\treturn accumulatedProps as never;\n};\n\nexport { mergeProps };\n"],"mappings":"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"}
|