@storybook/design-system
Version:
Storybook design system
191 lines (160 loc) • 8.57 kB
JavaScript
;
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;