orcs-design-system
Version:
TeamForm's Design System, aka: ORCS
355 lines (353 loc) • 16.6 kB
JavaScript
import _defineProperty from "@babel/runtime/helpers/defineProperty";
import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
const _excluded = ["numberProps"];
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
import React, { useMemo } from "react";
import { NumericFormat } from "react-number-format";
import PropTypes from "prop-types";
import styled, { css } from "styled-components";
import { space, layout, compose } from "styled-system";
import { createShouldForwardProp, props } from "@styled-system/should-forward-prop";
import Icon from "../Icon";
import { themeGet } from "@styled-system/theme-get";
import useInputFocus from "../../hooks/useInputFocus";
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
const InputStyles = compose(space, layout);
// For Group (div): block styled-system props and input-specific props so they don't leak to DOM
const shouldForwardProp = createShouldForwardProp([...props, "type", "placeholder", "defaultValue", "disabled", "maxLength", "pattern", "required", "autocomplete", "autofocus", "step", "readonly"]);
// For Input/NumberInput: only block styled-system props + invalid/valid (so type, placeholder, value reach the DOM)
const inputShouldForwardProp = prop => prop !== "invalid" && prop !== "valid" && createShouldForwardProp(props)(prop);
const Group = /*#__PURE__*/styled("div").withConfig({
shouldForwardProp,
displayName: "Group",
componentId: "sc-shde0o-0"
})(props => css({
position: "relative",
width: props.fullWidth ? "100%" : "auto",
minHeight: props => {
var _props$height;
return (_props$height = props.height) !== null && _props$height !== void 0 ? _props$height : themeGet(props.floating ? "appScale.inputHeightLarge" : "appScale.inputHeightDefault")(props);
}
}), InputStyles);
const IconWrapper = /*#__PURE__*/styled.label.withConfig({
displayName: "IconWrapper",
componentId: "sc-shde0o-1"
})(["display:flex;align-items:center;min-height:inherit;position:absolute;width:fit-content;bottom:0;padding:0 10px;svg{opacity:0.4;}", ";"], props => props.iconLeft && !props.floating ? css(["left:0;"]) : props.iconLeft && props.floating ? css(["left:0;bottom:11px;"]) : props.iconRight && !props.floating ? css(["right:0;"]) : props.iconRight && props.floating ? css(["right:0;bottom:11px;"]) : css([""]));
const InputStyle = /*#__PURE__*/css(["display:block;cursor:text;-moz-appearance:none;-webkit-appearance:none;appearance:none;font-family:\"Open Sans\",\"Helvetica Neue\",Helvetica,Arial,sans-serif;box-shadow:none;font-size:", ";z-index:1;border-radius:", ";transition:", ";background:", ";color:", ";width:", ";height:", ";padding:", ";border:1px solid ", ";", " &:hover{border:1px solid ", ";}&:focus{outline:0;box-shadow:", ";border:1px solid ", ";", ";}"], props => themeGet("fontSizes.0")(props), props => themeGet("radii.2")(props), props => themeGet("transition.transitionDefault")(props), props => props.disabled ? themeGet("colors.greyLightest")(props) : themeGet("colors.white")(props), props => props.disabled ? themeGet("colors.grey")(props) : themeGet("colors.greyDarkest")(props), props => props.fullWidth ? "100%" : "auto", props => props.height ? props.height : props.floating ? themeGet("appScale.inputHeightLarge")(props) : themeGet("appScale.inputHeightDefault")(props), props => {
let left = props.iconLeft ? 36 : 10;
let right = props.iconRight ? 36 : 10;
let top = props.floating ? 25 : 5;
let bottom = 6;
return "".concat(top, "px ").concat(right, "px ").concat(bottom, "px ").concat(left, "px");
}, props => props.invalid ? themeGet("colors.danger")(props) : props.valid ? themeGet("colors.success")(props) : themeGet("colors.black30")(props), props => props.floating ? css(["&::placeholder{color:transparent;}&:not(:placeholder-shown){~ label{transform:translateY(-10px);font-size:", ";}}&:-ms-input-placeholder:not(:focus){~ label{transform:translateY(-10px);font-size:", ";}}&:not(:-ms-input-placeholder){~ label{transform:translateY(-10px);font-size:", ";}}"], themeGet("fontSizes.0")(props), themeGet("fontSizes.0")(props), themeGet("fontSizes.0")(props)) : css(["&::placeholder{color:", ";}"], themeGet("colors.grey")(props)), props => props.invalid ? themeGet("colors.dangerDark")(props) : props.valid ? themeGet("colors.successDark")(props) : themeGet("colors.primary")(props), props => props.invalid ? themeGet("shadows.thickOutline")(props) + " " + themeGet("colors.danger30")(props) : props.valid ? themeGet("shadows.thickOutline")(props) + " " + themeGet("colors.success30")(props) : themeGet("shadows.thickOutline")(props) + " " + themeGet("colors.primary30")(props), props => props.invalid ? themeGet("colors.dangerDark")(props) : props.valid ? themeGet("colors.successDark")(props) : themeGet("colors.primary")(props), props => props.floating ? css(["&::placeholder{color:", ";}~ label{transform:translateY(-10px);font-size:", ";color:", ";}"], themeGet("colors.greyLight")(props), themeGet("fontSizes.0")(props), props => props.invalid ? themeGet("colors.dangerDark")(props) : props.valid ? themeGet("colors.successDark")(props) : themeGet("colors.primary")(props)) : css([""]));
const Input = /*#__PURE__*/styled("input").withConfig({
shouldForwardProp: inputShouldForwardProp
}).attrs(props => ({
"data-testid": props["data-testid"] ? props["data-testid"] : null
})).withConfig({
displayName: "Input",
componentId: "sc-shde0o-2"
})(["", ""], InputStyle);
const NumberInput = /*#__PURE__*/styled(NumericFormat).withConfig({
shouldForwardProp: inputShouldForwardProp
}).attrs(props => ({
"data-testid": props["data-testid"] ? props["data-testid"] : null
})).withConfig({
displayName: "NumberInput",
componentId: "sc-shde0o-3"
})(["", ""], InputStyle);
const Label = /*#__PURE__*/styled.label.withConfig({
displayName: "Label",
componentId: "sc-shde0o-4"
})(["display:block;z-index:2;text-align:left;font-size:", ";font-weight:", ";transition:", ";padding-right:", ";margin-bottom:", ";color:", ";", ";", ";"], props => themeGet("fontSizes.0")(props), props => props.bold ? themeGet("fontWeights.2")(props) : themeGet("fontWeights.1")(props), props => themeGet("transition.transitionDefault")(props), props => props.floating && props.iconRight ? "40px" : "12px", props => props.floating ? 0 : themeGet("space.xs")(props), props => props.inverted ? themeGet("colors.white")(props) : props.valid ? themeGet("colors.successDark")(props) : props.invalid ? themeGet("colors.dangerDark")(props) : themeGet("colors.greyDarkest")(props), props => props.floating ? css(["padding-left:", ";cursor:text;position:absolute;top:", ";color:", ";"], props => props.iconLeft ? "37px" : "11px", props => {
let inputHeight = themeGet("appScale.inputHeightLarge")(props);
return "calc(".concat(inputHeight, " / 3)");
}, props => props.invalid ? themeGet("colors.dangerDark")(props) : props.valid ? themeGet("colors.successDark")(props) : themeGet("colors.greyDark")(props)) : css([""]), props => props.mandatory ? css(["&::after{content:\" *\";color:", ";}"], themeGet("colors.danger")(props)) : css([""]));
const TextInput = /*#__PURE__*/React.forwardRef((props, ref) => {
const {
inverted,
floating,
id,
bold,
invalid,
valid,
fullWidth,
mandatory,
iconLeft,
iconRight,
InputStyles,
height,
focus,
ariaLabel
} = props;
const inputRef = useInputFocus(ref, focus);
const {
numberProps
} = props,
rest = _objectWithoutProperties(props, _excluded);
let getNumberInputRef = null;
if (numberProps && inputRef) {
getNumberInputRef = node => {
inputRef.current = node;
};
}
const label = useMemo(() => {
if (numberProps && numberProps.prefix) {
return "".concat(props.label, " ").concat(numberProps.prefix);
}
return props.label;
}, [props.label, numberProps]);
return /*#__PURE__*/_jsxs(Group, _objectSpread(_objectSpread({
fullWidth: fullWidth,
height: height
}, InputStyles), {}, {
children: [label && !floating ? /*#__PURE__*/_jsx(Label, {
inverted: inverted,
invalid: invalid,
valid: valid,
bold: bold,
htmlFor: id,
mandatory: mandatory,
children: label
}) : null, numberProps ? /*#__PURE__*/_jsx(NumberInput, _objectSpread(_objectSpread(_objectSpread({
getInputRef: getNumberInputRef,
"data-testid": props["data-testid"],
id: id,
"aria-label": ariaLabel,
"aria-invalid": invalid !== null && invalid !== void 0 ? invalid : undefined,
invalid: invalid,
valid: valid
}, rest), numberProps), {}, {
type: numberProps.type != null ? numberProps.type : rest.type === "number" ? "text" : rest.type || "text",
height: height
})) : /*#__PURE__*/_jsx(Input, _objectSpread({
"data-testid": props["data-testid"],
height: height,
ref: inputRef,
id: id,
"aria-label": ariaLabel,
"aria-invalid": invalid !== null && invalid !== void 0 ? invalid : undefined,
invalid: invalid,
valid: valid
}, rest)), label && floating ? /*#__PURE__*/_jsx(Label, {
floating: floating,
invalid: invalid,
valid: valid,
bold: bold,
htmlFor: id,
mandatory: mandatory,
iconRight: iconRight,
iconLeft: iconLeft,
children: label
}) : null, iconLeft ? /*#__PURE__*/_jsx(IconWrapper, {
htmlFor: id,
iconLeft: iconLeft,
floating: floating,
children: /*#__PURE__*/_jsx(Icon, {
icon: iconLeft,
htmlFor: id,
color: "black"
})
}) : null, iconRight ? /*#__PURE__*/_jsx(IconWrapper, {
htmlFor: id,
iconRight: iconRight,
floating: floating,
children: /*#__PURE__*/_jsx(Icon, {
icon: iconRight,
htmlFor: id,
color: "#black"
})
}) : null]
}));
});
TextInput.propTypes = {
/** Must be used to specify a unique ID. */
id: PropTypes.string.isRequired,
/** Can be used to set a specific height. */
height: PropTypes.string,
/** Specifies the text for the label. */
label: PropTypes.string,
/** Specifies aria-label for TextArea. This is only required if not using the label prop.*/
ariaLabel: (props, propName) => {
if (!props.label && (props[propName] == null || props[propName] === "")) {
return new Error("Missing prop `".concat(propName, "` not specified for TextInput component. When `label` is not provided, `").concat(propName, "` is required."));
}
if (props[propName] && typeof props[propName] !== "string") {
return new Error("Invalid propType `".concat(propName, "` supplied to TextInput component. Expected `string`, received `").concat(typeof props[propName], "`."));
}
return null;
},
/** Makes label text bold */
bold: PropTypes.bool,
/** Specifies the helper/example text for the placeholder. */
placeholder: PropTypes.string,
/** Specifies the type of text input, e.g. text, email, password, number */
type: PropTypes.string,
/** Applies different styling for a floating animated label aesthetic */
floating: PropTypes.bool,
/** Makes text box take up full width of parent */
fullWidth: PropTypes.bool,
/** Applies invalid input styles */
invalid: PropTypes.bool,
/** Applies valid input styles */
valid: PropTypes.bool,
/** Shows asterisk to denote a mandatory field */
mandatory: PropTypes.bool,
/** Applies an icon to the left of the text box with specified name. */
iconLeft: PropTypes.array,
/** Applies an icon to the right of the text box with specified name. */
iconRight: PropTypes.array,
/** Number format props, to render a number input textbox */
numberProps: PropTypes.object,
/** Set inverted styling for dark backgrounds */
inverted: PropTypes.bool,
/** Specifies the `data-testid` attribute for testing. */
"data-testid": PropTypes.string,
/** Specifies any additional `space` and `layout` props for the entire component */
InputStyles: PropTypes.object,
/** Focus on input */
focus: PropTypes.bool
};
TextInput.__docgenInfo = {
"description": "",
"methods": [],
"displayName": "TextInput",
"props": {
"id": {
"description": "Must be used to specify a unique ID.",
"type": {
"name": "string"
},
"required": true
},
"height": {
"description": "Can be used to set a specific height.",
"type": {
"name": "string"
},
"required": false
},
"label": {
"description": "Specifies the text for the label.",
"type": {
"name": "string"
},
"required": false
},
"ariaLabel": {
"description": "Specifies aria-label for TextArea. This is only required if not using the label prop.",
"type": {
"name": "custom",
"raw": "(props, propName) => {\n if (!props.label && (props[propName] == null || props[propName] === \"\")) {\n return new Error(\n `Missing prop \\`${propName}\\` not specified for TextInput component. When \\`label\\` is not provided, \\`${propName}\\` is required.`\n );\n }\n if (props[propName] && typeof props[propName] !== \"string\") {\n return new Error(\n `Invalid propType \\`${propName}\\` supplied to TextInput component. Expected \\`string\\`, received \\`${typeof props[\n propName\n ]}\\`.`\n );\n }\n return null;\n}"
},
"required": false
},
"bold": {
"description": "Makes label text bold",
"type": {
"name": "bool"
},
"required": false
},
"placeholder": {
"description": "Specifies the helper/example text for the placeholder.",
"type": {
"name": "string"
},
"required": false
},
"type": {
"description": "Specifies the type of text input, e.g. text, email, password, number",
"type": {
"name": "string"
},
"required": false
},
"floating": {
"description": "Applies different styling for a floating animated label aesthetic",
"type": {
"name": "bool"
},
"required": false
},
"fullWidth": {
"description": "Makes text box take up full width of parent",
"type": {
"name": "bool"
},
"required": false
},
"invalid": {
"description": "Applies invalid input styles",
"type": {
"name": "bool"
},
"required": false
},
"valid": {
"description": "Applies valid input styles",
"type": {
"name": "bool"
},
"required": false
},
"mandatory": {
"description": "Shows asterisk to denote a mandatory field",
"type": {
"name": "bool"
},
"required": false
},
"iconLeft": {
"description": "Applies an icon to the left of the text box with specified name.",
"type": {
"name": "array"
},
"required": false
},
"iconRight": {
"description": "Applies an icon to the right of the text box with specified name.",
"type": {
"name": "array"
},
"required": false
},
"numberProps": {
"description": "Number format props, to render a number input textbox",
"type": {
"name": "object"
},
"required": false
},
"inverted": {
"description": "Set inverted styling for dark backgrounds",
"type": {
"name": "bool"
},
"required": false
},
"data-testid": {
"description": "Specifies the `data-testid` attribute for testing.",
"type": {
"name": "string"
},
"required": false
},
"InputStyles": {
"description": "Specifies any additional `space` and `layout` props for the entire component",
"type": {
"name": "object"
},
"required": false
},
"focus": {
"description": "Focus on input",
"type": {
"name": "bool"
},
"required": false
}
}
};
export default TextInput;