Skip to content

Commit

Permalink
feat(Select): allow passing the options array
Browse files Browse the repository at this point in the history
  • Loading branch information
zettca authored and plagoa committed Dec 9, 2024
1 parent 92927f9 commit 1a611da
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 30 deletions.
57 changes: 42 additions & 15 deletions apps/docs/src/pages/components/select.mdx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {
HvOption,
HvOptionGroup,
HvSelect,
selectClasses,
theme,
} from "@hitachivantara/uikit-react-core";

import Playground from "@docs/components/code/Playground";
Expand Down Expand Up @@ -34,14 +34,40 @@ export const getStaticProps = async ({ params }) => {
placeholder: "Select a value",
}}
>
<HvOption value="ar">Argentina</HvOption>
<HvOption value="bg">Belgium</HvOption>
<HvOption value="pt">Portugal</HvOption>
<HvOption value="pl">Poland</HvOption>
<HvOption value="sp">Spain</HvOption>
<HvOption value="us">United States</HvOption>
<HvOptionGroup label="America">
<HvOption value="ar">Argentina</HvOption>
<HvOption value="us">United States</HvOption>
</HvOptionGroup>
<HvOptionGroup label="Europe">
<HvOption value="bg">Belgium</HvOption>
<HvOption value="pt">Portugal</HvOption>
<HvOption value="pl">Poland</HvOption>
<HvOption value="sp">Spain</HvOption>
</HvOptionGroup>
</Playground>

### Options

As an alternative to the `HvOption` `children`, `HvSelect` supports passing an `options` array of options (with `value` and `label`).

Keep in mind that the `children` is more flexible, as it allows using `HvOptionGroup` and distinct `label` and rendering (`children`) values.

```jsx live
<HvSelect
label="Country"
description="Please select a country"
placeholder="Select a value"
options={[
{ value: "ar", label: "Argentina" },
{ value: "bg", label: "Belgium" },
{ value: "pt", label: "Portugal" },
{ value: "pl", label: "Poland" },
{ value: "sp", label: "Spain", disabled: true },
{ value: "us", label: "United States" },
]}
/>
```

### Form

To integrate `HvSelect` in a form, make sure you're giving it a `name`.
Expand All @@ -63,14 +89,15 @@ The value result will be the selected option's `value`, or a JSON of the selecte
description="Select your favorite countries"
placeholder="Select countries"
getSerializedValue={(values) => values.map((v) => v.value).join(",")}
>
<HvOption value="ar">Argentina</HvOption>
<HvOption value="bg">Belgium</HvOption>
<HvOption value="pt">Portugal</HvOption>
<HvOption value="pl">Poland</HvOption>
<HvOption value="sp">Spain</HvOption>
<HvOption value="us">United States</HvOption>
</HvSelect>
options={[
{ value: "ar", label: "Argentina" },
{ value: "bg", label: "Belgium" },
{ value: "pt", label: "Portugal" },
{ value: "pl", label: "Poland" },
{ value: "sp", label: "Spain" },
{ value: "us", label: "United States" },
]}
/>
<br />
<HvButton type="submit" variant="secondarySubtle">
Submit
Expand Down
17 changes: 17 additions & 0 deletions packages/core/src/Select/Select.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,21 @@ describe("Select", () => {

expect(getSelect()).toHaveTextContent("Option2, Option4");
});

it("renders correctly when passing the options prop", async () => {
render(
<HvSelect
label={name}
options={["opt1", "opt2", "opt3"].map((label) => ({
label,
value: label,
}))}
defaultValue="opt2"
/>,
);

expect(getSelect()).toHaveTextContent("opt2");
await userEvent.click(getSelect());
expect(screen.getAllByRole("option").length).toBe(3);
});
});
12 changes: 11 additions & 1 deletion packages/core/src/Select/Select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { HvPanel } from "../Panel";
import { fixedForwardRef } from "../types/generic";
import { getContainerElement } from "../utils/document";
import { setId } from "../utils/setId";
import { HvOption } from "./Option";
import { staticClasses, useClasses } from "./Select.styles";

function defaultRenderValue<Value>(
Expand All @@ -47,6 +48,14 @@ function defaultRenderValue<Value>(

const mergeIds = (...ids: ClassValue[]) => clsx(ids) || undefined;

function renderOptions(options?: HvSelectProps<any>["options"]) {
return options?.map((option) => (
<HvOption key={option.value} {...option}>
{option.label}
</HvOption>
));
}

export { staticClasses as selectClasses };

export type HvSelectClasses = ExtractNames<typeof useClasses>;
Expand Down Expand Up @@ -104,7 +113,7 @@ export const HvSelect = fixedForwardRef(function HvSelect<
ref: React.Ref<HTMLButtonElement>,
) {
const {
children,
children: childrenProp,
classes: classesProp,
className,
id: idProp,
Expand Down Expand Up @@ -215,6 +224,7 @@ export const HvSelect = fixedForwardRef(function HvSelect<
.filter((v): v is SelectOption<OptionValue> => v !== undefined)
: (getOptionMetadata(value as OptionValue) ?? null);

const children = childrenProp ?? renderOptions(optionsProp);
const isOpen = open && !!children;

return (
Expand Down
23 changes: 9 additions & 14 deletions packages/core/src/Select/stories/Form.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { HvButton, HvOption, HvSelect } from "@hitachivantara/uikit-react-core";
import { HvButton, HvSelect } from "@hitachivantara/uikit-react-core";

const options = [
{ value: "ar", label: "Argentina", flag: "πŸ‡¦πŸ‡·" },
{ value: "bg", label: "Belgium", flag: "πŸ‡§πŸ‡ͺ" },
{ value: "pt", label: "Portugal", flag: "πŸ‡΅πŸ‡Ή" },
{ value: "pl", label: "Poland", flag: "πŸ‡΅πŸ‡±" },
{ value: "sp", label: "Spain", flag: "πŸ‡ͺπŸ‡Έ" },
{ value: "us", label: "United States", flag: "πŸ‡ΊπŸ‡Έ" },
{ value: "ar", label: "Argentina" },
{ value: "bg", label: "Belgium" },
{ value: "pt", label: "Portugal" },
{ value: "pl", label: "Poland" },
{ value: "sp", label: "Spain" },
{ value: "us", label: "United States" },
];

export default () => (
Expand All @@ -25,13 +25,8 @@ export default () => (
description="Select your favorite countries"
placeholder="Select countries"
getSerializedValue={(values) => values.map((v) => v.value).join(",")}
>
{options.map(({ value, label, flag }) => (
<HvOption key={value} value={value} label={label}>
{`${flag} ${label}`}
</HvOption>
))}
</HvSelect>
options={options}
/>
<br />
<HvButton type="submit" variant="secondarySubtle">
Submit
Expand Down

0 comments on commit 1a611da

Please sign in to comment.