Properly merge incoming props (#1265)

* rename inconsistent `passThroughProps` and `passthroughProps` to more
concise `incomingProps`

This is going to make a bit more sense in the next commits of this
branch, hold on!

* split props into `propsWeControl` and `propsTheyControl`

This will allow us to merge the props with a bit more control. Instead
of overriding every prop from the user' props with our props, we can now
merge event listeners.

* update `render` API to accept `propsWeControl` and `propsTheyControl`

* improve the merge logic

This will essentially do the exact same thing we were doing before:
```js
let props = { ...propsTheyControl, ...propsWeControl }
```

But instead of overriding everything, we will merge the event listener
related props like `onClick`, `onKeyDown`, ...

* fix typo in tests

* simplify naming

- Rename `propsWeControl` to `ourProps`
- Rename `propsTheyControl` to `theirProps`

* update changelog
This commit is contained in:
Robin Malfait
2022-03-22 17:32:11 +01:00
committed by GitHub
parent 4f8c615245
commit 3e19aa5c97
37 changed files with 398 additions and 283 deletions
@@ -314,7 +314,7 @@ let ListboxRoot = forwardRefWithAs(function Listbox<
},
ref: Ref<TTag>
) {
let { value, name, onChange, disabled = false, horizontal = false, ...passThroughProps } = props
let { value, name, onChange, disabled = false, horizontal = false, ...theirProps } = props
const orientation = horizontal ? 'horizontal' : 'vertical'
let listboxRef = useSyncRefs(ref)
@@ -382,8 +382,11 @@ let ListboxRoot = forwardRefWithAs(function Listbox<
[listboxState, disabled]
)
let ourProps = { ref: listboxRef }
let renderConfiguration = {
props: { ref: listboxRef, ...passThroughProps },
ourProps,
theirProps,
slot,
defaultTag: DEFAULT_LISTBOX_TAG,
name: 'Listbox',
@@ -513,8 +516,8 @@ let Button = forwardRefWithAs(function Button<TTag extends ElementType = typeof
() => ({ open: state.listboxState === ListboxStates.Open, disabled: state.disabled }),
[state]
)
let passthroughProps = props
let propsWeControl = {
let theirProps = props
let ourProps = {
ref: buttonRef,
id,
type: useResolveButtonType(props, state.buttonRef),
@@ -529,7 +532,8 @@ let Button = forwardRefWithAs(function Button<TTag extends ElementType = typeof
}
return render({
props: { ...passthroughProps, ...propsWeControl },
ourProps,
theirProps,
slot,
defaultTag: DEFAULT_BUTTON_TAG,
name: 'Listbox.Button',
@@ -562,9 +566,12 @@ let Label = forwardRefWithAs(function Label<TTag extends ElementType = typeof DE
() => ({ open: state.listboxState === ListboxStates.Open, disabled: state.disabled }),
[state]
)
let propsWeControl = { ref: labelRef, id, onClick: handleClick }
let theirProps = props
let ourProps = { ref: labelRef, id, onClick: handleClick }
return render({
props: { ...props, ...propsWeControl },
ourProps,
theirProps,
slot,
defaultTag: DEFAULT_LABEL_TAG,
name: 'Listbox.Label',
@@ -702,7 +709,9 @@ let Options = forwardRefWithAs(function Options<
() => ({ open: state.listboxState === ListboxStates.Open }),
[state]
)
let propsWeControl = {
let theirProps = props
let ourProps = {
'aria-activedescendant':
state.activeOptionIndex === null ? undefined : state.options[state.activeOptionIndex]?.id,
'aria-multiselectable': state.propsRef.current.mode === ValueMode.Multi ? true : undefined,
@@ -714,10 +723,10 @@ let Options = forwardRefWithAs(function Options<
tabIndex: 0,
ref: optionsRef,
}
let passthroughProps = props
return render({
props: { ...passthroughProps, ...propsWeControl },
ourProps,
theirProps,
slot,
defaultTag: DEFAULT_OPTIONS_TAG,
features: OptionsRenderFeatures,
@@ -758,7 +767,7 @@ let Option = forwardRefWithAs(function Option<
},
ref: Ref<HTMLElement>
) {
let { disabled = false, value, ...passthroughProps } = props
let { disabled = false, value, ...theirProps } = props
let [state, dispatch] = useListboxContext('Listbox.Option')
let id = `headlessui-listbox-option-${useId()}`
let active =
@@ -839,7 +848,7 @@ let Option = forwardRefWithAs(function Option<
() => ({ active, selected, disabled }),
[active, selected, disabled]
)
let propsWeControl = {
let ourProps = {
id,
ref: optionRef,
role: 'option',
@@ -859,7 +868,8 @@ let Option = forwardRefWithAs(function Option<
}
return render({
props: { ...passthroughProps, ...propsWeControl },
ourProps,
theirProps,
slot,
defaultTag: DEFAULT_OPTION_TAG,
name: 'Listbox.Option',