Skip to content

Commit b0cddc9

Browse files
authored
Merge pull request #688 from code0-tech/feat/#686
Select input and input wrapper
2 parents c5634b8 + 3cf359a commit b0cddc9

9 files changed

Lines changed: 472 additions & 478 deletions

File tree

package-lock.json

Lines changed: 139 additions & 471 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
"@vitest/browser-playwright": "^4.1.2",
6363
"@vitest/coverage-v8": "^4.1.2",
6464
"@xyflow/react": "^12.10.1",
65+
"avvvatars-react": "^0.4.2",
6566
"axe-playwright": "^2.2.2",
6667
"babel-loader": "^10.1.1",
6768
"babel-plugin-react-compiler": "^19.1.0-rc.3",
@@ -91,7 +92,7 @@
9192
"vite-plugin-dts": "^4.5.4",
9293
"vite-plugin-lib-inject-css": "^2.2.2",
9394
"vitest": "^4.1.2",
94-
"avvvatars-react": "^0.4.2"
95+
"@radix-ui/react-select": "^2.2.6"
9596
},
9697
"main": "dist/index.js",
9798
"repository": {
@@ -124,6 +125,7 @@
124125
"@uiw/codemirror-themes": "^4.25.4",
125126
"@uiw/react-codemirror": "^4.25.4",
126127
"@xyflow/react": "^12.10.0",
128+
"avvvatars-react": "^0.4.2",
127129
"cmdk": "^1.1.1",
128130
"js-md5": "^0.8.3",
129131
"merge-props": "^6.0.0",
@@ -132,7 +134,7 @@
132134
"react-resizable-panels": "^4.3.1",
133135
"react-zoom-pan-pinch": "^3.7.0",
134136
"sonner": "^2.0.7",
135-
"avvvatars-react": "^0.4.2"
137+
"@radix-ui/react-select": "^2.2.6"
136138
},
137139
"publishConfig": {
138140
"access": "public"

src/components/form/Input.stories.tsx

Lines changed: 79 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React from "react";
22
import {useForm} from "./useForm";
33
import {Card} from "../card/Card";
44
import {Button} from "../button/Button";
5-
import {IconKey, IconLogin, IconMail} from "@tabler/icons-react";
5+
import {IconChevronDown, IconKey, IconLogin, IconMail, IconVariable, IconX} from "@tabler/icons-react";
66
import {Text} from "../text/Text";
77
import {PasswordInput, passwordValidation} from "./PasswordInput";
88
import {TextInput} from "./TextInput";
@@ -14,6 +14,18 @@ import {CheckboxInput} from "./CheckboxInput";
1414
import {RadioGroup} from "./RadioGroup";
1515
import {RadioInput} from "./RadioInput";
1616
import {TextAreaInput} from "./TextAreaInput";
17+
import {
18+
SelectContent,
19+
SelectInput,
20+
SelectItem,
21+
SelectItemText,
22+
SelectPortal,
23+
SelectTrigger,
24+
SelectValue,
25+
SelectViewport
26+
} from "./SelectInput";
27+
import {Flex} from "../flex/Flex";
28+
import {ButtonGroup} from "../button-group/ButtonGroup";
1729

1830
export default {
1931
title: "Form"
@@ -164,7 +176,6 @@ export const RadioExample = () => {
164176

165177
}
166178

167-
168179
export const Checkbox = () => {
169180

170181
const [inputs, validate] = useForm({
@@ -208,7 +219,6 @@ export const Checkbox = () => {
208219

209220
}
210221

211-
212222
export const Switch = () => {
213223

214224
const [inputs, validate] = useForm({
@@ -248,7 +258,6 @@ export const Switch = () => {
248258

249259
}
250260

251-
252261
export const PinInputExample = () => {
253262

254263
const [inputs, validate] = useForm({
@@ -305,4 +314,70 @@ export const TextAreaExample = () => {
305314
leftType={"placeholder"}
306315
/>
307316
</Card>
317+
}
318+
319+
export const Select = () => {
320+
321+
const [inputs, validate] = useForm({
322+
initialValues: {
323+
select: undefined
324+
},
325+
validate: {
326+
select: (value) => {
327+
if (!value) return "Please select an option"
328+
return null
329+
}
330+
},
331+
onSubmit: (values) => {
332+
console.log(values)
333+
}
334+
})
335+
336+
return <Card color={"secondary"} w={"400px"}>
337+
<SelectInput title={"HTTP Method"}
338+
onValueChange={() => validate()}
339+
description={"You can choose between the standard http methods like GET, POST, etc."} right={
340+
<ButtonGroup color={"primary"}>
341+
<Button paddingSize={"xxs"}>
342+
<IconVariable size={13}/>
343+
</Button>
344+
<Button paddingSize={"xxs"}>
345+
<IconX size={13}/>
346+
</Button>
347+
</ButtonGroup>
348+
} rightType={"action"} {...inputs.getInputProps("select")}>
349+
<SelectTrigger asChild>
350+
<Flex justify={"space-between"} align={"center"}>
351+
<SelectValue placeholder={"Select..."}/>
352+
<IconChevronDown size={13}/>
353+
</Flex>
354+
</SelectTrigger>
355+
<SelectPortal>
356+
<SelectContent position={"item-aligned"}>
357+
<SelectViewport>
358+
<SelectItem value={"1"}>
359+
<SelectItemText>
360+
Option 1
361+
</SelectItemText>
362+
</SelectItem>
363+
<SelectItem value={"2"}>
364+
<SelectItemText>
365+
Option 2
366+
</SelectItemText>
367+
</SelectItem>
368+
<SelectItem value={"3"}>
369+
<SelectItemText>
370+
Option 3
371+
</SelectItemText>
372+
</SelectItem>
373+
<SelectItem value={"4"}>
374+
<SelectItemText>
375+
Option 4
376+
</SelectItemText>
377+
</SelectItem>
378+
</SelectViewport>
379+
</SelectContent>
380+
</SelectPortal>
381+
</SelectInput>
382+
</Card>
308383
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
@use "../../styles/helpers";
2+
@use "../../styles/variables";
3+
@use "../../styles/box";
4+
@use "sass:math";
5+
6+
.input-wrapper {
7+
8+
$padding: variables.$xs;
9+
display: flex;
10+
z-index: 1;
11+
width: 100%;
12+
align-items: center;
13+
box-sizing: border-box;
14+
gap: $padding;
15+
padding: 0 $padding / 4 0 $padding / 2;
16+
17+
& {
18+
@include box.box(variables.$tertiary, variables.$white, variables.$white);
19+
@include box.boxHover(variables.$primary, variables.$white, variables.$white);
20+
@include box.boxActive(variables.$primary, variables.$white, variables.$white);
21+
@include helpers.fontStyle();
22+
@include helpers.borderRadius();
23+
}
24+
25+
&:has(&__control:focus) {
26+
@include box.boxActiveStyle(variables.$primary, variables.$white, variables.$white);
27+
}
28+
29+
&--not-valid {
30+
@include box.box(variables.$error, variables.$white, variables.$error);
31+
}
32+
33+
&__left, &__right {
34+
display: flex;
35+
align-items: stretch;
36+
gap: $padding;
37+
margin: $padding / 4 0;
38+
39+
> button {
40+
height: 100%;
41+
padding-left: 0;
42+
padding-right: 0;
43+
}
44+
45+
&--action {
46+
padding: 0;
47+
}
48+
49+
&--placeholder {
50+
@include box.box(variables.$primary);
51+
@include helpers.fontStyle();
52+
border-radius: variables.$borderRadius - ($padding / 4);
53+
padding: $padding;
54+
box-shadow: none;
55+
}
56+
}
57+
58+
&__left {
59+
&--icon {
60+
align-items: center;
61+
}
62+
}
63+
64+
&__right {
65+
66+
&--icon {
67+
align-items: center;
68+
}
69+
}
70+
71+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import {Component, mergeComponentProps} from "../../utils";
2+
import React from "react";
3+
import {ValidationProps} from "./useForm";
4+
import {InputMessage} from "./InputMessage";
5+
import {InputLabel} from "./InputLabel";
6+
import {InputDescription} from "./InputDescription";
7+
import "./InputWrapper.style.scss"
8+
9+
export interface InputWrapperProps<T = any> extends Omit<Component<HTMLElement>, 'left' | 'right' | 'title' | "defaultValue" | "value">, ValidationProps<T> {
10+
right?: React.ReactNode
11+
left?: React.ReactNode
12+
leftType?: "action" | "placeholder" | "icon"
13+
rightType?: "action" | "placeholder" | "icon"
14+
title?: React.ReactNode
15+
description?: React.ReactNode
16+
wrapperComponent?: Component<HTMLDivElement>
17+
}
18+
19+
export const InputWrapper: React.ForwardRefExoticComponent<InputWrapperProps> = React.forwardRef((props, ref) => {
20+
21+
const {
22+
children,
23+
wrapperComponent = {},
24+
left,
25+
right,
26+
leftType = "icon",
27+
rightType = "action",
28+
title,
29+
description,
30+
formValidation = {valid: true, notValidMessage: null, setValue: null}
31+
} = props
32+
33+
return <>
34+
35+
{title && <InputLabel>{title}</InputLabel>}
36+
{description && <InputDescription>{description}</InputDescription>}
37+
38+
<div {...mergeComponentProps(`input-wrapper ${!formValidation?.valid ? "input-wrapper--not-valid" : ""}`, wrapperComponent)}>
39+
{left && <div className={`input-wrapper__left input__left--${leftType}`}>{left}</div>}
40+
{children}
41+
{right && <div className={`input-wrapper__right input-wrapper__right--${rightType}`}>{right}</div>}
42+
</div>
43+
44+
{!formValidation?.valid && formValidation?.notValidMessage && (
45+
<InputMessage>{formValidation.notValidMessage}</InputMessage>
46+
)}
47+
48+
</>
49+
})
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
@use "../../styles/helpers";
2+
@use "../../styles/box";
3+
@use "../../styles/variables";
4+
5+
6+
.select-input {
7+
&__content {
8+
padding: variables.$xxs;
9+
position: relative;
10+
box-sizing: border-box;
11+
z-index: 999;
12+
13+
& {
14+
@include helpers.borderRadius();
15+
}
16+
}
17+
18+
&__item {
19+
border-radius: variables.$borderRadius - variables.$xxs;
20+
padding: variables.$xxs variables.$xs;
21+
gap: variables.$xs;
22+
cursor: pointer;
23+
width: 100%;
24+
display: flex;
25+
align-items: center;
26+
font-size: variables.$sm;
27+
28+
& {
29+
@include box.box(variables.$primary, variables.$white, variables.$primary);
30+
@include helpers.noFocusStyle();
31+
@include helpers.fontStyle();
32+
@include helpers.disabled();
33+
box-shadow: none;
34+
}
35+
36+
&:focus, &[data-focus=true] {
37+
@include box.box(variables.$secondary, variables.$white, variables.$white);
38+
box-shadow: none;
39+
width: 100%;
40+
}
41+
}
42+
43+
&__trigger {
44+
height: stretch;
45+
width: 100%;
46+
position: relative;
47+
align-self: stretch;
48+
cursor: pointer;
49+
}
50+
}
51+
52+
@each $name, $color in variables.$colors {
53+
.select-input__content--#{$name} {
54+
@include box.box($color);
55+
border: helpers.backgroundColor(variables.$secondary) 2px solid;
56+
}
57+
}

0 commit comments

Comments
 (0)