Move hold prop to the Combobox Options (#1109)
* move `hold` prop to the `Combobox Options` * update changelog
This commit is contained in:
+2
-2
@@ -18,7 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
### Added
|
||||
|
||||
- Add `Combobox` component ([#1047](https://github.com/tailwindlabs/headlessui/pull/1047), [#1099](https://github.com/tailwindlabs/headlessui/pull/1099), [#1101](https://github.com/tailwindlabs/headlessui/pull/1101), [#1104](https://github.com/tailwindlabs/headlessui/pull/1104))
|
||||
- Add `Combobox` component ([#1047](https://github.com/tailwindlabs/headlessui/pull/1047), [#1099](https://github.com/tailwindlabs/headlessui/pull/1099), [#1101](https://github.com/tailwindlabs/headlessui/pull/1101), [#1104](https://github.com/tailwindlabs/headlessui/pull/1104), [#1109](https://github.com/tailwindlabs/headlessui/pull/1109))
|
||||
|
||||
## [Unreleased - @headlessui/vue]
|
||||
|
||||
@@ -32,7 +32,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
### Added
|
||||
|
||||
- Add `Combobox` component ([#1047](https://github.com/tailwindlabs/headlessui/pull/1047), [#1099](https://github.com/tailwindlabs/headlessui/pull/1099), [#1101](https://github.com/tailwindlabs/headlessui/pull/1101), [#1104](https://github.com/tailwindlabs/headlessui/pull/1104), [#1106](https://github.com/tailwindlabs/headlessui/pull/1106))
|
||||
- Add `Combobox` component ([#1047](https://github.com/tailwindlabs/headlessui/pull/1047), [#1099](https://github.com/tailwindlabs/headlessui/pull/1099), [#1101](https://github.com/tailwindlabs/headlessui/pull/1101), [#1104](https://github.com/tailwindlabs/headlessui/pull/1104), [#1106](https://github.com/tailwindlabs/headlessui/pull/1106), [#1109](https://github.com/tailwindlabs/headlessui/pull/1109))
|
||||
|
||||
## [@headlessui/react@v1.4.3] - 2022-01-14
|
||||
|
||||
|
||||
@@ -4269,10 +4269,10 @@ describe('Mouse interactions', () => {
|
||||
'should be possible to hold the last active option',
|
||||
suppressConsoleLogs(async () => {
|
||||
render(
|
||||
<Combobox value="test" onChange={console.log} hold>
|
||||
<Combobox value="test" onChange={console.log}>
|
||||
<Combobox.Input onChange={NOOP} />
|
||||
<Combobox.Button>Trigger</Combobox.Button>
|
||||
<Combobox.Options>
|
||||
<Combobox.Options hold>
|
||||
<Combobox.Option value="a">Option A</Combobox.Option>
|
||||
<Combobox.Option value="b">Option B</Combobox.Option>
|
||||
<Combobox.Option value="c">Option C</Combobox.Option>
|
||||
|
||||
@@ -53,13 +53,13 @@ interface StateDefinition {
|
||||
comboboxPropsRef: MutableRefObject<{
|
||||
value: unknown
|
||||
onChange(value: unknown): void
|
||||
hold: boolean
|
||||
}>
|
||||
inputPropsRef: MutableRefObject<{
|
||||
displayValue?(item: unknown): string
|
||||
}>
|
||||
optionsPropsRef: MutableRefObject<{
|
||||
static: boolean
|
||||
hold: boolean
|
||||
}>
|
||||
labelRef: MutableRefObject<HTMLLabelElement | null>
|
||||
inputRef: MutableRefObject<HTMLInputElement | null>
|
||||
@@ -230,22 +230,23 @@ let ComboboxRoot = forwardRefWithAs(function Combobox<
|
||||
TTag extends ElementType = typeof DEFAULT_COMBOBOX_TAG,
|
||||
TType = string
|
||||
>(
|
||||
props: Props<TTag, ComboboxRenderPropArg<TType>, 'value' | 'onChange' | 'disabled' | 'hold'> & {
|
||||
props: Props<TTag, ComboboxRenderPropArg<TType>, 'value' | 'onChange' | 'disabled'> & {
|
||||
value: TType
|
||||
onChange(value: TType): void
|
||||
disabled?: boolean
|
||||
hold?: boolean
|
||||
},
|
||||
ref: Ref<TTag>
|
||||
) {
|
||||
let { value, onChange, disabled = false, hold = false, ...passThroughProps } = props
|
||||
let { value, onChange, disabled = false, ...passThroughProps } = props
|
||||
|
||||
let comboboxPropsRef = useRef<StateDefinition['comboboxPropsRef']['current']>({
|
||||
value,
|
||||
onChange,
|
||||
hold,
|
||||
})
|
||||
let optionsPropsRef = useRef<StateDefinition['optionsPropsRef']['current']>({ static: false })
|
||||
let optionsPropsRef = useRef<StateDefinition['optionsPropsRef']['current']>({
|
||||
static: false,
|
||||
hold: false,
|
||||
})
|
||||
let inputPropsRef = useRef<StateDefinition['inputPropsRef']['current']>({
|
||||
displayValue: undefined,
|
||||
})
|
||||
@@ -272,9 +273,6 @@ let ComboboxRoot = forwardRefWithAs(function Combobox<
|
||||
useIsoMorphicEffect(() => {
|
||||
comboboxPropsRef.current.onChange = onChange
|
||||
}, [onChange, comboboxPropsRef])
|
||||
useIsoMorphicEffect(() => {
|
||||
comboboxPropsRef.current.hold = hold
|
||||
}, [hold, comboboxPropsRef])
|
||||
|
||||
useIsoMorphicEffect(() => dispatch({ type: ActionTypes.SetDisabled, disabled }), [disabled])
|
||||
|
||||
@@ -710,6 +708,7 @@ interface OptionsRenderPropArg {
|
||||
type OptionsPropsWeControl =
|
||||
| 'aria-activedescendant'
|
||||
| 'aria-labelledby'
|
||||
| 'hold'
|
||||
| 'id'
|
||||
| 'onKeyDown'
|
||||
| 'role'
|
||||
@@ -721,9 +720,12 @@ let Options = forwardRefWithAs(function Options<
|
||||
TTag extends ElementType = typeof DEFAULT_OPTIONS_TAG
|
||||
>(
|
||||
props: Props<TTag, OptionsRenderPropArg, OptionsPropsWeControl> &
|
||||
PropsForFeatures<typeof OptionsRenderFeatures>,
|
||||
PropsForFeatures<typeof OptionsRenderFeatures> & {
|
||||
hold?: boolean
|
||||
},
|
||||
ref: Ref<HTMLUListElement>
|
||||
) {
|
||||
let { hold = false, ...passthroughProps } = props
|
||||
let [state] = useComboboxContext('Combobox.Options')
|
||||
let { optionsPropsRef } = state
|
||||
|
||||
@@ -743,6 +745,9 @@ let Options = forwardRefWithAs(function Options<
|
||||
useIsoMorphicEffect(() => {
|
||||
optionsPropsRef.current.static = props.static ?? false
|
||||
}, [optionsPropsRef, props.static])
|
||||
useIsoMorphicEffect(() => {
|
||||
optionsPropsRef.current.hold = hold
|
||||
}, [hold, optionsPropsRef])
|
||||
|
||||
useTreeWalker({
|
||||
container: state.optionsRef.current,
|
||||
@@ -774,7 +779,6 @@ let Options = forwardRefWithAs(function Options<
|
||||
id,
|
||||
ref: optionsRef,
|
||||
}
|
||||
let passthroughProps = props
|
||||
|
||||
return render({
|
||||
props: { ...passthroughProps, ...propsWeControl },
|
||||
@@ -880,7 +884,7 @@ function Option<
|
||||
let handleLeave = useCallback(() => {
|
||||
if (disabled) return
|
||||
if (!active) return
|
||||
if (state.comboboxPropsRef.current.hold) return
|
||||
if (state.optionsPropsRef.current.hold) return
|
||||
dispatch({ type: ActionTypes.GoToOption, focus: Focus.Nothing })
|
||||
}, [disabled, active, dispatch, state.comboboxState, state.comboboxPropsRef])
|
||||
|
||||
|
||||
@@ -4491,10 +4491,10 @@ describe('Mouse interactions', () => {
|
||||
suppressConsoleLogs(async () => {
|
||||
renderTemplate({
|
||||
template: html`
|
||||
<Combobox v-model="value" hold>
|
||||
<Combobox v-model="value">
|
||||
<ComboboxInput />
|
||||
<ComboboxButton>Trigger</ComboboxButton>
|
||||
<ComboboxOptions>
|
||||
<ComboboxOptions hold>
|
||||
<ComboboxOption value="a">Option A</ComboboxOption>
|
||||
<ComboboxOption value="b">Option B</ComboboxOption>
|
||||
<ComboboxOption value="c">Option C</ComboboxOption>
|
||||
|
||||
@@ -37,10 +37,9 @@ type StateDefinition = {
|
||||
// State
|
||||
comboboxState: Ref<ComboboxStates>
|
||||
value: ComputedRef<unknown>
|
||||
hold: ComputedRef<Boolean>
|
||||
|
||||
inputPropsRef: Ref<{ displayValue?: (item: unknown) => string }>
|
||||
optionsPropsRef: Ref<{ static: boolean }>
|
||||
optionsPropsRef: Ref<{ static: boolean; hold: boolean }>
|
||||
|
||||
labelRef: Ref<HTMLLabelElement | null>
|
||||
inputRef: Ref<HTMLInputElement | null>
|
||||
@@ -85,7 +84,6 @@ export let Combobox = defineComponent({
|
||||
as: { type: [Object, String], default: 'template' },
|
||||
disabled: { type: [Boolean], default: false },
|
||||
modelValue: { type: [Object, String, Number, Boolean] },
|
||||
hold: { type: [Boolean], default: false },
|
||||
},
|
||||
setup(props, { slots, attrs, emit }) {
|
||||
let comboboxState = ref<StateDefinition['comboboxState']['value']>(ComboboxStates.Closed)
|
||||
@@ -97,17 +95,16 @@ export let Combobox = defineComponent({
|
||||
) as StateDefinition['optionsRef']
|
||||
let optionsPropsRef = ref<StateDefinition['optionsPropsRef']['value']>({
|
||||
static: false,
|
||||
hold: false,
|
||||
}) as StateDefinition['optionsPropsRef']
|
||||
let options = ref<StateDefinition['options']['value']>([])
|
||||
let activeOptionIndex = ref<StateDefinition['activeOptionIndex']['value']>(null)
|
||||
|
||||
let value = computed(() => props.modelValue)
|
||||
let hold = computed(() => props.hold)
|
||||
|
||||
let api = {
|
||||
comboboxState,
|
||||
value,
|
||||
hold,
|
||||
inputRef,
|
||||
labelRef,
|
||||
buttonRef,
|
||||
@@ -260,7 +257,7 @@ export let Combobox = defineComponent({
|
||||
}
|
||||
|
||||
return render({
|
||||
props: omit(props, ['modelValue', 'onUpdate:modelValue', 'disabled', 'hold']),
|
||||
props: omit(props, ['modelValue', 'onUpdate:modelValue', 'disabled']),
|
||||
slot,
|
||||
slots,
|
||||
attrs,
|
||||
@@ -545,12 +542,16 @@ export let ComboboxOptions = defineComponent({
|
||||
as: { type: [Object, String], default: 'ul' },
|
||||
static: { type: Boolean, default: false },
|
||||
unmount: { type: Boolean, default: true },
|
||||
hold: { type: [Boolean], default: false },
|
||||
},
|
||||
setup(props, { attrs, slots }) {
|
||||
let api = useComboboxContext('ComboboxOptions')
|
||||
let id = `headlessui-combobox-options-${useId()}`
|
||||
watchEffect(() => {
|
||||
api.optionsPropsRef.value.static = props.static ?? false
|
||||
api.optionsPropsRef.value.static = props.static
|
||||
})
|
||||
watchEffect(() => {
|
||||
api.optionsPropsRef.value.hold = props.hold
|
||||
})
|
||||
let usesOpenClosedState = useOpenClosed()
|
||||
let visible = computed(() => {
|
||||
@@ -586,7 +587,7 @@ export let ComboboxOptions = defineComponent({
|
||||
ref: api.optionsRef,
|
||||
role: 'listbox',
|
||||
}
|
||||
let passThroughProps = props
|
||||
let passThroughProps = omit(props, ['hold'])
|
||||
|
||||
return render({
|
||||
props: { ...passThroughProps, ...propsWeControl },
|
||||
@@ -667,7 +668,7 @@ export let ComboboxOption = defineComponent({
|
||||
function handleLeave() {
|
||||
if (props.disabled) return
|
||||
if (!active.value) return
|
||||
if (api.hold.value) return
|
||||
if (api.optionsPropsRef.value.hold) return
|
||||
api.goToOption(Focus.Nothing)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user