Skip to content

Commit 7a98c2c

Browse files
wmertensshairez
andauthored
fix(select): types for multiple yes/no (#1021)
* fix(select): types for multiple yes/no * added missing changesets --------- Co-authored-by: Shai Reznik <[email protected]>
1 parent 4b4d50e commit 7a98c2c

File tree

5 files changed

+38
-41
lines changed

5 files changed

+38
-41
lines changed

.changeset/shy-bottles-agree.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@qwik-ui/styled': patch
3+
---
4+
5+
FIX: onChange not accepting regular functions

.changeset/tender-pens-run.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@qwik-ui/headless': patch
3+
---
4+
5+
FIX: types for multiple values

packages/kit-headless/src/components/select/select-inline.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { type JSXNode, Component } from '@builder.io/qwik';
1+
import { type JSXNode, type PublicProps } from '@builder.io/qwik';
22
import { HSelectImpl, type SelectProps } from './select-root';
33
import { HSelectItem as InternalSelectItem } from './select-item';
44
import { HSelectItemLabel as InternalSelectItemLabel } from './select-item-label';
@@ -14,8 +14,8 @@ type InlineCompProps = {
1414
This is an inline component. An example use case of an inline component to get the proper indexes with CSR. See issue #4757
1515
for more information.
1616
*/
17-
export const HSelectRoot: Component<SelectProps & InlineCompProps> = (
18-
props: SelectProps & InlineCompProps,
17+
export const HSelectRoot = <M extends true>(
18+
props: PublicProps<SelectProps<M> & InlineCompProps>,
1919
) => {
2020
const {
2121
children: myChildren,

packages/kit-headless/src/components/select/select-root.tsx

+21-36
Original file line numberDiff line numberDiff line change
@@ -32,44 +32,24 @@ export type InternalSelectProps = {
3232
_itemsMap: TItemsMap;
3333
};
3434

35-
export type TMultiple<M> = M extends true ? string[] : string;
36-
37-
/**
38-
* Value sets an initial value for the select. If multiple is true, value is disabled
39-
*
40-
*/
41-
type TMultiValue =
42-
| { multiple: true; value?: never }
43-
| { multiple?: false; value?: string };
44-
45-
type TStringOrArray =
46-
| {
47-
multiple?: true;
48-
onChange$?: QRL<(value: string[]) => void>;
49-
}
50-
| {
51-
multiple?: false;
52-
onChange$?: QRL<(value: string) => void>;
53-
};
54-
55-
export type SelectProps<M extends boolean = boolean> = Omit<
56-
PropsOf<'div'>,
57-
'onChange$'
58-
> & {
35+
export type SelectProps<
36+
M extends true,
37+
T = boolean extends M ? string : M extends true ? string[] : string,
38+
> = Omit<PropsOf<'div'>, 'onChange$'> & {
5939
/** A signal that controls the current selected value (controlled). */
60-
'bind:value'?: Signal<TMultiple<M>>;
40+
'bind:value'?: T extends string ? Signal<T> : never;
6141

6242
/** A signal that controls the current open state (controlled). */
6343
'bind:open'?: Signal<boolean>;
6444

6545
// eslint-disable-next-line @typescript-eslint/no-explicit-any
66-
'bind:displayValue'?: Signal<TMultiple<M>>;
46+
'bind:displayValue'?: T extends string ? Signal<T> : never;
6747

6848
/**
6949
* QRL handler that runs when a select value changes.
7050
* @param value The new value as a string.
7151
*/
72-
onChange$?: QRL<(value: TMultiple<M>) => void>;
52+
onChange$?: QRL<(value: T) => void>;
7353
/**
7454
* QRL handler that runs when the listbox opens or closes.
7555
* @param open The new state of the listbox.
@@ -107,13 +87,18 @@ export type SelectProps<M extends boolean = boolean> = Omit<
10787
*/
10888
multiple?: M;
10989

90+
/**
91+
* Value sets an initial value for the select. If multiple is true, value is disabled
92+
*
93+
*/
94+
value?: M extends false ? string : never;
95+
11096
invalid?: boolean;
111-
} & TMultiValue &
112-
TStringOrArray;
97+
};
11398

11499
/* root component in select-inline.tsx */
115-
export const HSelectImpl = component$<SelectProps<boolean> & InternalSelectProps>(
116-
(props: SelectProps<boolean> & InternalSelectProps) => {
100+
export const HSelectImpl = component$(
101+
<M extends true, T>(props: SelectProps<M, T> & InternalSelectProps) => {
117102
const {
118103
_itemsMap,
119104
_valuePropIndex: givenValuePropIndex,
@@ -259,7 +244,7 @@ export const HSelectImpl = component$<SelectProps<boolean> & InternalSelectProps
259244
}
260245

261246
if (onChange$ && selectedIndexSetSig.value.size > 0) {
262-
await onChange$(context.multiple ? values : values[0]);
247+
await onChange$(context.multiple ? (values as T) : (values[0] as T));
263248
}
264249

265250
// sync the user's given signal when an option is selected
@@ -269,9 +254,9 @@ export const HSelectImpl = component$<SelectProps<boolean> & InternalSelectProps
269254

270255
if (currUserSigValues !== newUserSigValues) {
271256
if (context.multiple) {
272-
bindValueSig.value = values;
257+
bindValueSig.value = values as T;
273258
} else {
274-
bindValueSig.value = values[0];
259+
bindValueSig.value = values[0] as T;
275260
}
276261
}
277262
}
@@ -281,8 +266,8 @@ export const HSelectImpl = component$<SelectProps<boolean> & InternalSelectProps
281266
// sync the user's given signal for the display value
282267
if (bindDisplayTextSig && context.currDisplayValueSig.value) {
283268
bindDisplayTextSig.value = context.multiple
284-
? context.currDisplayValueSig.value
285-
: context.currDisplayValueSig.value[0];
269+
? (context.currDisplayValueSig.value as T)
270+
: (context.currDisplayValueSig.value[0] as T);
286271
}
287272
});
288273

packages/kit-styled/src/components/select/select.tsx

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
import { type PropsOf, Slot, component$ } from '@builder.io/qwik';
1+
import { type PropsOf, type PublicProps, Slot, component$ } from '@builder.io/qwik';
22
import { Select as HeadlessSelect } from '@qwik-ui/headless';
33
import { cn } from '@qwik-ui/utils';
44
import { LuCheck, LuChevronDown } from '@qwikest/icons/lucide';
55

6-
const Root = (props: PropsOf<typeof HeadlessSelect.Root>) => (
6+
const Root = <M extends true>(
7+
props: PublicProps<PropsOf<typeof HeadlessSelect.Root<M>>>,
8+
) => (
79
<HeadlessSelect.Root
810
{...props}
911
selectItemComponent={Item}

0 commit comments

Comments
 (0)