mirror of
https://github.com/react95-io/React95.git
synced 2026-04-26 03:00:18 -04:00
extracted InputBase, styled NumberField
This commit is contained in:
@@ -117,8 +117,9 @@ class DatePicker extends Component {
|
||||
/>
|
||||
<NumberField
|
||||
value={year}
|
||||
disableKeyboardInput
|
||||
onChange={this.handleYearSelect}
|
||||
width={90}
|
||||
width={100}
|
||||
className={`${baseClass}-toolbar__input`}
|
||||
/>
|
||||
</div>
|
||||
|
||||
51
src/components/InputBase/InputBase.js
Normal file
51
src/components/InputBase/InputBase.js
Normal file
@@ -0,0 +1,51 @@
|
||||
import React from "react";
|
||||
import propTypes from "prop-types";
|
||||
|
||||
import styled from "styled-components";
|
||||
import { StyledTextInput, StyledCutout } from "../common";
|
||||
import { colors, blockSizes } from "../common/theme.variables";
|
||||
|
||||
const StyledInputWrapper = styled(StyledCutout)`
|
||||
height: ${blockSizes.md};
|
||||
padding: 2px;
|
||||
background: ${props => (props.isDisabled ? colors.bg : colors.light)};
|
||||
`;
|
||||
|
||||
const InputBase = ({
|
||||
onChange,
|
||||
value,
|
||||
disabled,
|
||||
name,
|
||||
type,
|
||||
style,
|
||||
shadow,
|
||||
...otherProps
|
||||
}) => (
|
||||
<StyledInputWrapper shadow={shadow} isDisabled={disabled} style={style}>
|
||||
<StyledTextInput
|
||||
onChange={disabled ? undefined : onChange}
|
||||
readOnly={disabled}
|
||||
disabled={disabled}
|
||||
value={value}
|
||||
name={name}
|
||||
type={type}
|
||||
{...otherProps}
|
||||
/>
|
||||
</StyledInputWrapper>
|
||||
);
|
||||
|
||||
InputBase.defaultProps = {
|
||||
value: "",
|
||||
disabled: false,
|
||||
shadow: true,
|
||||
onChange: undefined
|
||||
};
|
||||
InputBase.propTypes = {
|
||||
name: propTypes.string,
|
||||
onChange: propTypes.func,
|
||||
value: propTypes.oneOfType([propTypes.string, propTypes.number]).isRequired,
|
||||
disabled: propTypes.bool,
|
||||
shadow: propTypes.bool,
|
||||
type: propTypes.oneOf(["text", "number", "tel"])
|
||||
};
|
||||
export default InputBase;
|
||||
@@ -1,16 +1,54 @@
|
||||
import React, { Component } from "react";
|
||||
import React from "react";
|
||||
import propTypes from "prop-types";
|
||||
import cx from "classnames";
|
||||
|
||||
import "./NumberField.css";
|
||||
import Button from "../Button/Button";
|
||||
|
||||
import TextField from "../TextField/TextField";
|
||||
import styled from "styled-components";
|
||||
import { colors, blockSizes } from "../common/theme.variables";
|
||||
import InputBase from "../InputBase/InputBase";
|
||||
|
||||
class NumberField extends Component {
|
||||
// ⭕⭕⭕⭕⭕ fix functionality and use hooks
|
||||
|
||||
const StyledNumberFieldWrapper = styled.div`
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
const StyledButtonWrapper = styled.div`
|
||||
height: ${blockSizes.md};
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: nowrap;
|
||||
margin-left: 2px;
|
||||
margin-top: -2px;
|
||||
`;
|
||||
const StyledButton = styled(Button)`
|
||||
height: 50%;
|
||||
width: 30px;
|
||||
padding: 0;
|
||||
flex-shrink: 0;
|
||||
border-left-color: ${colors.lightGray};
|
||||
border-top-color: ${colors.lightGray};
|
||||
box-shadow: inset 1px 1px 0px 1px ${colors.light},
|
||||
inset -1px -1px 0 1px ${colors.darkGray};
|
||||
`;
|
||||
const StyledButtonIcon = styled.span`
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%) ${props => props.invert && "rotateZ(180deg)"};
|
||||
width: 0px;
|
||||
height: 0px;
|
||||
border-left: 4px solid transparent;
|
||||
border-right: 4px solid transparent;
|
||||
display: inline-block;
|
||||
border-top: 4px solid ${colors.dark};
|
||||
`;
|
||||
|
||||
class NumberField extends React.Component {
|
||||
static defaultProps = {
|
||||
value: 0,
|
||||
disabled: false,
|
||||
width: null
|
||||
disabled: false
|
||||
};
|
||||
static propTypes = {
|
||||
onChange: propTypes.func.isRequired,
|
||||
@@ -19,6 +57,9 @@ class NumberField extends Component {
|
||||
max: propTypes.number,
|
||||
width: propTypes.oneOfType([propTypes.string, propTypes.number]),
|
||||
disabled: propTypes.bool,
|
||||
disableKeyboardInput: propTypes.bool,
|
||||
fullWidth: propTypes.bool,
|
||||
shadow: propTypes.bool,
|
||||
className: propTypes.string
|
||||
};
|
||||
state = {
|
||||
@@ -32,51 +73,56 @@ class NumberField extends Component {
|
||||
};
|
||||
|
||||
handleChange = e => {
|
||||
const newValue = this.normalize(parseInt(e.target.value));
|
||||
this.props.onChange(newValue);
|
||||
this.setState({ value: newValue });
|
||||
let newValue =
|
||||
e.target.value === "-" ? "-" : this.normalize(e.target.value);
|
||||
console.log(newValue);
|
||||
newValue = newValue ? newValue : newValue === 0 ? 0 : "";
|
||||
if (e.target.validity.valid) {
|
||||
this.setState({ value: newValue });
|
||||
this.props.onChange(newValue);
|
||||
}
|
||||
};
|
||||
normalize = value => {
|
||||
const { min, max } = this.props;
|
||||
if (min !== undefined && value < min) return min;
|
||||
if (max !== undefined && value > max) return max;
|
||||
return value;
|
||||
return parseInt(value);
|
||||
};
|
||||
render() {
|
||||
const { disabled, className, width, style } = this.props;
|
||||
const {
|
||||
disabled,
|
||||
disableKeyboardInput,
|
||||
className,
|
||||
width,
|
||||
style,
|
||||
shadow
|
||||
} = this.props;
|
||||
const { value } = this.state;
|
||||
const baseClass = "NumberField";
|
||||
const rootClass = cx(baseClass, className, {
|
||||
[`${baseClass}__disabled`]: disabled
|
||||
});
|
||||
|
||||
return (
|
||||
<div
|
||||
className={rootClass}
|
||||
<StyledNumberFieldWrapper
|
||||
className={className}
|
||||
style={{ ...style, width: width ? width : "auto" }}
|
||||
>
|
||||
<TextField
|
||||
width={"100%"}
|
||||
<InputBase
|
||||
value={value}
|
||||
onChange={disabled ? undefined : this.handleChange}
|
||||
readOnly={disabled}
|
||||
type="number"
|
||||
onChange={
|
||||
disabled || disableKeyboardInput ? undefined : this.handleChange
|
||||
}
|
||||
readOnly={disabled || disableKeyboardInput}
|
||||
disabled={disabled}
|
||||
shadow={shadow}
|
||||
type="tel"
|
||||
pattern="^-?[0-9]\d*\.?\d*$"
|
||||
/>
|
||||
<div className={`${baseClass}-buttons`}>
|
||||
<button onClick={() => this.add(1)} className={`${baseClass}-button`}>
|
||||
<span
|
||||
className={`${baseClass}-button__icon ${baseClass}-button__icon--up`}
|
||||
/>
|
||||
</button>
|
||||
|
||||
<button
|
||||
onClick={() => this.add(-1)}
|
||||
className={`${baseClass}-button`}
|
||||
>
|
||||
<span className={`${baseClass}-button__icon`} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<StyledButtonWrapper>
|
||||
<StyledButton disabled={disabled} onClick={() => this.add(1)}>
|
||||
<StyledButtonIcon invert />
|
||||
</StyledButton>
|
||||
<StyledButton disabled={disabled} onClick={() => this.add(-1)}>
|
||||
<StyledButtonIcon />
|
||||
</StyledButton>
|
||||
</StyledButtonWrapper>
|
||||
</StyledNumberFieldWrapper>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,9 +15,36 @@ storiesOf("NumberField", module)
|
||||
</div>
|
||||
))
|
||||
.add("default", () => (
|
||||
<NumberField value={1991} onChange={value => console.log(value)} />
|
||||
))
|
||||
.add("fixed width", () => (
|
||||
<NumberField
|
||||
width={200}
|
||||
value={1991}
|
||||
onChange={value => console.log(value)}
|
||||
/>
|
||||
))
|
||||
.add("disabled", () => (
|
||||
<NumberField
|
||||
disabled
|
||||
width={200}
|
||||
value={1991}
|
||||
onChange={value => console.log(value)}
|
||||
/>
|
||||
))
|
||||
.add("disabled keyboard input", () => (
|
||||
<NumberField
|
||||
disableKeyboardInput
|
||||
width={200}
|
||||
value={1991}
|
||||
onChange={value => console.log(value)}
|
||||
/>
|
||||
))
|
||||
.add("no shadow", () => (
|
||||
<NumberField
|
||||
shadow={false}
|
||||
width={200}
|
||||
value={1991}
|
||||
onChange={value => console.log(value)}
|
||||
/>
|
||||
));
|
||||
|
||||
@@ -47,7 +47,7 @@ const StyledDropdownIcon = styled.span`
|
||||
border-left: 6px solid transparent;
|
||||
border-right: 6px solid transparent;
|
||||
display: inline-block;
|
||||
border-top: 6px solid #050608;
|
||||
border-top: 6px solid ${colors.dark};
|
||||
`;
|
||||
|
||||
const StyledDropdownList = styled.ul`
|
||||
|
||||
@@ -1,35 +1,7 @@
|
||||
import React, { useState } from "react";
|
||||
import propTypes from "prop-types";
|
||||
|
||||
import styled from "styled-components";
|
||||
import { StyledCutout } from "../common";
|
||||
import {
|
||||
blockSizes,
|
||||
fontSizes,
|
||||
padding,
|
||||
colors
|
||||
} from "../common/theme.variables";
|
||||
|
||||
const StyledInputWrapper = styled(StyledCutout)`
|
||||
height: ${blockSizes.md};
|
||||
padding: 2px;
|
||||
background: ${props => (props.isDisabled ? colors.bg : colors.light)};
|
||||
`;
|
||||
const StyledInput = styled.input`
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0 ${padding.sm};
|
||||
outline: none;
|
||||
border: none;
|
||||
background: none;
|
||||
font-size: ${fontSizes.md};
|
||||
|
||||
color: ${props => (props.disabled ? colors.darkGray : colors.dark)};
|
||||
text-shadow: ${props =>
|
||||
props.disabled ? "1px 1px " + colors.light : "none"};
|
||||
filter: ${props => (props.disabled ? "grayscale(100%)" : "none")};
|
||||
/* negative margin to compensate for wrapper borders */
|
||||
`;
|
||||
import InputBase from "../InputBase/InputBase";
|
||||
|
||||
const TextField = ({
|
||||
onChange,
|
||||
@@ -45,28 +17,24 @@ const TextField = ({
|
||||
}) => {
|
||||
const [inputValue, setInputValue] = useState(value);
|
||||
|
||||
console.log(value, inputValue);
|
||||
const onValueChange = e => {
|
||||
const newValue = e.target.value;
|
||||
setInputValue(newValue);
|
||||
onChange && onChange(e);
|
||||
};
|
||||
return (
|
||||
<StyledInputWrapper
|
||||
<InputBase
|
||||
shadow={shadow}
|
||||
isDisabled={disabled}
|
||||
style={{ ...style, width: width ? width : "auto" }}
|
||||
>
|
||||
<StyledInput
|
||||
onChange={disabled ? undefined : onValueChange}
|
||||
readOnly={disabled}
|
||||
disabled={disabled}
|
||||
value={inputValue}
|
||||
name={name}
|
||||
className={className}
|
||||
type={type}
|
||||
{...otherProps}
|
||||
/>
|
||||
</StyledInputWrapper>
|
||||
onChange={disabled ? undefined : onValueChange}
|
||||
disabled={disabled}
|
||||
value={inputValue}
|
||||
name={name}
|
||||
className={className}
|
||||
type="text"
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -83,8 +51,6 @@ TextField.propTypes = {
|
||||
value: propTypes.oneOfType([propTypes.string, propTypes.number]).isRequired,
|
||||
disabled: propTypes.bool,
|
||||
shadow: propTypes.bool,
|
||||
rows: propTypes.number,
|
||||
width: propTypes.oneOfType([propTypes.string, propTypes.number]),
|
||||
type: propTypes.oneOf(["text", "number"])
|
||||
width: propTypes.oneOfType([propTypes.string, propTypes.number])
|
||||
};
|
||||
export default TextField;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import styled, { css } from "styled-components";
|
||||
import { colors, fontSizes } from "./theme.variables";
|
||||
import { colors, fontSizes, padding } from "./theme.variables";
|
||||
|
||||
const { bg, light, dark, lightGray, darkGray } = colors;
|
||||
|
||||
@@ -80,3 +80,19 @@ export const StyledCutout = styled.div`
|
||||
props.shadow && "box-shadow: inset 3px 3px 10px rgba(0, 0, 0, 0.3);"}
|
||||
}
|
||||
`;
|
||||
|
||||
export const StyledTextInput = styled.input`
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0 ${padding.sm};
|
||||
outline: none;
|
||||
border: none;
|
||||
background: none;
|
||||
font-size: ${fontSizes.md};
|
||||
|
||||
color: ${props => (props.disabled ? colors.darkGray : colors.dark)};
|
||||
text-shadow: ${props =>
|
||||
props.disabled ? "1px 1px " + colors.light : "none"};
|
||||
filter: ${props => (props.disabled ? "grayscale(100%)" : "none")};
|
||||
/* negative margin to compensate for wrapper borders */
|
||||
`;
|
||||
|
||||
Reference in New Issue
Block a user