UNPKG

react-jsonschema-form-validation

Version:
217 lines (197 loc) 7.39 kB
import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties"; import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck"; import _createClass from "@babel/runtime/helpers/esm/createClass"; import _possibleConstructorReturn from "@babel/runtime/helpers/esm/possibleConstructorReturn"; import _getPrototypeOf from "@babel/runtime/helpers/esm/getPrototypeOf"; import _inherits from "@babel/runtime/helpers/esm/inherits"; /** * @import { * ReactNode, * ElementType, * Ref, * FocusEvent, * ForwardRefRenderFunction, * ComponentProps, * ComponentPropsWithRef, * } from 'react' * @import { FormChangeEvent, SafePropsOmit } from '../Form/helpers' * @import { FormContextValue } from '../Form/Context.types' */ import classnames from 'classnames'; import memoize from 'memoize-one'; import React, { PureComponent } from 'react'; import { withFormContext } from '../Form/Context'; /** * Signature of the user-supplied `onChange` handler. It receives the event * and the form's internal handler so the user can decide whether to apply, * transform or skip the update. * * @typedef {( * event: FormChangeEvent, * formHandleFieldChange: FormContextValue['handleFieldChange'], * ) => void} FieldChangeHandler */ /** * Base props of `<Field>` — the validation-specific props handled by the * component itself. The public, polymorphic `FieldProps<C>` extends this * with the props of the underlying component `C`. * * `forwardedRef` is an implementation detail (injected by the outer * `React.forwardRef` wrapper) and is omitted from the public polymorphic * type below. * * @typedef {{ * name: string, * children?: ReactNode, * className?: string, * component?: ElementType, * forwardedRef?: Ref<unknown> | null, * onBlur?: ((event: FocusEvent) => void) | null, * onChange?: FieldChangeHandler | null, * }} FieldBaseProps */ /** * Polymorphic props of `<Field>`. When `component={X}` is supplied, every * prop accepted by `X` is also accepted here (with autocomplete and typo * detection). The default `C = 'input'` matches the runtime default. * * - `name` — path within the form data this field reads/writes. * - `component` — host element or component (default `'input'`). * - `onChange` — user override; receives the raw event plus the form's * internal change handler so the user can decide whether * to apply, transform or skip the update. * - `onBlur` — user override; always fires *after* `form.touch(name)`. * * @template {ElementType} [C = 'input'] * @typedef {( * Omit<FieldBaseProps, 'component' | 'forwardedRef'> * & { component?: C } * & SafePropsOmit<ComponentProps<C>, keyof FieldBaseProps | 'ref'> * )} FieldProps */ /** @extends {PureComponent<FieldBaseProps>} */ var Field = /*#__PURE__*/ function (_PureComponent) { _inherits(Field, _PureComponent); function Field() { var _getPrototypeOf2; var _this; _classCallCheck(this, Field); for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(Field)).call.apply(_getPrototypeOf2, [this].concat(args))); _this.memoGetClassnames = memoize(function ( /** @type {string | undefined} */ className, /** @type {boolean} */ isInvalid, /** @type {boolean} */ isSubmitted, /** @type {boolean} */ isTouched) { return classnames('Jfv_Field', className, { isInvalid: isInvalid, isSubmitted: isSubmitted, isTouched: isTouched }); }); _this.memoGetOnBlurHandler = memoize(function ( /** @type {FormContextValue['touch']} */ touch, /** @type {string} */ name, /** @type {((e: FocusEvent) => void) | null | undefined} */ onBlur) { return ( /** @param {FocusEvent} event */ function (event) { touch(name); if (onBlur) onBlur(event); } ); }); _this.memoGetOnChangeHandler = memoize(function ( /** @type {FieldChangeHandler | null | undefined} */ onChange, /** @type {FormContextValue['handleFieldChange']} */ handleFieldChange) { return ( /** @param {FormChangeEvent} event */ function (event) { if (onChange) { // User-supplied onChange replaces the default behavior. We pass the // form's own update handler so the user can still apply the change // from inside their handler (e.g. after a transformation). onChange(event, handleFieldChange); return; } handleFieldChange(event); } ); }); _this.getClassnames = function (form) { var _this$props = _this.props, className = _this$props.className, name = _this$props.name; var isFieldInvalid = form.isFieldInvalid, isFieldTouched = form.isFieldTouched, isSubmitted = form.isSubmitted; return _this.memoGetClassnames(className, isFieldInvalid(name), isSubmitted, isFieldTouched(name)); }; return _this; } _createClass(Field, [{ key: "render", value: function render() { var _this2 = this; var _this$props2 = this.props, children = _this$props2.children, className = _this$props2.className, _this$props2$componen = _this$props2.component, Component = _this$props2$componen === void 0 ? 'input' : _this$props2$componen, onBlur = _this$props2.onBlur, onChange = _this$props2.onChange, name = _this$props2.name, forwardedRef = _this$props2.forwardedRef, props = _objectWithoutProperties(_this$props2, ["children", "className", "component", "onBlur", "onChange", "name", "forwardedRef"]); return withFormContext(function (form) { return React.createElement(Component, Object.assign({ className: _this2.getClassnames(form), name: name, onBlur: _this2.memoGetOnBlurHandler(form.touch, name, onBlur), onChange: _this2.memoGetOnChangeHandler(onChange, form.handleFieldChange), ref: forwardedRef }, props), children); }); } }]); return Field; }(PureComponent); Field.defaultProps = { children: null, className: '', component: 'input', forwardedRef: null, onBlur: null, onChange: null }; // `React.forwardRef` itself is not generic; the type annotation on the // default export below reinstates the polymorphism so consumers get full // autocomplete and type-checking for the props of the `component` they // pass. `ref` is typed via `ComponentPropsWithRef<C>['ref']` so it matches // the underlying component (e.g. `Ref<HTMLInputElement>` by default, or // the custom handle type when a user component is supplied). var FieldComponent = React.forwardRef( /** @type {ForwardRefRenderFunction<unknown, FieldBaseProps>} */ function (props, ref) { return React.createElement(Field, Object.assign({}, props, { forwardedRef: ref })); }); export default /** @type {<C extends ElementType = 'input'>( props: FieldProps<C> & { ref?: ComponentPropsWithRef<C>['ref'] } ) => JSX.Element | null} */ /** @type {unknown} */ FieldComponent;