Skip to content

Commit cfe03a2

Browse files
committed
feat(InputGroup): add InputGroup component
1 parent e43dc62 commit cfe03a2

File tree

6 files changed

+184
-1
lines changed

6 files changed

+184
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { Playground, Attributes } from 'lib/components';
2+
import { InputGroup, Input, Button } from 'components';
3+
4+
export const meta = {
5+
title: 'Input Group',
6+
group: 'Data Entry',
7+
};
8+
9+
# Input Group
10+
11+
The `InputGroup` component facilitates efficient form inputs integrated with action buttons.
12+
13+
<Playground
14+
title="Button right"
15+
desc="An input group with a button at the end."
16+
scope={{ InputGroup, Input, Button }}
17+
code={`
18+
<>
19+
<InputGroup buttonPosition="end">
20+
<Input placeholder="Enter text here" />
21+
<Button>Submit</Button>
22+
</InputGroup>
23+
</>
24+
`}
25+
/>
26+
27+
<Playground
28+
title="Button left"
29+
desc="Place a button at the start of the input group. "
30+
scope={{ InputGroup, Input, Button }}
31+
code={`
32+
<>
33+
<InputGroup buttonPosition="start">
34+
<Input placeholder="Search..." />
35+
<Button>Clear</Button>
36+
</InputGroup>
37+
</>
38+
`}
39+
/>
40+
41+
<Playground
42+
title="Multiple Inputs"
43+
desc="Showcases an input group with two input fields, arranged side by side."
44+
scope={{ InputGroup, Input, Button }}
45+
code={`
46+
<>
47+
<InputGroup>
48+
<Input placeholder="First Name" />
49+
<Input placeholder="Last Name" />
50+
<Button w={0.40}>Submit</Button>
51+
</InputGroup>
52+
</>
53+
`}
54+
/>
55+
56+
<Playground
57+
title="Multiple Actions"
58+
desc="Features an input group with one input field accompanied by two buttons."
59+
scope={{ InputGroup, Input, Button }}
60+
code={`
61+
<>
62+
<InputGroup buttonPosition="end">
63+
<Input placeholder="Search..." />
64+
<Button w={0.40} style={{background: "var(--color-background-800)"}}>Search</Button>
65+
<Button w={0.40} style={{background: "var(--color-background-800)"}}>Clear</Button>
66+
</InputGroup>
67+
</>
68+
`}
69+
/>
70+
71+
72+
<Attributes component="InputGroup" edit="/app/components/input-group.mdx"></Attributes>
+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
'use client';
2+
import Documentation from './input-group.mdx';
3+
4+
export default function Page() {
5+
return <Documentation />;
6+
}

src/components/index.ts

+3
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ export type { ImageBrowserProps, ImageProps } from './image';
6666
export { default as Input } from './input';
6767
export type { InputInternalProps, InputPasswordProps, InputProps, InputType } from './input';
6868

69+
export { default as InputGroup } from './input-group';
70+
export type { InputGroupProps } from './input-group';
71+
6972
export { default as PinCode } from './pin-code';
7073
export type { PinCodeProps } from './pin-code';
7174

src/components/input-group/index.ts

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import InputGroup from './input-group';
2+
3+
export type { InputGroupProps } from './input-group';
4+
export default InputGroup;
+98
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
'use client';
2+
import React from 'react';
3+
import useClasses from '../use-classes';
4+
import useScale, { withScale } from '../use-scale';
5+
import { pickChild } from 'components/utils/collections';
6+
import Button from 'components/button';
7+
import Input from 'components/input';
8+
9+
interface Props {
10+
buttonPosition?: 'start' | 'end';
11+
}
12+
13+
type NativeAttrs = Omit<React.HTMLAttributes<HTMLDivElement>, keyof Props>;
14+
export type InputGroupProps = Props & NativeAttrs;
15+
16+
const InputGroupComponent: React.FC<React.PropsWithChildren<InputGroupProps>> = ({ buttonPosition = 'end', className, children, ...props }) => {
17+
const { SCALE, UNIT, CLASS_NAMES } = useScale();
18+
const [, buttonChildren] = pickChild(children, Button);
19+
const [, inputChildren] = pickChild(children, Input);
20+
21+
const inputGroupClasses = useClasses('input-group', buttonPosition === 'start' ? 'button-start' : 'button-end', className, CLASS_NAMES);
22+
23+
return (
24+
<div className={inputGroupClasses} {...props}>
25+
<div className="input-with-button">
26+
{buttonPosition === 'start' && buttonChildren}
27+
{inputChildren}
28+
{buttonPosition === 'end' && buttonChildren}
29+
</div>
30+
<style jsx global>{`
31+
.input-group .input-with-button .input-container {
32+
height: var(--input-group-height);
33+
border: none;
34+
}
35+
36+
.input-group .input-with-button .input-container .input-wrapper.hover {
37+
box-shadow: none !important;
38+
border: none;
39+
}
40+
41+
.input-group .input-with-button .input-wrapper {
42+
border-radius: var(--input-group-border-radius);
43+
height: var(--input-group-height);
44+
border: none;
45+
}
46+
.input-group .input-with-button button {
47+
border-radius: 0;
48+
height: var(--input-group-height);
49+
border: none;
50+
}
51+
52+
.input-group .input-with-button button:first-of-type {
53+
border-top-left-radius: var(--input-group-border-radius);
54+
border-bottom-left-radius: var(--input-group-border-radius);
55+
}
56+
57+
.input-group .input-with-button button:last-of-type {
58+
border-top-right-radius: var(--input-group-border-radius);
59+
border-bottom-right-radius: var(--input-group-border-radius);
60+
}
61+
`}</style>
62+
63+
<style jsx>{`
64+
.input-group {
65+
66+
--input-group-border-color: var(--color-border-1000);
67+
68+
display: flex;
69+
align-items: center;
70+
max-width: max-content;
71+
border: 1px solid var(--input-group-border-color);
72+
border-radius: var(--input-group-border-radius);
73+
transition:
74+
border 200ms ease 0s,
75+
color 200ms ease 0s;
76+
box-shadow 200ms ease 0s;
77+
&:hover{
78+
border-color: var(--color-border-800);
79+
box-shadow none;
80+
}
81+
}
82+
83+
.input-with-button {
84+
display: flex;
85+
}
86+
87+
${SCALE.w(1, value => `width: ${value};`, 'auto', 'input-group')}
88+
${SCALE.h(2.5, value => `--input-group-height: ${value};`, undefined, 'input-group')}
89+
${SCALE.r(1, value => `--input-group-border-radius: ${value};`, 'var(--layout-radius)', 'input-group')}
90+
${UNIT('input-group')}
91+
`}</style>
92+
</div>
93+
);
94+
};
95+
96+
InputGroupComponent.displayName = 'HimalayaInputGroup';
97+
const InputGroup = withScale(InputGroupComponent);
98+
export default InputGroup;

src/lib/data/metadata.json

+1-1
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)