@mapbox/mr-ui
Version:
UI components for Mapbox projects
183 lines (182 loc) • 8.09 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = ControlText;
var _react = _interopRequireWildcard(require("react"));
var _propTypes = _interopRequireDefault(require("prop-types"));
var _omit = _interopRequireDefault(require("../utils/omit"));
var _controlLabel = _interopRequireDefault(require("../control-label"));
var _controlWrapper = _interopRequireDefault(require("../control-wrapper"));
var _popover = _interopRequireDefault(require("../popover"));
var _icon = _interopRequireDefault(require("../icon"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
const propNames = ['id', 'value', 'onChange', 'type', 'label', 'noAuto', 'optional', 'aside', 'validationError', 'errorStyle', 'popoverProps', 'themeControlInput', 'themeControlWrapper', 'themeLabel',
// Passed when used with the Form component
'initialValue', 'validator'];
function ControlText(_ref) {
let {
id,
onChange,
value = '',
label,
aside,
type = 'text',
optional = false,
validationError,
errorStyle = 'default',
noAuto = false,
themeLabel,
themeControlInput = 'input',
themeControlWrapper,
...props
} = _ref;
const [popoverOpen, setPopoverOpen] = (0, _react.useState)(false);
const extraProps = (0, _omit.default)(props, propNames);
const inputElement = (0, _react.useRef)(null);
const errorElement = (0, _react.useRef)(null);
const onErrorClick = () => {
if (inputElement.current) inputElement.current.select();
};
const isActive = () => {
if (typeof window === 'undefined') return false;
return window.document.activeElement === inputElement.current || window.document.activeElement === errorElement.current;
};
const onContainerMouseOver = () => {
if (isActive()) return;
setPopoverOpen(true);
};
const onContainerMouseOut = () => {
if (isActive()) return;
setPopoverOpen(false);
};
const renderLabel = () => {
return /*#__PURE__*/_react.default.createElement(_controlLabel.default, {
text: label,
id: id,
aside: aside,
optional: optional,
themeLabel: themeLabel
});
};
const inputProps = {
id,
name: id,
onChange: e => onChange(e.target.value, id),
value,
type,
className: themeControlInput,
'aria-required': !optional,
'data-testid': `${id}-input`
};
if (noAuto) {
inputProps.autoCapitalize = 'none';
inputProps.autoCorrect = 'off';
inputProps.spellCheck = false;
}
if (validationError) {
inputProps['aria-invalid'] = true;
}
if (validationError && errorStyle === 'inline') {
inputProps.className = `${themeControlInput} round-l flex-child-grow`;
inputProps.style = {
boxShadow: 'inset 0 0 0 1px #f74e4e'
};
}
const labelElement = label ? renderLabel() : null;
let control = /*#__PURE__*/_react.default.createElement("input", _extends({}, inputProps, extraProps));
if (errorStyle === 'inline') {
if (validationError) {
control = /*#__PURE__*/_react.default.createElement("div", {
onMouseOver: onContainerMouseOver,
onMouseOut: onContainerMouseOut,
"data-testid": "control-text-container",
className: "flex"
}, /*#__PURE__*/_react.default.createElement("input", _extends({
ref: inputElement,
onFocus: () => setPopoverOpen(true),
onBlur: () => setPopoverOpen(false)
}, inputProps, extraProps)), /*#__PURE__*/_react.default.createElement(_popover.default, _extends({
active: popoverOpen,
content: validationError,
placement: "top",
"aria-label": "Validation error"
}, props.popoverProps), /*#__PURE__*/_react.default.createElement("button", {
type: "button",
onFocus: () => setPopoverOpen(true),
onBlur: () => setPopoverOpen(false),
ref: errorElement,
onClick: onErrorClick,
"data-testid": "validation-error",
role: "alert",
className: "h-full bg-red color-white round-r px6"
}, /*#__PURE__*/_react.default.createElement("span", {
className: "flex flex--center-cross flex--center-main"
}, /*#__PURE__*/_react.default.createElement(_icon.default, {
name: "alert",
passthroughProps: {
fill: 'white',
className: 'cursor-pointer'
}
})))));
}
return /*#__PURE__*/_react.default.createElement(_controlWrapper.default, {
themeControlWrapper: themeControlWrapper,
id: id
}, labelElement, control);
}
return /*#__PURE__*/_react.default.createElement(_controlWrapper.default, {
themeControlWrapper: themeControlWrapper,
id: id,
validationError: validationError
}, labelElement, control);
}
ControlText.propTypes = {
/** Unique id for this control. Required if you want a `label`. */
id: _propTypes.default.string.isRequired,
/**
* Invoked when the control's value changes.
* Passed two arguments:
*
* - `value` the current value of the input passes as a string
* - The `id` prop.
*/
onChange: _propTypes.default.func.isRequired,
/** The control's value. Can be an empty string to indicate no value. */
value: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.number]),
/** Type attribute to override the existing default of 'text' */
type: _propTypes.default.string,
/** Label for the control. Label can be string or ReactNode. */
label: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.node]),
/** Enable/Disable browser enabled autocorrect or spelling suggestions from the element. */
noAuto: _propTypes.default.bool,
/** If provided, "(optional)" is appended to the value of the legend element. */
optional: _propTypes.default.bool,
/** Additional content inserted alongside the label element. */
aside: _propTypes.default.node,
/** If provided, the value of this propery displays as an error message. */
validationError: _propTypes.default.node,
/**
* Sets the style of the error message. There are two options:
*
* - `default` the standard presentation control components display an error
* message: beneath the input.
* - `inline` An error indicator is displayed to the right of the element
* with the value of `validationError` prop displayed in a tooltip.
*/
errorStyle: _propTypes.default.oneOf(['default', 'inline']),
/**
* Props to pass directly to the [Popover](#popover) component when inline error validation is in use. See Popover's
* documentation for details.
*/
popoverProps: _propTypes.default.object,
/** Classes to apply to the input element */
themeControlInput: _propTypes.default.string,
/** Classes to apply to the control wrapper */
themeControlWrapper: _propTypes.default.string,
/** classes to apply to the label element */
themeLabel: _propTypes.default.string
};