Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
155 changes: 155 additions & 0 deletions docs/docs/components/nativeSelect.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
# Native Select

### Quick start

Here's a quick start guide to get started with the nativeSelect component

### Importing Component

import "@hover-design/react/dist/style.css";
import { NativeSelect } from "@hover-design/react";
import { useState } from "react";

```jsx
import { NativeSelect } from "@hover-design/react";
```

### Code Snippets and Examples

##### NativeSelect Default

```jsx
const options = [
{ label: "First", value: "first" },
{ label: "Second", value: "second", disabled: true },
{ label: "Third", value: "third" },
{ label: "Fourth", value: "fourth" },
];

<div className="App">
<NativeSelect options={options} />
</div>;
```

<NativeSelect
options={[
{ label: "First", value: "first" },
{ label: "Second", value: "second", disabled: true },
{ label: "Third", value: "third" },
{ label: "Fourth", value: "fourth" },
]}
/>

##### NativeSelect Controlled

```jsx
const [value, setValue] = useState("first");

const options = [
{ label: "First", value: "first" },
{ label: "Second", value: "second" },
{ label: "Third", value: "third" },
{ label: "Fourth", value: "fourth" },
];

<div className="App">
<NativeSelect
value={value}
onChange={(event) => {
setValue(event.target.value);
}}
options={options}
/>
</div>;
```

export const App = () => {
const [value, setValue] = useState("first");
const options = [
{ label: "First", value: "first" },
{ label: "Second", value: "second" },
{ label: "Third", value: "third" },
{ label: "Fourth", value: "fourth" },
];
return (
<NativeSelect
value={value}
onChange={(event) => {
setValue(event.target.value);
}}
options={options}
/>
);
};

<App />

##### NativeSelect Error

```jsx
const options = [
{ label: "First", value: "first" },
{ label: "Second", value: "second" },
{ label: "Third", value: "third" },
{ label: "Fourth", value: "fourth" },
];

<div className="App">
<NativeSelect error="This is an error" options={options} />
</div>;
```

> Note: **error** can also be passed as a boolean.

<NativeSelect
error="This is an error"
options={[
{ label: "First", value: "first" },
{ label: "Second", value: "second" },
{ label: "Third", value: "third" },
{ label: "Fourth", value: "fourth" },
]}
/>

##### NativeSelect Rounded

```jsx
const options = [
{ label: "First", value: "first" },
{ label: "Second", value: "second" },
{ label: "Third", value: "third" },
{ label: "Fourth", value: "fourth" },
];

<div className="App">
<NativeSelect
borderRadius={"50px"}
error="This is an error"
options={options}
/>
</div>;
```

> Note: **error** can also be passed as a boolean.

<NativeSelect
borderRadius={"60px"}
options={[
{ label: "First", value: "first" },
{ label: "Second", value: "second" },
{ label: "Third", value: "third" },
{ label: "Fourth", value: "fourth" },
]}
/>

### Props Reference

| Attributes | Values | Default Value | Optional ? |
| :----------- | :------------------------------------------------------------------: | :-----------: | ---------: |
| options | ` Array of`<br/> { label:string , <br/> value:string &#124; number } | | No |
| height | `string` | `fit-content` | Yes |
| width | `string` | `fit-content` | Yes |
| borderRadius | `string` | `0` | Yes |
| error | `string` &#124; `boolean` | false | Yes |

> NativeSelect extends the props of **select tag** https://developer.mozilla.org/en-US/docs/Web/HTML/Element/select
63 changes: 63 additions & 0 deletions lib/src/components/NativeSelect/NativeSelect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { assignInlineVars } from "@vanilla-extract/dynamic";
import { FC, useEffect } from "react";
import { Flex } from "../Flex";
import { ArrowDown } from "../_internal/Icons/ArrowDown";
import {
nativeSelectContainerStyles,
nativeSelectErrorMsg,
nativeSelectIconStyle,
nativeSelectRecipe,
nativeSelectVars,
} from "./nativeSelect.css";
import { NativeSelectPropsType } from "./nativeSelect.types";

export const NativeSelect: FC<NativeSelectPropsType> = ({
height = "fit-content",
width = "fit-content",
borderRadius = "0",
options,
error = false,
className,
style = {},
multiple,
...nativeProps
}) => {
const nativeSelectClass = nativeSelectRecipe({
error: error ? true : false,
isMulti: multiple ? true : false,
});

return (
<Flex flexDirection="column">
<div
className={nativeSelectContainerStyles}
style={assignInlineVars({
[nativeSelectVars.height]: height,
[nativeSelectVars.width]: width,
[nativeSelectVars.borderRadius]: borderRadius,
})}
>
<select
style={style}
className={`${nativeSelectClass} ${className}`}
multiple={multiple}
{...nativeProps}
>
{options.map((option) => (
<option disabled={option.disabled} value={option.value}>
{option.label}
</option>
))}
</select>
{!multiple && (
<Flex className={nativeSelectIconStyle} alignItems="center">
<ArrowDown />
</Flex>
)}
</div>
{error && typeof error !== "boolean" && (
<span className={nativeSelectErrorMsg}>{error}</span>
)}
</Flex>
);
};
2 changes: 2 additions & 0 deletions lib/src/components/NativeSelect/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./NativeSelect";
export * from "./nativeSelect.css";
53 changes: 53 additions & 0 deletions lib/src/components/NativeSelect/nativeSelect.css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { createTheme, style } from "@vanilla-extract/css";
import { recipe } from "@vanilla-extract/recipes";
import { NativeSelectThemeType } from "./nativeSelect.types";

export const [nativeSelectThemeClass, nativeSelectVars]: NativeSelectThemeType =
createTheme({
height: "fit-content",
borderRadius: "0",
width: "fit-content",
});

export const nativeSelectRecipe = recipe({
base: {
appearance: "none",
height: "100%",
padding: "8px 32px 8px 16px",
width: "100%",
borderRadius: nativeSelectVars.borderRadius,
},
variants: {
error: {
true: {
border: "1px solid #DA2C2C",
color: "#DA2C2C",
},
},
isMulti: {
true: {
padding: "8px 16px",
},
},
},
});

export const nativeSelectContainerStyles = style({
height: nativeSelectVars.height,
width: nativeSelectVars.width,
position: "relative",
});

export const nativeSelectIconStyle = style({
pointerEvents: "none",
position: "absolute",
height: "100%",
top: 0,
right: "10px",
});

export const nativeSelectErrorMsg = style({
fontSize: "12px",
color: "#DA2C2C",
margin: "4px 0",
});
22 changes: 22 additions & 0 deletions lib/src/components/NativeSelect/nativeSelect.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
export type NativeSelectPropsType = JSX.IntrinsicElements["select"] & {
height?: string;
width?: string;
borderRadius?: string;
options: OptionsType[];
error?: boolean | string;
};

export type OptionsType = {
label: string;
value: string | number;
disabled?: boolean | undefined;
};

export type NativeSelectThemeType = [
string,
{
height: string;
width: string;
borderRadius: string;
}
];
1 change: 1 addition & 0 deletions lib/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ export * from "./components/Modal";
export * from "./components/Table";
export * from "./components/Dialog";
export * from "./components/Select";
export * from "./components/NativeSelect";