Skip to content

Commit

Permalink
fix(select): types for multiple yes/no (#1021)
Browse files Browse the repository at this point in the history
* fix(select): types for multiple yes/no

* added missing changesets

---------

Co-authored-by: Shai Reznik <shairez@users.noreply.github.com>
  • Loading branch information
wmertens and shairez authored Dec 2, 2024
1 parent 4b4d50e commit 7a98c2c
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 41 deletions.
5 changes: 5 additions & 0 deletions .changeset/shy-bottles-agree.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@qwik-ui/styled': patch
---

FIX: onChange not accepting regular functions
5 changes: 5 additions & 0 deletions .changeset/tender-pens-run.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@qwik-ui/headless': patch
---

FIX: types for multiple values
6 changes: 3 additions & 3 deletions packages/kit-headless/src/components/select/select-inline.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type JSXNode, Component } from '@builder.io/qwik';
import { type JSXNode, type PublicProps } from '@builder.io/qwik';
import { HSelectImpl, type SelectProps } from './select-root';
import { HSelectItem as InternalSelectItem } from './select-item';
import { HSelectItemLabel as InternalSelectItemLabel } from './select-item-label';
Expand All @@ -14,8 +14,8 @@ type InlineCompProps = {
This is an inline component. An example use case of an inline component to get the proper indexes with CSR. See issue #4757
for more information.
*/
export const HSelectRoot: Component<SelectProps & InlineCompProps> = (
props: SelectProps & InlineCompProps,
export const HSelectRoot = <M extends true>(
props: PublicProps<SelectProps<M> & InlineCompProps>,
) => {
const {
children: myChildren,
Expand Down
57 changes: 21 additions & 36 deletions packages/kit-headless/src/components/select/select-root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,44 +32,24 @@ export type InternalSelectProps = {
_itemsMap: TItemsMap;
};

export type TMultiple<M> = M extends true ? string[] : string;

/**
* Value sets an initial value for the select. If multiple is true, value is disabled
*
*/
type TMultiValue =
| { multiple: true; value?: never }
| { multiple?: false; value?: string };

type TStringOrArray =
| {
multiple?: true;
onChange$?: QRL<(value: string[]) => void>;
}
| {
multiple?: false;
onChange$?: QRL<(value: string) => void>;
};

export type SelectProps<M extends boolean = boolean> = Omit<
PropsOf<'div'>,
'onChange$'
> & {
export type SelectProps<
M extends true,
T = boolean extends M ? string : M extends true ? string[] : string,
> = Omit<PropsOf<'div'>, 'onChange$'> & {
/** A signal that controls the current selected value (controlled). */
'bind:value'?: Signal<TMultiple<M>>;
'bind:value'?: T extends string ? Signal<T> : never;

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

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

/**
* QRL handler that runs when a select value changes.
* @param value The new value as a string.
*/
onChange$?: QRL<(value: TMultiple<M>) => void>;
onChange$?: QRL<(value: T) => void>;
/**
* QRL handler that runs when the listbox opens or closes.
* @param open The new state of the listbox.
Expand Down Expand Up @@ -107,13 +87,18 @@ export type SelectProps<M extends boolean = boolean> = Omit<
*/
multiple?: M;

/**
* Value sets an initial value for the select. If multiple is true, value is disabled
*
*/
value?: M extends false ? string : never;

invalid?: boolean;
} & TMultiValue &
TStringOrArray;
};

/* root component in select-inline.tsx */
export const HSelectImpl = component$<SelectProps<boolean> & InternalSelectProps>(
(props: SelectProps<boolean> & InternalSelectProps) => {
export const HSelectImpl = component$(
<M extends true, T>(props: SelectProps<M, T> & InternalSelectProps) => {
const {
_itemsMap,
_valuePropIndex: givenValuePropIndex,
Expand Down Expand Up @@ -259,7 +244,7 @@ export const HSelectImpl = component$<SelectProps<boolean> & InternalSelectProps
}

if (onChange$ && selectedIndexSetSig.value.size > 0) {
await onChange$(context.multiple ? values : values[0]);
await onChange$(context.multiple ? (values as T) : (values[0] as T));
}

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

if (currUserSigValues !== newUserSigValues) {
if (context.multiple) {
bindValueSig.value = values;
bindValueSig.value = values as T;
} else {
bindValueSig.value = values[0];
bindValueSig.value = values[0] as T;
}
}
}
Expand All @@ -281,8 +266,8 @@ export const HSelectImpl = component$<SelectProps<boolean> & InternalSelectProps
// sync the user's given signal for the display value
if (bindDisplayTextSig && context.currDisplayValueSig.value) {
bindDisplayTextSig.value = context.multiple
? context.currDisplayValueSig.value
: context.currDisplayValueSig.value[0];
? (context.currDisplayValueSig.value as T)
: (context.currDisplayValueSig.value[0] as T);
}
});

Expand Down
6 changes: 4 additions & 2 deletions packages/kit-styled/src/components/select/select.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { type PropsOf, Slot, component$ } from '@builder.io/qwik';
import { type PropsOf, type PublicProps, Slot, component$ } from '@builder.io/qwik';
import { Select as HeadlessSelect } from '@qwik-ui/headless';
import { cn } from '@qwik-ui/utils';
import { LuCheck, LuChevronDown } from '@qwikest/icons/lucide';

const Root = (props: PropsOf<typeof HeadlessSelect.Root>) => (
const Root = <M extends true>(
props: PublicProps<PropsOf<typeof HeadlessSelect.Root<M>>>,
) => (
<HeadlessSelect.Root
{...props}
selectItemComponent={Item}
Expand Down

0 comments on commit 7a98c2c

Please sign in to comment.