-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Description
Provide a general summary of the feature here
It is desirable to be able to merge slot props onto an existing slot. In order to do so, you must extract the context and merge your props into the existing slot and then provide the updated context.
🤔 Expected Behavior?
MergeProvider would consume the context of any context that it is provided and attempt to merge the new values in on top using the mergeProps util
😯 Current Behavior
Only Provider exists and it doesn't support merging, only overriding
💁 Possible Solution
I've created a rough first draft. Keep in mind that I'm using my own mergeProps that is built on top of the RAC mergeProps but replaces the behavior for merging of className and style to support render props.
import { type Context, type ReactNode } from 'react';
import { mergeProps } from '../../utils';
import { type MergeProviderProps } from './types';
function merge<T>(context: Context<T>, next: T, children: ReactNode) {
return function Consumer(prev: T) {
let merged = next;
if (
prev != null &&
next != null &&
typeof prev === 'object' &&
typeof next === 'object'
) {
const prevSlots =
'slots' in prev && (prev.slots as Record<string, object>);
const nextSlots =
'slots' in next && (next.slots as Record<string, object>);
if (prevSlots && nextSlots) {
merged = {
...prev,
...next,
slots: {
...prevSlots,
...nextSlots,
...Object.entries(nextSlots).reduce<Record<string, object>>(
(acc, [key, value]) => {
if (Object.hasOwn(prevSlots, key)) {
acc[key] = mergeProps(prevSlots[key], value);
}
return acc;
},
{}
),
},
} as T;
} else if (!prevSlots && !nextSlots) {
merged = mergeProps(prev as object, next as object) as T;
}
}
return <context.Provider value={merged}>{children}</context.Provider>;
};
}
export function MergeProvider<A, B, C, D, E, F, G, H, I, J, K>({
values,
children,
}: MergeProviderProps<A, B, C, D, E, F, G, H, I, J, K>) {
for (let [context, next] of values) {
children = (
<context.Consumer>
{merge(context as Context<typeof next>, next, children)}
</context.Consumer>
);
}
return <>{children}</>;
}🔦 Context
I'm implementing a custom component built on top of an RAC that currently implements the "remove" slot for a button. I want to maintain all of the RAC props for that slot, but I also want to add my own. If I were to just implement the Provider, then the context is overridden and I would lose (or have to completely reimplement) the RAC props. Instead, I'd like to implement MergeProvider that will automatically merge props for slots that exist in both versions of the context
💻 Examples
No response
🧢 Your Company/Team
No response
🕷 Tracking Issue
No response