UNPKG

@mapbox/mr-ui

Version:

UI components for Mapbox projects

183 lines (182 loc) 8.09 kB
"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 };