UNPKG

@kiwicom/orbit-components

Version:

Orbit-components is a React component library which provides developers with the easiest possible way of building Kiwi.com’s products.

190 lines (175 loc) 6.98 kB
import * as React from "react"; import styled, { css } from "styled-components"; import defaultTheme from "../../defaultTheme"; import FormLabel from "../../FormLabel"; import { FakeInput, Input, InputContainer } from "../InputField"; import { SelectContainer } from "../Select"; import FormFeedback from "../FormFeedback"; import { SIZE_OPTIONS, TOKENS } from "./consts"; import { right, rtlSpacing } from "../../utils/rtl"; import getSpacingToken from "../../common/getSpacingToken"; import randomID from "../../utils/randomID"; import formElementFocus from "../InputField/helpers/formElementFocus"; import mq from "../../utils/mediaQuery"; const getToken = name => ({ theme, size }) => { const tokens = { [TOKENS.height]: { [SIZE_OPTIONS.SMALL]: theme.orbit.heightInputSmall, [SIZE_OPTIONS.NORMAL]: theme.orbit.heightInputNormal }, [TOKENS.heightLine]: { [SIZE_OPTIONS.SMALL]: "16px", [SIZE_OPTIONS.NORMAL]: "24px" } }; return tokens[name][size]; }; const FakeGroup = styled(({ children, className }) => /*#__PURE__*/React.createElement("span", { className: className }, children)).withConfig({ displayName: "InputGroup__FakeGroup", componentId: "sc-ed1mas-0" })(["", ""], ({ theme, error, disabled }) => css(["width:100%;display:block;position:absolute;top:0px;left:0;z-index:1;box-sizing:border-box;height:", ";box-shadow:", ";box-shadow:", ";", ";background-color:", ";font-size:", ";transition:box-shadow ", " ease-in-out;border-radius:6px;", ";&:hover{box-shadow:inset 0 0 0 ", ";}"], getToken(TOKENS.height), `inset 0 0 0 ${theme.orbit.borderWidthInput} ${theme.orbit.borderColorInput}`, error && `inset 0 0 0 ${theme.orbit.borderWidthInput} ${theme.orbit.borderColorInputError}`, ({ active }) => active && formElementFocus, disabled ? theme.orbit.backgroundInputDisabled : theme.orbit.backgroundInput, theme.orbit.fontSizeInputNormal, theme.orbit.durationFast, mq.tablet(css(["border-radius:", ";"], theme.orbit.borderRadiusNormal)), `${theme.orbit.borderWidthInput} ${error ? theme.orbit.borderColorInputErrorHover : theme.orbit.borderColorInputHover}`)); // $FlowFixMe: https://github.com/flow-typed/flow-typed/issues/3653#issuecomment-568539198 FakeGroup.defaultProps = { theme: defaultTheme }; const StyledChildren = styled.div.withConfig({ displayName: "InputGroup__StyledChildren", componentId: "sc-ed1mas-1" })(["display:flex;position:relative;"]); const StyledChild = styled.div.withConfig({ displayName: "InputGroup__StyledChild", componentId: "sc-ed1mas-2" })(["flex:", ";padding:", ";:last-child{padding:0;}"], ({ flex }) => flex, ({ theme }) => rtlSpacing(`0 ${theme.orbit.spaceXSmall} 0 0`)); // $FlowFixMe: https://github.com/flow-typed/flow-typed/issues/3653#issuecomment-568539198 StyledChild.defaultProps = { theme: defaultTheme }; const StyledInputGroup = styled(({ children, className, dataTest, role, ariaLabelledby, forwardRef, dataState }) => /*#__PURE__*/React.createElement("div", { "data-state": dataState, ref: forwardRef, className: className, "data-test": dataTest, role: role, "aria-labelledby": ariaLabelledby }, children)).withConfig({ displayName: "InputGroup__StyledInputGroup", componentId: "sc-ed1mas-3" })(["display:flex;width:100%;flex-direction:column;position:relative;margin-bottom:", ";", "{", "{box-shadow:none;background-color:transparent;display:none;align-items:center;justify-content:flex-end;}", "{background-color:transparent;> select{box-shadow:none;background-color:transparent;&:focus{box-shadow:none;}}}", ":after,", ":after{content:\" \";position:absolute;top:50%;transform:translateY(-50%);", ":0;height:", ";width:1px;background-color:", ";transition:background-color ", " ease-in-out;display:block;z-index:2;}&:last-of-type{", ":after,", ":after{content:none;}}}", " ", "{display:", ";}", ":focus ~ ", "{box-shadow:none;}"], getSpacingToken, StyledChild, FakeInput, SelectContainer, InputContainer, SelectContainer, right, getToken(TOKENS.heightLine), ({ theme, error, active }) => error && !active ? theme.orbit.borderColorInputError : theme.orbit.borderColorInput, ({ theme }) => theme.orbit.durationFast, InputContainer, SelectContainer, StyledChild, FormLabel, ({ label }) => label && "none", Input, FakeInput); // $FlowFixMe: https://github.com/flow-typed/flow-typed/issues/3653#issuecomment-568539198 StyledInputGroup.defaultProps = { theme: defaultTheme }; const findPropInChild = (propToFind, children) => { return React.Children.toArray(children).map(el => { if (el.props && typeof el.props[propToFind] !== "undefined") return el.props[propToFind]; return null; }).filter(el => el !== null && el !== ""); }; const InputGroup = ({ children, label, flex = "0 1 auto", size = SIZE_OPTIONS.NORMAL, help, error, dataTest, spaceAfter = "medium", onFocus, onBlur, onChange }) => { const [active, setActive] = React.useState(false); const [filled, setFilled] = React.useState(false); const inputID = React.useMemo(() => randomID("inputGroupID"), []); const isFilled = React.useCallback(() => setFilled(findPropInChild("value", children).length === React.Children.toArray(children).length), [children]); React.useEffect(() => { isFilled(); }, [isFilled]); const handleFocus = ev => { setActive(true); if (onFocus) { onFocus(ev); } }; const handleBlur = ev => { isFilled(); setActive(false); if (onBlur) { onBlur(ev); } }; const handleChange = ev => { isFilled(); if (onChange) { onChange(ev); } }; return /*#__PURE__*/React.createElement(StyledInputGroup, { label: label, error: error, active: active, size: size, dataTest: dataTest, spaceAfter: spaceAfter, role: "group", ariaLabelledby: label && inputID }, label && /*#__PURE__*/React.createElement(FormLabel, { filled: filled, id: inputID }, label), /*#__PURE__*/React.createElement(StyledChildren, null, React.Children.map(children, (item, key) => { // either array, array with one length or string // if it's not defined, use the first or string const childFlex = Array.isArray(flex) && flex.length !== 1 ? flex[key] || flex[0] : flex; return /*#__PURE__*/React.createElement(StyledChild, { flex: childFlex }, /*#__PURE__*/React.cloneElement(item, { size, label: undefined, help: undefined, error: undefined, onChange: item.props.onChange != null ? item.props.onChange : handleChange, onBlur: item.props.onBlur != null ? item.props.onChange : handleBlur, onFocus: item.props.onFocus != null ? item.props.onFocus : handleFocus })); }), /*#__PURE__*/React.createElement(FakeGroup, { label: label, error: error, active: active, size: size })), /*#__PURE__*/React.createElement(FormFeedback, { error: error, help: help })); }; export default InputGroup;