UNPKG

@storybook/design-system

Version:
191 lines (160 loc) 8.57 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); var _typeof = require("@babel/runtime/helpers/typeof"); Object.defineProperty(exports, "__esModule", { value: true }); exports.FormErrorState = exports.PureFormErrorState = void 0; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray")); var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties")); var _react = _interopRequireWildcard(require("react")); var _excluded = ["onSubmit"]; function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; } var PureFormErrorState = function PureFormErrorState(_ref) { var children = _ref.children, _ref$suppressErrorMes = _ref.suppressErrorMessages, suppressErrorMessages = _ref$suppressErrorMes === void 0 ? false : _ref$suppressErrorMes, onSubmit = _ref.onSubmit, _onMouseEnter = _ref.onMouseEnter, _onMouseLeave = _ref.onMouseLeave, _onBlur = _ref.onBlur, _onFocus = _ref.onFocus, getError = _ref.getError, primaryFieldId = _ref.primaryFieldId; var getFormErrorFieldProps = function getFormErrorFieldProps(_ref2) { var id = _ref2.id, validate = _ref2.validate; return { onMouseEnter: function onMouseEnter() { return _onMouseEnter(id); }, onMouseLeave: function onMouseLeave() { return _onMouseLeave(id); }, onFocus: function onFocus() { return _onFocus(id); }, onBlur: function onBlur() { return _onBlur(id); }, error: function error(value) { return getError({ id: id, value: value, validate: validate }); }, suppressErrorMessage: suppressErrorMessages || !primaryFieldId || primaryFieldId !== id }; }; return children({ getFormErrorFieldProps: getFormErrorFieldProps, onSubmit: onSubmit }); }; exports.PureFormErrorState = PureFormErrorState; var FormErrorState = function FormErrorState(_ref3) { var onSubmit = _ref3.onSubmit, rest = (0, _objectWithoutProperties2["default"])(_ref3, _excluded); var _useState = (0, _react.useState)(undefined), _useState2 = (0, _slicedToArray2["default"])(_useState, 2), focusedFieldId = _useState2[0], setFocusedFieldId = _useState2[1]; // The lastInteractionFieldId is used to control error messaging for fields that // are not active, but had an error after a recent focus. var _useState3 = (0, _react.useState)(undefined), _useState4 = (0, _slicedToArray2["default"])(_useState3, 2), lastInteractionFieldId = _useState4[0], setLastInteractionFieldId = _useState4[1]; var _useState5 = (0, _react.useState)(undefined), _useState6 = (0, _slicedToArray2["default"])(_useState5, 2), hoveredFieldId = _useState6[0], setHoveredFieldId = _useState6[1]; // The primary field is the field that's visual cues take precedence over any // others given the entire form's focused & hover states. // Use this to control things like error messaging priority. var _useState7 = (0, _react.useState)(undefined), _useState8 = (0, _slicedToArray2["default"])(_useState7, 2), primaryFieldId = _useState8[0], setPrimaryFieldId = _useState8[1]; var _useState9 = (0, _react.useState)(new Set()), _useState10 = (0, _slicedToArray2["default"])(_useState9, 2), blurredFieldIds = _useState10[0], setBlurredFieldIds = _useState10[1]; var _useState11 = (0, _react.useState)(new Set()), _useState12 = (0, _slicedToArray2["default"])(_useState11, 2), erroredFieldIds = _useState12[0], setErroredFieldIds = _useState12[1]; var _useState13 = (0, _react.useState)(false), _useState14 = (0, _slicedToArray2["default"])(_useState13, 2), didAttemptSubmission = _useState14[0], setDidAttemptSubmission = _useState14[1]; (0, _react.useEffect)(function () { if (hoveredFieldId) setPrimaryFieldId(hoveredFieldId);else if (focusedFieldId && erroredFieldIds.has(focusedFieldId)) setPrimaryFieldId(focusedFieldId);else if (erroredFieldIds.size > 0) setPrimaryFieldId(lastInteractionFieldId);else if (focusedFieldId) setPrimaryFieldId(focusedFieldId);else setPrimaryFieldId(undefined); }, [focusedFieldId, hoveredFieldId, lastInteractionFieldId, erroredFieldIds]); // Wrap the submit handler to control form error state once it has been submitted var handleSubmit = (0, _react.useCallback)(function () { setDidAttemptSubmission(true); onSubmit.apply(void 0, arguments); }, [onSubmit]); // There are a lot of pieces of state that can affect the callbacks. Rather // than list each one in every callback which could lead to one being left // out easily, just regenerate the callbacks when any of them change. var callbackRegenValues = [focusedFieldId, lastInteractionFieldId, hoveredFieldId, primaryFieldId, blurredFieldIds, erroredFieldIds, didAttemptSubmission]; var trackErrorsAndValidate = (0, _react.useCallback)(function (_ref4) { var id = _ref4.id, validate = _ref4.validate, value = _ref4.value; var error = validate(value); if (error) { !erroredFieldIds.has(id) && setErroredFieldIds(new Set(erroredFieldIds.add(id))); } else { erroredFieldIds["delete"](id) && setErroredFieldIds(new Set(erroredFieldIds)); } return error; }, callbackRegenValues); var wasFieldTouched = (0, _react.useCallback)(function (id) { return blurredFieldIds.has(id) || didAttemptSubmission; }, callbackRegenValues); var isErrorVisible = (0, _react.useCallback)(function (id) { return wasFieldTouched(id) && erroredFieldIds.has(id); }, callbackRegenValues); var onFocus = (0, _react.useCallback)(function (id) { return setFocusedFieldId(id); }, callbackRegenValues); var onBlur = (0, _react.useCallback)(function (id) { !blurredFieldIds.has(id) && setBlurredFieldIds(blurredFieldIds.add(id)); setLastInteractionFieldId(focusedFieldId); setFocusedFieldId(undefined); }, callbackRegenValues); // We only care about the hover state of previously blurred fields. // We don't want to show error tooltips for fields that haven't been // visited yet. In the case that the form has already had an attempted // submission, all errors will be visible. var onMouseEnter = (0, _react.useCallback)(function (id) { if (isErrorVisible(id)) setHoveredFieldId(id); }, callbackRegenValues); var onMouseLeave = (0, _react.useCallback)(function (id) { if (isErrorVisible(id)) { setLastInteractionFieldId(hoveredFieldId); setHoveredFieldId(undefined); } }, callbackRegenValues); var getError = (0, _react.useCallback)(function (_ref5) { var id = _ref5.id, value = _ref5.value, validate = _ref5.validate; return wasFieldTouched(id) && trackErrorsAndValidate({ id: id, validate: validate, value: value }); }, callbackRegenValues); return /*#__PURE__*/_react["default"].createElement(PureFormErrorState, (0, _extends2["default"])({}, rest, { primaryFieldId: primaryFieldId, onSubmit: handleSubmit, onFocus: onFocus, onBlur: onBlur, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, getError: getError })); }; exports.FormErrorState = FormErrorState;