Skip to content

Commit 5051fff

Browse files
authored
Ensure we handle null dataRef values correctly (#2258)
* ensure we handle `null` dataRef values correctly Initially when the `dataRef` is created, then the `current` value is going to be `null`. We didn't properly encode this in the types. Now that we do, it exposed some places where this was used incorrectly (because we assumed it was always defined). * update changelog
1 parent 3a54a91 commit 5051fff

File tree

2 files changed

+18
-13
lines changed

2 files changed

+18
-13
lines changed

packages/@headlessui-react/CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10-
- Nothing yet!
10+
### Fixed
11+
12+
- Ensure we handle `null` dataRef values correctly ([#2258](https://github.com/tailwindlabs/headlessui/pull/2258))
1113

1214
## [1.7.10] - 2023-02-06
1315

packages/@headlessui-react/src/components/combobox/combobox.tsx

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ type ComboboxOptionDataRef<T> = MutableRefObject<{
6868
}>
6969

7070
interface StateDefinition<T> {
71-
dataRef: MutableRefObject<_Data>
71+
dataRef: MutableRefObject<_Data | null>
7272
labelId: string | null
7373

7474
comboboxState: ComboboxState
@@ -139,30 +139,33 @@ let reducers: {
139139
) => StateDefinition<T>
140140
} = {
141141
[ActionTypes.CloseCombobox](state) {
142-
if (state.dataRef.current.disabled) return state
142+
if (state.dataRef.current?.disabled) return state
143143
if (state.comboboxState === ComboboxState.Closed) return state
144144
return { ...state, activeOptionIndex: null, comboboxState: ComboboxState.Closed }
145145
},
146146
[ActionTypes.OpenCombobox](state) {
147-
if (state.dataRef.current.disabled) return state
147+
if (state.dataRef.current?.disabled) return state
148148
if (state.comboboxState === ComboboxState.Open) return state
149149

150150
// Check if we have a selected value that we can make active
151151
let activeOptionIndex = state.activeOptionIndex
152-
let { isSelected } = state.dataRef.current
153-
let optionIdx = state.options.findIndex((option) => isSelected(option.dataRef.current.value))
154152

155-
if (optionIdx !== -1) {
156-
activeOptionIndex = optionIdx
153+
if (state.dataRef.current) {
154+
let { isSelected } = state.dataRef.current
155+
let optionIdx = state.options.findIndex((option) => isSelected(option.dataRef.current.value))
156+
157+
if (optionIdx !== -1) {
158+
activeOptionIndex = optionIdx
159+
}
157160
}
158161

159162
return { ...state, comboboxState: ComboboxState.Open, activeOptionIndex }
160163
},
161164
[ActionTypes.GoToOption](state, action) {
162-
if (state.dataRef.current.disabled) return state
165+
if (state.dataRef.current?.disabled) return state
163166
if (
164-
state.dataRef.current.optionsRef.current &&
165-
!state.dataRef.current.optionsPropsRef.current.static &&
167+
state.dataRef.current?.optionsRef.current &&
168+
!state.dataRef.current?.optionsPropsRef.current.static &&
166169
state.comboboxState === ComboboxState.Closed
167170
) {
168171
return state
@@ -203,7 +206,7 @@ let reducers: {
203206

204207
// Check if we need to make the newly registered option active.
205208
if (state.activeOptionIndex === null) {
206-
if (state.dataRef.current.isSelected(action.dataRef.current.value)) {
209+
if (state.dataRef.current?.isSelected(action.dataRef.current.value)) {
207210
adjustedState.activeOptionIndex = adjustedState.options.indexOf(option)
208211
}
209212
}
@@ -214,7 +217,7 @@ let reducers: {
214217
activationTrigger: ActivationTrigger.Other,
215218
}
216219

217-
if (state.dataRef.current.__demoMode && state.dataRef.current.value === undefined) {
220+
if (state.dataRef.current?.__demoMode && state.dataRef.current.value === undefined) {
218221
nextState.activeOptionIndex = 0
219222
}
220223

0 commit comments

Comments
 (0)