@sanity/form-builder
Version:
Sanity form builder
278 lines (276 loc) • 15.1 kB
JavaScript
"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)));
}