UNPKG

@cimpress/react-components

Version:
312 lines (300 loc) 13.3 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.TextArea = exports.TextField = exports.controlLabelCss = exports.formGroupActiveCss = exports.formGroupCss = void 0; const react_1 = __importStar(require("react")); const css_1 = require("@emotion/css"); const utils_1 = require("./utils"); const cvar_1 = __importDefault(require("./theme/cvar")); const SuccessSvg_1 = __importDefault(require("./icons/SuccessSvg")); const WarningSvg_1 = __importDefault(require("./icons/WarningSvg")); const ErrorSvg_1 = __importDefault(require("./icons/ErrorSvg")); const FeatureFlags_1 = require("./FeatureFlags"); const isTextTruthy = (val) => val !== undefined && val !== null && val.toString() !== ''; exports.formGroupCss = (0, css_1.css) ` position: relative; margin-bottom: ${(0, cvar_1.default)('spacing-16')}; input, textarea { color: ${(0, cvar_1.default)('color-text-default')}; } input { box-shadow: none; padding: ${(0, cvar_1.default)('spacing-16')}; transition: all 0.2s ease-out; &:focus { outline: none; box-shadow: none; border-color: ${(0, cvar_1.default)('color-border-interactive')}; } } textarea { box-shadow: none; padding: ${(0, cvar_1.default)('spacing-16')}; height: auto; &:focus { outline: none; box-shadow: none; border-color: ${(0, cvar_1.default)('color-border-interactive')}; } } label { color: ${(0, cvar_1.default)('color-text-label')}; font-weight: normal; position: absolute; left: ${(0, cvar_1.default)('spacing-16')}; top: ${(0, cvar_1.default)('spacing-16')}; line-height: 16px; margin-bottom: 0; transition: all 0.2s ease-out; z-index: 5; overflow-x: clip; white-space: nowrap; text-overflow: ellipsis; max-width: 90%; } `; exports.formGroupActiveCss = (0, css_1.css) ` input, textarea { padding: ${(0, cvar_1.default)('spacing-24')} ${(0, cvar_1.default)('spacing-16')} ${(0, cvar_1.default)('spacing-8')}; } label { top: ${(0, cvar_1.default)('spacing-4')}; font-size: 12px; } `; exports.controlLabelCss = (0, css_1.css) ` margin-bottom: 0; font-size: inherit; line-height: 1.5; `; const isRequired = (0, css_1.css) ` label:after { content: ' *'; color: ${(0, cvar_1.default)('color-required-asterisk')}; } `; const isDisabled = (0, css_1.css) ` input { color: ${(0, cvar_1.default)('color-text-label')}; background: ${(0, cvar_1.default)('color-textfield-disabled')}; } `; const formControl = (0, css_1.css) ` height: ${(0, cvar_1.default)('spacing-48')}; border: 1px solid ${(0, cvar_1.default)('color-border-default')}; position: relative; flex: 1 1 auto; width: 1%; margin-bottom: 0; `; const inputGroup = (0, css_1.css) ` z-index: 0; position: relative; display: flex; width: 100%; > .crc-button { padding: ${(0, cvar_1.default)('spacing-12')} ${(0, cvar_1.default)('spacing-24')}; } /* Remove border from input when right addon is present */ &:has(> .crc-button) :is(input, textarea) { border-right: 0; } /* Remove right border radius from addon button when consecutive addon is present */ &:has(> .crc-button + .crc-button) :not(.crc-button:last-of-type) { border-top-right-radius: 0; border-bottom-right-radius: 0; } /* Remove border radius from left addon when it is the first addon */ > .crc-button:first-of-type { border-top-left-radius: 0; border-bottom-left-radius: 0; } /* Remove double borders between addons, and remove left border radius from when addons are consecutive */ > .crc-button + .crc-button { border-left: 0; border-top-left-radius: 0; border-bottom-left-radius: 0; } `; const helpBlock = (0, css_1.css) ` display: block; margin-top: ${(0, cvar_1.default)('spacing-4')}; `; const textfieldColorMap = { success: 'color-border-success', warning: 'color-border-warning', error: 'color-border-error', }; const statusIconStyles = (0, css_1.css) ` position: absolute; right: ${(0, cvar_1.default)('spacing-12')}; top: ${(0, cvar_1.default)('spacing-16')}; color: var(--crc-text-input-status-icon-color); transition: all 0.2s ease-out; `; const statusIconSvg = { success: react_1.default.createElement(SuccessSvg_1.default, { className: statusIconStyles }), warning: react_1.default.createElement(WarningSvg_1.default, { className: statusIconStyles }), error: react_1.default.createElement(ErrorSvg_1.default, { className: statusIconStyles }), }; const statusCss = (status) => (0, css_1.css) ` --crc-text-input-status-icon-color: ${(0, cvar_1.default)(textfieldColorMap[status])}; input { box-shadow: none; padding-right: ${(0, cvar_1.default)('spacing-32')}; &:focus { border-color: ${(0, cvar_1.default)(textfieldColorMap[status])}; } } .crc-text-field { border-color: ${(0, cvar_1.default)(textfieldColorMap[status])}; } `; const inputWrapper = (0, css_1.css) ` display: flex; flex: 1 1 auto; position: relative; `; const noOuterMarginCss = (0, css_1.css) ` margin-bottom: 0; `; exports.TextField = react_1.default.forwardRef((_a, ref) => { var { autoFocus = false, className = '', disabled = false, helpText, id, inputStyle, label, name, onBlur, onChange, onClick, onFocus, onKeyDown, placeholder, required = false, rightAddon, status, style, type = 'text', value, defaultValue = '', pattern } = _a, rest = __rest(_a, ["autoFocus", "className", "disabled", "helpText", "id", "inputStyle", "label", "name", "onBlur", "onChange", "onClick", "onFocus", "onKeyDown", "placeholder", "required", "rightAddon", "status", "style", "type", "value", "defaultValue", "pattern"]); const { v17_noOuterSpacing } = (0, FeatureFlags_1.useFeatureFlags)(); const [internalValue, setInternalValue] = (0, react_1.useState)(defaultValue); const isControlled = value !== undefined; const currentValue = isControlled ? value : internalValue; const [float, setFloat] = (0, react_1.useState)(isTextTruthy(currentValue)); const uniqueId = (0, utils_1.useMemoizedId)({ label: `${name}-${placeholder}-${label}`, id }); (0, react_1.useEffect)(() => { setFloat(isTextTruthy(currentValue)); }, [setFloat, currentValue]); const handleBlur = (e) => { setFloat(isTextTruthy(currentValue)); onBlur && onBlur(e); }; const handleFocus = (e) => { setFloat(true); onFocus && onFocus(e); }; const handleChange = (e) => { const newValue = e.target.value; const isValid = !pattern || !!newValue.match(new RegExp(`^${pattern}$`)); if (!isControlled) { setInternalValue(newValue); } onChange && onChange(Object.assign(Object.assign({}, e), { isValid })); }; const inputId = id || uniqueId; const wrapperClassNames = (0, css_1.cx)('crc-text-input', exports.formGroupCss, v17_noOuterSpacing && noOuterMarginCss, className, { [exports.formGroupActiveCss]: !!label && float, [statusCss(status)]: !!status, [isRequired]: !!required, [isDisabled]: !!disabled, }); const inputProps = Object.assign(Object.assign({}, rest), { autoFocus, disabled, id: inputId, name, onBlur: handleBlur, onChange: handleChange, onClick, onFocus: handleFocus, onKeyDown, placeholder, required, style: inputStyle, value: currentValue, pattern, type }); const inputElement = (react_1.default.createElement("input", Object.assign({}, inputProps, { className: (0, css_1.cx)(formControl, 'crc-text-field'), ref: ref }))); const labelElement = label ? (react_1.default.createElement("label", { className: exports.controlLabelCss, htmlFor: inputId, title: label }, label)) : null; return (react_1.default.createElement("div", { className: wrapperClassNames, style: style }, react_1.default.createElement("div", { className: inputGroup }, react_1.default.createElement("div", { className: inputWrapper }, inputElement, labelElement, !!status && statusIconSvg[status]), rightAddon), helpText ? react_1.default.createElement("small", { className: helpBlock }, helpText) : null)); }); exports.TextField.displayName = 'TextField'; exports.TextArea = react_1.default.forwardRef((_a, ref) => { var { autoFocus = false, className = '', disabled = false, helpText, id, inputStyle, label, name, onBlur, onChange, onClick, onFocus, onKeyDown, placeholder, required = false, rightAddon, status, style, value, defaultValue = '', pattern } = _a, rest = __rest(_a, ["autoFocus", "className", "disabled", "helpText", "id", "inputStyle", "label", "name", "onBlur", "onChange", "onClick", "onFocus", "onKeyDown", "placeholder", "required", "rightAddon", "status", "style", "value", "defaultValue", "pattern"]); const { v17_noOuterSpacing: noOuterSpacing } = (0, FeatureFlags_1.useFeatureFlags)(); const [internalValue, setInternalValue] = (0, react_1.useState)(defaultValue); const isControlled = value !== undefined; const currentValue = isControlled ? value : internalValue; const [float, setFloat] = (0, react_1.useState)(isTextTruthy(currentValue)); const uniqueId = (0, utils_1.useMemoizedId)({ label: `${name}-${placeholder}-${label}`, id }); (0, react_1.useEffect)(() => { setFloat(isTextTruthy(currentValue)); }, [setFloat, currentValue]); const handleBlur = (e) => { setFloat(isTextTruthy(currentValue)); onBlur && onBlur(e); }; const handleFocus = (e) => { setFloat(true); onFocus && onFocus(e); }; const handleChange = (e) => { const newValue = e.target.value; const isValid = !pattern || !!newValue.match(new RegExp(`^${pattern}$`)); if (!isControlled) { setInternalValue(newValue); } onChange && onChange(Object.assign(Object.assign({}, e), { isValid })); }; const inputId = id || uniqueId; const wrapperClassNames = (0, css_1.cx)('crc-text-input', exports.formGroupCss, noOuterSpacing && noOuterMarginCss, className, { [exports.formGroupActiveCss]: !!label && float, [statusCss(status)]: !!status, [isRequired]: !!required, [isDisabled]: !!disabled, }); const inputProps = Object.assign(Object.assign({}, rest), { autoFocus, disabled, id: inputId, name, onBlur: handleBlur, onChange: handleChange, onClick, onFocus: handleFocus, onKeyDown, placeholder, required, style: inputStyle, value: currentValue }); const inputElement = (react_1.default.createElement("textarea", Object.assign({}, inputProps, { className: (0, css_1.cx)(formControl, 'crc-text-field'), ref: ref }))); const labelElement = label ? (react_1.default.createElement("label", { className: exports.controlLabelCss, htmlFor: inputId, title: label }, label)) : null; return (react_1.default.createElement("div", { className: wrapperClassNames, style: style }, react_1.default.createElement("div", { className: inputGroup }, react_1.default.createElement("div", { className: inputWrapper }, inputElement, labelElement, !!status && statusIconSvg[status]), rightAddon && react_1.default.createElement("div", null, rightAddon)), helpText ? react_1.default.createElement("small", { className: helpBlock }, helpText) : null)); }); exports.TextArea.displayName = 'TextArea'; //# sourceMappingURL=TextInput.js.map