UNPKG

@sanity/form-builder

Version:
278 lines (276 loc) • 15.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.FormBuilderInput = void 0; var _react = _interopRequireWildcard(require("react")); var _shallowEquals = _interopRequireDefault(require("shallow-equals")); var _changeIndicators = require("@sanity/base/change-indicators"); var _internal = require("@sanity/base/_internal"); var PathUtils = _interopRequireWildcard(require("@sanity/util/paths")); var _generateHelpUrl = require("@sanity/generate-help-url"); var _presence = require("@sanity/base/presence"); var _empty = require("./utils/empty"); var _common = require("./inputs/common"); var _excluded = ["path", "focusPath", "markers"], _excluded2 = ["path", "focusPath", "markers"], _excluded3 = ["readOnly", "_internal_parent"], _excluded4 = ["childFocusPath", "compareValue", "component", "context", "focusPath", "markers", "isRoot", "level", "onBlur", "onChange", "onFocus", "path", "presence", "readOnly", "setInput", "type", "value"]; function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 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; } function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } 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); } function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; } function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); } function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } /* eslint-disable camelcase */ var EMPTY_MARKERS = (0, _empty.emptyArray)(); var EMPTY_PATH = (0, _empty.emptyArray)(); var EMPTY_PRESENCE = (0, _empty.emptyArray)(); var WRAPPER_INNER_STYLES = { minWidth: 0 }; // eslint-disable-next-line @typescript-eslint/no-empty-function var ENABLE_CONTEXT = () => undefined; function getDisplayName(component) { return component.displayName || component.name || 'Unknown'; } class FormBuilderInput extends _react.default.Component { constructor() { super(...arguments); _defineProperty(this, "_element", void 0); _defineProperty(this, "_input", void 0); _defineProperty(this, "scrollTimeout", void 0); _defineProperty(this, "getValuePath", () => { return this.context.getValuePath().concat(this.props.path); }); _defineProperty(this, "setInput", component => { this._input = component; }); _defineProperty(this, "handleChange", patchEvent => { var _this$props = this.props, type = _this$props.type, onChange = _this$props.onChange; if (typeof type.readOnly === 'boolean' && type.readOnly) { return; } onChange(patchEvent); }); _defineProperty(this, "handleFocus", nextPath => { var _this$props2 = this.props, path = _this$props2.path, onFocus = _this$props2.onFocus, focusPath = _this$props2.focusPath; if (!onFocus) { // eslint-disable-next-line no-console console.warn('FormBuilderInput was used without passing a required onFocus prop. Read more at %s.', (0, _generateHelpUrl.generateHelpUrl)('form-builder-input-missing-required-prop')); return; } var nextFocusPath = Array.isArray(nextPath) ? [...path, ...nextPath] : path; if (PathUtils.isEqual(focusPath, nextFocusPath)) { // no change return; } onFocus(nextFocusPath); }); _defineProperty(this, "handleBlur", () => { var onBlur = this.props.onBlur; if (!onBlur) { // eslint-disable-next-line no-console console.warn('FormBuilderInput was used without passing a required onBlur prop. Read more at %s.', (0, _generateHelpUrl.generateHelpUrl)('form-builder-input-missing-required-prop')); return; } onBlur(); }); } getChildContext() { return { getValuePath: this.getValuePath }; } componentDidMount() { var _this$props3 = this.props, focusPath = _this$props3.focusPath, path = _this$props3.path; if (PathUtils.hasFocus(focusPath, path)) { this.focus(); } } shouldComponentUpdate(nextProps) { var _this$props4 = this.props, oldPath = _this$props4.path, oldFocusPath = _this$props4.focusPath, oldMarkers = _this$props4.markers, oldProps = _objectWithoutProperties(_this$props4, _excluded); var newPath = nextProps.path, newFocusPath = nextProps.focusPath, newMarkers = nextProps.markers, newProps = _objectWithoutProperties(nextProps, _excluded2); return !(0, _shallowEquals.default)(oldProps, newProps) || !(0, _shallowEquals.default)(oldPath, newPath) || !(0, _shallowEquals.default)(oldFocusPath, newFocusPath) || !(0, _shallowEquals.default)(oldMarkers, newMarkers); } componentDidUpdate(prevProps) { var hadFocus = PathUtils.hasFocus(prevProps.focusPath, prevProps.path); var hasFocus = PathUtils.hasFocus(this.props.focusPath, this.props.path); if (!hadFocus && hasFocus) { this.focus(); } } componentWillUnmount() { if (this.scrollTimeout) { clearTimeout(this.scrollTimeout); } } resolveInputComponent(type) { var inputComponent = this.props.inputComponent; return inputComponent !== null && inputComponent !== void 0 ? inputComponent : this.context.formBuilder.resolveInputComponent(type); } focus() { var type = this.props.type; if (this._input && typeof this._input.focus === 'function') { this._input.focus(); return; } var inputComponent = this.resolveInputComponent(type); var inputDisplayName = getDisplayName(inputComponent); // no ref if (!this._input) { // eslint-disable-next-line no-console console.warn('The input component for type "%s" has no associated ref element. Please check the implementation of "%s" [%O]. If this is a function component, it must be wrapped in React.forwardRef(). Read more at %s', type.name, inputDisplayName, inputComponent, (0, _generateHelpUrl.generateHelpUrl)('input-component-no-ref')); return; } // eslint-disable-next-line no-console console.warn('The input component for type "%s" is missing a required ".focus()" method. Please check the implementation of "%s" [%O]. Read more at %s', type.name, inputDisplayName, inputComponent, (0, _generateHelpUrl.generateHelpUrl)('input-component-missing-required-method')); } getChildFocusPath() { var _this$props5 = this.props, path = _this$props5.path, focusPath = _this$props5.focusPath; return PathUtils.trimChildPath(path, focusPath); } render() { var _this$props6 = this.props, type = _this$props6.type, _internal_parent = _this$props6._internal_parent, value = _this$props6.value; // Separate readOnly in order to resolve it to a boolean type var _this$props7 = this.props, readOnly = _this$props7.readOnly, _ = _this$props7._internal_parent, restProps = _objectWithoutProperties(_this$props7, _excluded3); var InputComponent = this.resolveInputComponent(type); if (!InputComponent) { return /*#__PURE__*/_react.default.createElement("div", { tabIndex: 0, ref: this.setInput }, "No input resolved for type ", type.name ? JSON.stringify(type.name) : '<unknown type>'); } if (typeof readOnly === 'function' || typeof type.readOnly === 'function') { return /*#__PURE__*/_react.default.createElement(_common.ConditionalReadOnlyField, { parent: _internal_parent, value: value, readOnly: readOnly !== null && readOnly !== void 0 ? readOnly : type.readOnly }, /*#__PURE__*/_react.default.createElement(FormBuilderInputInner, _extends({}, restProps, { childFocusPath: this.getChildFocusPath(), context: this.context, component: InputComponent, onBlur: this.handleBlur, onChange: this.handleChange, onFocus: this.handleFocus, setInput: this.setInput }))); } return /*#__PURE__*/_react.default.createElement(FormBuilderInputInner, _extends({}, restProps, { readOnly: readOnly, childFocusPath: this.getChildFocusPath(), context: this.context, component: InputComponent, onBlur: this.handleBlur, onChange: this.handleChange, onFocus: this.handleFocus, setInput: this.setInput })); } } exports.FormBuilderInput = FormBuilderInput; _defineProperty(FormBuilderInput, "contextTypes", { presence: ENABLE_CONTEXT, formBuilder: ENABLE_CONTEXT, getValuePath: ENABLE_CONTEXT }); _defineProperty(FormBuilderInput, "childContextTypes", { getValuePath: ENABLE_CONTEXT }); _defineProperty(FormBuilderInput, "defaultProps", { focusPath: EMPTY_PATH, path: EMPTY_PATH, markers: EMPTY_MARKERS }); function FormBuilderInputInner(props) { var _useConditionalReadOn; var childFocusPath = props.childFocusPath, compareValue = props.compareValue, InputComponent = props.component, context = props.context, focusPath = props.focusPath, markers = props.markers, isRoot = props.isRoot, level = props.level, onBlur = props.onBlur, onChange = props.onChange, onFocus = props.onFocus, path = props.path, presenceProp = props.presence, readOnly = props.readOnly, setInput = props.setInput, type = props.type, value = props.value, rest = _objectWithoutProperties(props, _excluded4); var conditionalReadOnly = (_useConditionalReadOn = (0, _internal.useConditionalReadOnly)()) !== null && _useConditionalReadOn !== void 0 ? _useConditionalReadOn : readOnly; var presence = presenceProp || context.presence; var childPresenceInfo = (0, _react.useMemo)(() => { if (!presence || presence.length === 0) { return EMPTY_PRESENCE; } return presence.filter(item => PathUtils.startsWith(path, item.path)).map(item => _objectSpread(_objectSpread({}, item), {}, { path: PathUtils.trimChildPath(path, item.path) })); }, [path, presence]); var childMarkers = (0, _react.useMemo)(() => { if (isRoot) return markers; return markers.filter(marker => PathUtils.startsWith(path, marker.path)).map(marker => _objectSpread(_objectSpread({}, marker), {}, { path: PathUtils.trimChildPath(path, marker.path) })); }, [isRoot, markers, path]); var isLeaf = type.jsonType !== 'object' && type.jsonType !== 'array'; var childCompareValue = PathUtils.get(compareValue, path); var inputProps = (0, _react.useMemo)(() => _objectSpread(_objectSpread({}, rest), {}, { focusPath: isLeaf ? undefined : childFocusPath, isRoot, value, compareValue: childCompareValue, readOnly: conditionalReadOnly, markers: childMarkers.length === 0 ? EMPTY_MARKERS : childMarkers, type, presence: childPresenceInfo, onChange, onFocus, onBlur, level, ref: setInput }), [childCompareValue, childFocusPath, childMarkers, childPresenceInfo, isLeaf, isRoot, level, onBlur, onChange, onFocus, conditionalReadOnly, rest, setInput, type, value]); var input = (0, _react.useMemo)(() => /*#__PURE__*/_react.default.createElement(InputComponent, inputProps), [InputComponent, inputProps]); return /*#__PURE__*/_react.default.createElement("div", { "data-testid": path.length === 0 ? 'input-$root' : "input-".concat(PathUtils.toString(path)), style: WRAPPER_INNER_STYLES }, /*#__PURE__*/_react.default.createElement(_presence.FormFieldPresenceContext.Provider, { value: childPresenceInfo }, /*#__PURE__*/_react.default.createElement(_changeIndicators.ChangeIndicatorProvider, { path: path, focusPath: focusPath, value: value, compareValue: childCompareValue }, input))); }