adobe / adobe/react-spectrum

`MergeProvider`

Open
#6,610 10 comments 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
15.9k
Forks
1.6k
Avg merge
3d 5h
Merged PRs (30d)
58

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.
```tsx
import { type Context, type ReactNode } from 'react';
import { mergeProps } from '../../utils';
import { type MergeProviderProps } from './types';

function merge(context: Context, 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);

const nextSlots =
'slots' in next && (next.slots as Record);

if (prevSlots && nextSlots) {
merged = {
...prev,
...next,
slots: {
...prevSlots,
...nextSlots,
...Object.entries(nextSlots).reduce>(
(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 {children};
};
}

export function MergeProvider({
values,
children,
}: MergeProviderProps) {
for (let [context, next] of values) {
children = (

{merge(context as Context, next, children)}

);
}

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_

Contributor guide

Open the contributing guide

Research direction

Start by locating the existing Provider, MergeProviderProps, and mergeProps utility referenced by the proposal, then read how React context values and slot props are currently handled. Done means a MergeProvider can merge supplied context values, including overlapping slot props, without losing existing provider values; the issue does not name a test file or specific implementation entry point.

Written by the indexing model from the issue text.

Assessment

Tech stack
react, typescript
Domain
frontend
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.