Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Input: Number type input #213

Merged
merged 9 commits into from
Jan 8, 2021
1 change: 0 additions & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
{
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "all"
}
90 changes: 80 additions & 10 deletions src/lib/components/input/Input.component.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//@flow
import React from "react";
import React, { useRef } from "react";
import { DebounceInput } from "react-debounce-input";
import Checkbox from "../checkbox/Checkbox.component";
import Select from "../select/Select.component";
Expand All @@ -8,12 +8,12 @@ import {
InputContainer,
LabelStyle,
InputErrorMessage,
InputWrapper
InputWrapper,
} from "./Input.component.style";

export type Item = {
label: string,
value: string | number
value: string | number,
};

type Items = Array<Item>;
Expand All @@ -26,8 +26,10 @@ type Props = {
error?: string,
id?: string,
checked?: boolean,
onChange: () => void,
options?: Items
onChange: (e?: any) => void,
options?: Items,
min?: string,
max?: string,
};

const InputRenderer = ({
Expand All @@ -37,8 +39,48 @@ const InputRenderer = ({
checked,
onChange,
options = [],
min,
max,
...rest
}) => {
const inputEl = useRef(null);

const handleNumberClick = (e) => {
/*
** Since react is using Synthetic event we have to do the following to be
** able to programmatically dispatch the onChange event from the input
*/
const valuePropDescriptor = Object.getOwnPropertyDescriptor(
window.HTMLInputElement.prototype,
"value",
);
if (valuePropDescriptor && inputEl.current) {
const nativeInputValueSetter = valuePropDescriptor.set;
if (nativeInputValueSetter) {
if (e.target.dataset.core === "up")
nativeInputValueSetter.call(
inputEl.current,
max
? max && parseInt(value) + 1 <= parseInt(max)
? parseInt(value) + 1
: parseInt(value)
: parseInt(value) + 1,
);
else
nativeInputValueSetter.call(
inputEl.current,
min
? min && parseInt(value) - 1 >= parseInt(min)
? parseInt(value) - 1
: parseInt(value)
: parseInt(value) - 1,
);
}
const event = new Event("input", { bubbles: true });
inputEl.current.dispatchEvent(event);
}
};

const input = {
select: (
<Select
Expand All @@ -59,6 +101,33 @@ const InputRenderer = ({
/>
),
textarea: <TextArea id={id} value={value} onChange={onChange} {...rest} />,
number: (
<div className="sc-number-input-wrapper">
<input
className="sc-input-type sc-number-input"
type="number"
id={id}
value={value}
onChange={onChange}
ref={inputEl}
min={min}
max={max}
{...rest}
/>
<div className="carets-wrapper">
<i
className="fas fa-caret-up"
data-core="up"
onClick={handleNumberClick}
></i>
<i
className="fas fa-caret-down"
data-core="down"
onClick={handleNumberClick}
></i>
</div>
</div>
),
text: (
<DebounceInput
className="sc-input-type"
Expand All @@ -70,22 +139,23 @@ const InputRenderer = ({
autoComplete="off"
{...rest}
/>
)
),
};

return input[type] || input.text;
if (type) return input[type];
else return input.text;
};

const Input = ({ label, id, error, ...rest }: Props) => {
const Input = ({ label, id, error, type, ...rest }: Props) => {
return (
<InputContainer className="sc-input" error={error}>
<InputContainer className="sc-input" error={error} type={type}>
{label && (
<LabelStyle htmlFor={id} className="sc-input-label">
{label}
</LabelStyle>
)}
<InputWrapper className="sc-input-wrapper">
<InputRenderer id={id} {...rest} />
<InputRenderer id={id} type={type} {...rest} />
{error && (
<InputErrorMessage className="sc-input-error">
{error}
Expand Down
41 changes: 41 additions & 0 deletions src/lib/components/input/Input.component.style.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,47 @@ export const InputContainer = styled.div`
outline: none;
}

input[type="number"] {
/* Adding a padding to make room for the custom absolute postionned arrows */
padding-right: 20px;
-moz-appearance: textfield; /*For FireFox*/

&::-webkit-inner-spin-button {
/*For Webkits like Chrome and Safari*/
-webkit-appearance: none;
margin: 0;
}
}

${(props) => {
if (props.type === "number")
return css`
.sc-input-wrapper {
align-items: center;
position: relative;
.carets-wrapper {
display: flex;
flex-direction: column;
${(props) => {
const { textSecondary } = getTheme(props);
return css`
color: ${textSecondary};
`;
}};
position: absolute;
right: ${defaultTheme.padding.smaller};
top: 50%;
transform: translate(-50%, -50%);

i {
font-size: 0.8em;
cursor: pointer;
}
}
}
`;
}}

${(props) => {
if (props.error) {
return css`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ exports[`Storyshots Input Default 1`] = `
Input without label
</h3>
<div
className="sc-ifAKCX hULCSa sc-input"
className="sc-ifAKCX kwGiKK sc-input"
>
<div
className="sc-gzVnrw kvhoeX sc-input-wrapper"
Expand All @@ -34,7 +34,7 @@ exports[`Storyshots Input Default 1`] = `
Input with label
</h3>
<div
className="sc-ifAKCX hULCSa sc-input"
className="sc-ifAKCX kwGiKK sc-input"
>
<label
className="sc-EHOje glQODq sc-input-label"
Expand Down Expand Up @@ -63,7 +63,7 @@ exports[`Storyshots Input Default 1`] = `
Input with error
</h3>
<div
className="sc-ifAKCX exwQMG sc-input"
className="sc-ifAKCX iDfclL sc-input"
>
<label
className="sc-EHOje glQODq sc-input-label"
Expand Down Expand Up @@ -100,7 +100,7 @@ exports[`Storyshots Input Default 1`] = `
className="sc-gqjmRU czbDPR"
>
<div
className="sc-ifAKCX exwQMG sc-input"
className="sc-ifAKCX iDfclL sc-input"
>
<label
className="sc-EHOje glQODq sc-input-label"
Expand Down Expand Up @@ -135,7 +135,8 @@ exports[`Storyshots Input Default 1`] = `
Checkbox Input
</h3>
<div
className="sc-ifAKCX hULCSa sc-input"
className="sc-ifAKCX kwGiKK sc-input"
type="checkbox"
>
<label
className="sc-EHOje glQODq sc-input-label"
Expand Down Expand Up @@ -169,7 +170,8 @@ exports[`Storyshots Input Default 1`] = `
Checkbox Input with error
</h3>
<div
className="sc-ifAKCX exwQMG sc-input"
className="sc-ifAKCX iDfclL sc-input"
type="checkbox"
>
<label
className="sc-EHOje glQODq sc-input-label"
Expand Down Expand Up @@ -208,7 +210,8 @@ exports[`Storyshots Input Default 1`] = `
Select Input
</h3>
<div
className="sc-ifAKCX hULCSa sc-input"
className="sc-ifAKCX kwGiKK sc-input"
type="select"
>
<label
className="sc-EHOje glQODq sc-input-label"
Expand Down Expand Up @@ -341,7 +344,8 @@ exports[`Storyshots Input Default 1`] = `
Textarea Input
</h3>
<div
className="sc-ifAKCX hULCSa sc-input"
className="sc-ifAKCX kwGiKK sc-input"
type="textarea"
>
<label
className="sc-EHOje glQODq sc-input-label"
Expand Down Expand Up @@ -369,7 +373,8 @@ exports[`Storyshots Input Default 1`] = `
Textarea Input with error
</h3>
<div
className="sc-ifAKCX exwQMG sc-input"
className="sc-ifAKCX iDfclL sc-input"
type="textarea"
>
<label
className="sc-EHOje glQODq sc-input-label"
Expand All @@ -396,5 +401,46 @@ exports[`Storyshots Input Default 1`] = `
</span>
</div>
</div>
<h3
className="sc-dnqmqq lgiIQQ"
>
Number Input
</h3>
<div
className="sc-ifAKCX iqCCSp sc-input"
type="number"
>
<div
className="sc-gzVnrw kvhoeX sc-input-wrapper"
>
<div
className="sc-number-input-wrapper"
>
<input
className="sc-input-type sc-number-input"
id="id8"
max="100"
min="0"
onChange={[Function]}
type="number"
value={1}
/>
<div
className="carets-wrapper"
>
<i
className="fas fa-caret-up"
data-core="up"
onClick={[Function]}
/>
<i
className="fas fa-caret-down"
data-core="down"
onClick={[Function]}
/>
</div>
</div>
</div>
</div>
</div>
`;
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ exports[`Storyshots SearchInput Default 1`] = `
className="sc-htoDjs gpFhwS sc-searchinput"
>
<div
className="sc-ifAKCX hULCSa sc-input"
className="sc-ifAKCX kwGiKK sc-input"
type="text"
>
<div
className="sc-gzVnrw kvhoeX sc-input-wrapper"
Expand Down Expand Up @@ -74,7 +75,8 @@ exports[`Storyshots SearchInput Default 1`] = `
data-cy="carlito_searchinput"
>
<div
className="sc-ifAKCX hULCSa sc-input"
className="sc-ifAKCX kwGiKK sc-input"
type="text"
>
<div
className="sc-gzVnrw kvhoeX sc-input-wrapper"
Expand Down Expand Up @@ -126,7 +128,8 @@ exports[`Storyshots SearchInput Default 1`] = `
className="sc-htoDjs cAmcWy sc-searchinput"
>
<div
className="sc-ifAKCX hULCSa sc-input"
className="sc-ifAKCX kwGiKK sc-input"
type="text"
>
<div
className="sc-gzVnrw kvhoeX sc-input-wrapper"
Expand Down Expand Up @@ -179,7 +182,8 @@ exports[`Storyshots SearchInput Default 1`] = `
className="sc-htoDjs cAmcWy sc-searchinput"
>
<div
className="sc-ifAKCX hULCSa sc-input"
className="sc-ifAKCX kwGiKK sc-input"
type="text"
>
<div
className="sc-gzVnrw kvhoeX sc-input-wrapper"
Expand Down
Loading