Skip to content

Commit 7ad4ca9

Browse files
Virtute90astagi
andcommitted
feat: add icon and button to input
Co-authored-by: Andrea Stagi <stagi.andrea@gmail.com>
1 parent 39821d9 commit 7ad4ca9

File tree

7 files changed

+2286
-2214
lines changed

7 files changed

+2286
-2214
lines changed

src/Input/Input.tsx

+27-11
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
1+
import isNumber from 'is-number';
12
import React, {
2-
InputHTMLAttributes,
33
ElementType,
4-
Ref,
4+
InputHTMLAttributes,
55
ReactNode,
6+
Ref,
67
useCallback,
7-
useState,
8+
useEffect,
89
useRef,
9-
useEffect
10+
useState
1011
} from 'react';
11-
import isNumber from 'is-number';
1212

13-
import { InputContainer } from './InputContainer';
14-
import { Icon } from '../Icon/Icon';
15-
import { getTag, getFormControlClass, getClasses, getValidationTextControlClass, useFocus } from './utils';
13+
import classNames from 'classnames';
1614
import type { CSSModule } from 'reactstrap/types/lib/utils';
15+
import { Icon } from '../Icon/Icon';
1716
import { notifyDeprecation } from '../utils';
18-
import classNames from 'classnames';
17+
import { InputContainer } from './InputContainer';
18+
import { getClasses, getFormControlClass, getTag, getValidationTextControlClass, useFocus } from './utils';
1919

2020
// taken from reactstrap types
2121
type InputType =
@@ -101,6 +101,14 @@ export interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
101101
static?: boolean;
102102
/** Quando attivo rimuove il componente contenitore dell'Input. Utile per un controllo maggiore dello styling */
103103
noWrapper?: boolean;
104+
/** Indica che il componente ha un bottone a destra rispetto all'input */
105+
hasButtonRight?: boolean;
106+
/** Componente per il bottone */
107+
buttonRight?: ReactNode;
108+
/** Indica che il componente ha una icona a sinistra rispetto all'input */
109+
hasIconLeft?: boolean;
110+
/** Componente per l'icona */
111+
iconLeft?: ReactNode;
104112
testId?: string;
105113
}
106114

@@ -128,6 +136,10 @@ export const Input = ({
128136
size,
129137
testId,
130138
noWrapper = false,
139+
hasButtonRight,
140+
buttonRight,
141+
hasIconLeft,
142+
iconLeft,
131143
...attributes
132144
}: InputProps) => {
133145
const [isHidden, setHidden] = useState(true);
@@ -249,7 +261,11 @@ export const Input = ({
249261
label,
250262
validationTextClass,
251263
validationText,
252-
wrapperClass
264+
wrapperClass,
265+
hasButtonRight,
266+
buttonRight,
267+
hasIconLeft,
268+
iconLeft
253269
};
254270

255271
if (noWrapper) {
@@ -399,4 +415,4 @@ export const Input = ({
399415
}
400416

401417
return <Tag {...rest} {...extraAttributes} className={inputClasses} {...sharedAttributes} data-testid={testId} />;
402-
};
418+
};

src/Input/InputContainer.tsx

+33
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@ export interface InputContainerProps extends HTMLAttributes<HTMLElement> {
1010
id: string | undefined;
1111
infoId: string | undefined;
1212
infoText: string | undefined;
13+
/** Indica che il componente ha un bottone a destra rispetto all'input */
14+
hasButtonRight?: boolean;
15+
/** Componente per il bottone */
16+
buttonRight?: ReactNode;
17+
/** Indica che il componente ha una icona a sinistra rispetto all'input */
18+
hasIconLeft?: boolean;
19+
/** Componente per l'icona */
20+
iconLeft?: ReactNode;
1321
testId?: string;
1422
}
1523

@@ -24,8 +32,33 @@ export const InputContainer: FC<InputContainerProps> = ({
2432
validationTextClass,
2533
validationText,
2634
wrapperClass,
35+
hasButtonRight,
36+
buttonRight,
37+
hasIconLeft,
38+
iconLeft,
2739
children
2840
}) => {
41+
42+
if (hasButtonRight || hasIconLeft) {
43+
return (
44+
<div className={wrapperClass} data-testid={testId}>
45+
<div className='input-group'>
46+
{hasIconLeft && <span className='input-group-text'>{iconLeft}</span>}
47+
<label htmlFor={id} className={activeClass + ' ' + extraLabelClass}>
48+
{label}
49+
</label>
50+
{children}
51+
{infoText && (
52+
<small id={infoId} className='form-text'>
53+
{infoText}
54+
</small>
55+
)}
56+
<div className={validationTextClass}>{validationText}</div>
57+
{hasButtonRight && <div className='input-group-append'>{buttonRight}</div>}
58+
</div>
59+
</div>
60+
);
61+
}
2962
return (
3063
<div className={wrapperClass} data-testid={testId}>
3164
<label htmlFor={id} className={activeClass + ' ' + extraLabelClass}>

stories/Components/Form/Input.stories.tsx

+30-100
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Meta, StoryObj } from "@storybook/react";
22
// @ts-ignore per il momento questo modulo non ha types
33
import Autocomplete from "accessible-autocomplete/react"; // Reference to https://www.npmjs.com/package/accessible-autocomplete
44
import React, { useState } from "react";
5-
import { FormGroup, Icon, Input, TextArea } from "../../../src";
5+
import { Button, FormGroup, Icon, Input, TextArea } from "../../../src";
66

77
const meta: Meta<typeof Input> = {
88
title: "Documentazione/Form/Input",
@@ -44,107 +44,37 @@ export const UtilizzoDiPlaceholderELabel: Story = {
4444
)
4545
};
4646

47-
const InputConIconaOBottoniHooks = () => {
48-
const [isFocused1, toggleFocus1] = useState(false);
49-
const [isFocused2, toggleFocus2] = useState(false);
50-
const [isFocused3, toggleFocus3] = useState(false);
51-
52-
const toggleFocusLabel1 = () => toggleFocus1(true);
53-
// @ts-ignore: ignore types for now
54-
const toggleBlurLabel1 = (e) => {
55-
if (e.target.value === "") {
56-
toggleFocus1(!isFocused1);
57-
}
58-
};
59-
const toggleFocusLabel2 = () => toggleFocus2(true);
60-
// @ts-ignore: ignore types for now
61-
const toggleBlurLabel2 = (e) => {
62-
if (e.target.value === "") {
63-
toggleFocus2(!isFocused2);
64-
}
65-
};
66-
const toggleFocusLabel3 = () => toggleFocus3(true);
67-
// @ts-ignore: ignore types for no}w
68-
const toggleBlurLabel3 = (e) => {
69-
if (e.target.value === "") {
70-
toggleFocus3(!isFocused3);
71-
}
72-
};
73-
return (
74-
<div>
75-
<div className="form-group">
76-
<div className="input-group">
77-
<span className="input-group-text">
78-
<Icon icon="it-pencil" aria-hidden size="sm" />
79-
</span>
80-
<label htmlFor="input-group-1" className={isFocused1 ? "active" : ""}>
81-
Con Etichetta
82-
</label>
83-
<input
84-
type="text"
85-
className={isFocused1 ? "form-control focus--mouse" : "form-control"}
86-
onFocus={toggleFocusLabel1}
87-
onBlur={toggleBlurLabel1}
88-
id="input-group-1"
89-
name="input-group-1"
90-
/>
91-
</div>
92-
</div>
93-
<div className="form-group">
94-
<div className="input-group">
95-
<span className="input-group-text">
96-
<Icon icon="it-pencil" color="danger" aria-hidden size="sm" />
97-
</span>
98-
<label htmlFor="input-group-2" className="active">
99-
Con Etichetta e placeholder
100-
</label>
101-
<input
102-
type="text"
103-
className={isFocused2 ? "form-control focus--mouse" : "form-control"}
104-
onFocus={toggleFocusLabel2}
105-
onBlur={toggleBlurLabel2}
106-
id="input-group-2"
107-
name="input-group-2"
108-
placeholder="Lorem Ipsum"
109-
/>
110-
</div>
111-
</div>
112-
<div className="form-group">
113-
<div className="input-group">
114-
<span className="input-group-text">
115-
<Icon icon="it-pencil" color="primary" aria-hidden size="sm" />
116-
</span>
117-
<label htmlFor="input-group-3" className={isFocused3 ? "active" : ""}>
118-
Con Etichetta e bottone di tipo primary
119-
</label>
120-
<input
121-
type="text"
122-
className={isFocused3 ? "form-control focus--mouse" : "form-control"}
123-
onFocus={toggleFocusLabel3}
124-
onBlur={toggleBlurLabel3}
125-
id="input-group-3"
126-
name="input-group-3"
127-
/>
128-
<div className="input-group-append">
129-
<button className="btn btn-primary" type="button" id="button-3">
130-
Invio
131-
</button>
132-
</div>
133-
</div>
134-
</div>
135-
</div>
136-
);
137-
};
138-
13947
export const InputConIconaOBottoni: Story = {
14048
render: () => {
141-
return <InputConIconaOBottoniHooks />
142-
},
143-
parameters: {
144-
docs: {
145-
canvas: { sourceState: "none" },
146-
},
147-
},
49+
return (
50+
<>
51+
<Input
52+
id='exampleInputIcon'
53+
label='Campo di tipo testuale'
54+
type='text'
55+
hasIconLeft
56+
iconLeft={<Icon icon='it-pencil' aria-hidden size='sm' />}
57+
/>
58+
<Input
59+
id='exampleInputIconDanger'
60+
label='Con etichetta e placeholder'
61+
placeholder='Lorem Ipsum'
62+
type='text'
63+
hasIconLeft
64+
iconLeft={<Icon icon='it-pencil' aria-hidden color='danger' size='sm' />}
65+
/>
66+
<Input
67+
id='exampleInputButton'
68+
label='Con etichetta e bottone di tipo primary'
69+
type='text'
70+
hasIconLeft
71+
iconLeft={<Icon icon='it-pencil' color='primary' aria-hidden size='sm' />}
72+
hasButtonRight
73+
buttonRight={<Button color='primary'>Invio</Button>}
74+
/>
75+
</>
76+
)
77+
}
14878
}
14979

15080

stories/Documentation/Form/Input.mdx

-94
Original file line numberDiff line numberDiff line change
@@ -43,100 +43,6 @@ In caso di necessità, è anche possibile utilizzare un ulteriore contenuto test
4343

4444
<Canvas of={InputStories.InputConIconaOBottoni} />
4545

46-
#### Codice
47-
48-
```tsx
49-
const [isFocused1, toggleFocus1] = useState(false);
50-
const [isFocused2, toggleFocus2] = useState(false);
51-
const [isFocused3, toggleFocus3] = useState(false);
52-
53-
const toggleFocusLabel1 = () => toggleFocus1(true);
54-
// @ts-ignore: ignore types for now
55-
const toggleBlurLabel1 = (e) => {
56-
if (e.target.value === '') {
57-
toggleFocus1(!isFocused1);
58-
}
59-
};
60-
const toggleFocusLabel2 = () => toggleFocus2(true);
61-
// @ts-ignore: ignore types for now
62-
const toggleBlurLabel2 = (e) => {
63-
if (e.target.value === '') {
64-
toggleFocus2(!isFocused2);
65-
}
66-
};
67-
const toggleFocusLabel3 = () => toggleFocus3(true);
68-
// @ts-ignore: ignore types for no}w
69-
const toggleBlurLabel3 = (e) => {
70-
if (e.target.value === '') {
71-
toggleFocus3(!isFocused3);
72-
}
73-
};
74-
return (
75-
<div>
76-
<div className='form-group'>
77-
<div className='input-group'>
78-
<span className='input-group-text'>
79-
<Icon icon='it-pencil' aria-hidden size='sm' />
80-
</span>
81-
<label htmlFor='input-group-1' className={isFocused1 ? 'active' : ''}>
82-
Con Etichetta
83-
</label>
84-
<input
85-
type='text'
86-
className={isFocused1 ? 'form-control focus--mouse' : 'form-control'}
87-
onFocus={toggleFocusLabel1}
88-
onBlur={toggleBlurLabel1}
89-
id='input-group-1'
90-
name='input-group-1'
91-
/>
92-
</div>
93-
</div>
94-
<div className='form-group'>
95-
<div className='input-group'>
96-
<span className='input-group-text'>
97-
<Icon icon='it-pencil' color='danger' aria-hidden size='sm' />
98-
</span>
99-
<label htmlFor='input-group-2' className='active'>
100-
Con Etichetta e placeholder
101-
</label>
102-
<input
103-
type='text'
104-
className={isFocused2 ? 'form-control focus--mouse' : 'form-control'}
105-
onFocus={toggleFocusLabel2}
106-
onBlur={toggleBlurLabel2}
107-
id='input-group-2'
108-
name='input-group-2'
109-
placeholder='Lorem Ipsum'
110-
/>
111-
</div>
112-
</div>
113-
<div className='form-group'>
114-
<div className='input-group'>
115-
<span className='input-group-text'>
116-
<Icon icon='it-pencil' color='primary' aria-hidden size='sm' />
117-
</span>
118-
<label htmlFor='input-group-3' className={isFocused3 ? 'active' : ''}>
119-
Con Etichetta e bottone di tipo primary
120-
</label>
121-
<input
122-
type='text'
123-
className={isFocused3 ? 'form-control focus--mouse' : 'form-control'}
124-
onFocus={toggleFocusLabel3}
125-
onBlur={toggleBlurLabel3}
126-
id='input-group-3'
127-
name='input-group-3'
128-
/>
129-
<div className='input-group-append'>
130-
<button className='btn btn-primary' type='button' id='button-3'>
131-
Invio
132-
</button>
133-
</div>
134-
</div>
135-
</div>
136-
</div>
137-
);
138-
```
139-
14046
## Input password
14147

14248
Per rendere più semplice l’inserimento della password, l’elemento è stato dotato di un visualizzatore dei caratteri digitati.

0 commit comments

Comments
 (0)