@cimpress/react-components
Version:
React components to support the MCP styleguide
312 lines (300 loc) • 13.3 kB
JavaScript
;
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