mirror of
https://github.com/zoriya/v10.git
synced 2026-08-10 16:09:18 +00:00
84 lines
2.2 KiB
JavaScript
84 lines
2.2 KiB
JavaScript
"use client";
|
|
//#region src/utils/merge-props.ts
|
|
/**
|
|
* Check if a key is an event handler key (on* with capital letter).
|
|
*/
|
|
function isEventHandlerKey(key) {
|
|
return key.charCodeAt(0) === 111 && key.charCodeAt(1) === 110 && key.charCodeAt(2) >= 65 && key.charCodeAt(2) <= 90;
|
|
}
|
|
/**
|
|
* Check if a key/value pair is an event handler (includes undefined values).
|
|
*/
|
|
function isEventHandler(key, value) {
|
|
return isEventHandlerKey(key) && (typeof value === "function" || typeof value === "undefined");
|
|
}
|
|
/**
|
|
* Merge two event handlers - external runs first, ours runs second.
|
|
*/
|
|
function mergeEventHandlers(ours, theirs) {
|
|
if (!theirs) return ours;
|
|
if (!ours) return theirs;
|
|
return (event) => {
|
|
theirs(event);
|
|
ours(event);
|
|
};
|
|
}
|
|
/**
|
|
* Merge two className values - concatenate strings.
|
|
*/
|
|
function mergeClassNames(ours, theirs) {
|
|
if (theirs && ours) return `${theirs} ${ours}`;
|
|
return theirs || ours;
|
|
}
|
|
/**
|
|
* Merge two style objects - theirs overwrites conflicts.
|
|
*/
|
|
function mergeStyles(ours, theirs) {
|
|
if (!theirs) return ours;
|
|
if (!ours) return theirs;
|
|
return {
|
|
...ours,
|
|
...theirs
|
|
};
|
|
}
|
|
/**
|
|
* Merge a single props object into accumulated result.
|
|
*/
|
|
function mergeOne(merged, props) {
|
|
if (!props) return merged;
|
|
for (const key in props) {
|
|
const value = props[key];
|
|
if (key === "className") merged.className = mergeClassNames(merged.className, value);
|
|
else if (key === "style") merged.style = mergeStyles(merged.style, value);
|
|
else if (isEventHandler(key, value)) merged[key] = mergeEventHandlers(merged[key], value);
|
|
else merged[key] = value;
|
|
}
|
|
return merged;
|
|
}
|
|
/**
|
|
* Merge multiple props objects.
|
|
*
|
|
* - Event handlers (on*): chained - external first, ours second
|
|
* - className: concatenated
|
|
* - style: merged objects (external wins conflicts)
|
|
* - other: last one wins
|
|
*
|
|
* @public
|
|
* @example
|
|
* ```ts
|
|
* const merged = mergeProps(
|
|
* { onClick: ourHandler, className: 'base' },
|
|
* { onClick: theirHandler, className: 'custom' }
|
|
* );
|
|
* // { onClick: chainedHandler, className: 'custom base' }
|
|
* ```
|
|
*/
|
|
function mergeProps(...propSets) {
|
|
let merged = {};
|
|
for (const props of propSets) merged = mergeOne(merged, props);
|
|
return merged;
|
|
}
|
|
//#endregion
|
|
export { mergeProps };
|
|
|
|
//# sourceMappingURL=merge-props.js.map
|