@helpscout/hsds-react
Version:
React component library for Help Scout's Design System
1,310 lines (1,133 loc) • 48.9 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
exports.__esModule = true;
exports.default = exports.EditableField = void 0;
var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose"));
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var _inheritsLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/inheritsLoose"));
var _react = _interopRequireDefault(require("react"));
var _propTypes = _interopRequireDefault(require("prop-types"));
var _fastDeepEqual = _interopRequireDefault(require("fast-deep-equal"));
var _classnames = _interopRequireDefault(require("classnames"));
var _lodash = _interopRequireDefault(require("lodash.isfunction"));
var _lodash2 = _interopRequireDefault(require("lodash.isnil"));
var _EditableField = require("./EditableField.css");
var _EditableField2 = require("./EditableField.constants");
var _EditableField3 = require("./EditableField.Input");
var _EditableField4 = require("./EditableField.Mask");
var _EditableField5 = require("./EditableField.Actions");
var _Icon = _interopRequireDefault(require("../Icon"));
var _getValidProps = _interopRequireDefault(require("@helpscout/react-utils/dist/getValidProps"));
var _EditableField6 = require("./EditableField.utils");
var _Keys = require("../../constants/Keys");
var _node = require("../../utilities/node");
var _jsxRuntime = require("react/jsx-runtime");
function _createForOfIteratorHelperLoose(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (it) return (it = it.call(o)).next.bind(it); if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; return function () { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
function noop() {}
var EditableField = /*#__PURE__*/function (_React$Component) {
(0, _inheritsLoose2.default)(EditableField, _React$Component);
function EditableField(props) {
var _this;
_this = _React$Component.call(this, props) || this;
_this.editableFieldRef = void 0;
_this.setEditableNode = function (node) {
_this.editableFieldRef = node;
_this.props.innerRef(node);
};
_this.assignInputValueToFieldValue = function (_ref) {
var inputValue = _ref.inputValue,
name = _ref.name;
var fieldValue = _this.state.fieldValue;
return fieldValue.map(function (val) {
if (val.id === name) {
return (0, _extends2.default)({}, val, {
value: inputValue,
validated: false
});
}
return val;
});
};
_this.handleInputFocus = function (_ref2) {
var name = _ref2.name,
event = _ref2.event;
var onInputFocus = _this.props.onInputFocus;
var fieldValue = _this.state.fieldValue; // There is a bug in Safari as of version 14.0.1 where a second focus event
// is being received on inputs. The bug is not fixed in the technology
// preview of 14.1.0 either. It would appear that Safari has had an on-again
// off-again issue with focus events.
// See: https://github.com/facebook/react/issues/10871
// See: https://bugs.webkit.org/show_bug.cgi?id=179990
// In the case where this happens, the second focus event will have a
// secondary target. If we have an EditableField, the secondary target
// will be the field mask. If we have an EditableFieldComposite, the
// secondary target will be the composed mask. Otherwise the secondary
// target will be null or another element in the case of tab navigation.
var isSafari = function isSafari() {
if (!navigator) return false;
var ua = navigator.userAgent.toLowerCase();
return !ua.includes('chrome') && ua.includes('safari');
};
var maskIsSecondaryTarget = !!event.relatedTarget && (event.relatedTarget.classList.contains('FieldMask__value') || event.relatedTarget.classList.contains('ComposedMask'));
if (isSafari() && maskIsSecondaryTarget) {
event.target.blur();
return;
}
_this.setState({
activeField: name,
maskTabIndex: null
}, function () {
onInputFocus({
name: name,
value: fieldValue,
event: event
});
});
};
_this.handleInputBlur = function (payload) {
var name = payload.name,
event = payload.event;
var _this$state = _this.state,
activeField = _this$state.activeField,
multipleValuesEnabled = _this$state.multipleValuesEnabled,
valueOptions = _this$state.valueOptions;
var _this$props = _this.props,
validate = _this$props.validate,
onCommit = _this$props.onCommit,
onDiscard = _this$props.onDiscard,
onInputBlur = _this$props.onInputBlur;
var hasOptions = !(0, _lodash2.default)(valueOptions);
var changedField = _this.state.fieldValue.length === 1 ? _this.state.fieldValue[0] : _this.state.fieldValue.find(function (val) {
return "" + val.id === event.target.id;
});
var initialField = _this.state.initialFieldValue.length === 1 ? _this.state.initialFieldValue[0] : _this.state.initialFieldValue.find(function (val) {
return "" + val.id === event.target.id;
});
if ((0, _fastDeepEqual.default)(_this.state.initialFieldValue, _this.state.fieldValue) || (0, _fastDeepEqual.default)(initialField, changedField) || _this.state.disabledItem.indexOf(changedField.id) !== -1) {
// On multiple value fields, if we jump from one input to another
// of the same EditableField, all we want is to fire onInputBlur
var parentSelector = "[data-field-id=\"ef_" + _this.props.name + "\"]";
var nextElHasSameParent = (0, _node.nodesHaveSameParent)(parentSelector, event.relatedTarget, event.target);
if (nextElHasSameParent) {
onInputBlur({
name: name,
value: _this.state.fieldValue,
event: event
});
return;
}
_this.setState({
activeField: _EditableField2.EMPTY_VALUE
}, function () {
onInputBlur({
name: name,
value: _this.state.fieldValue,
event: event
});
});
return;
}
var removedEmptyFields = _this.state.fieldValue.filter(function (field) {
return Boolean(field.value);
}); // In multivalue fields, remove the empty one when there're at least 2 fields
var shouldDiscardEmpty = multipleValuesEnabled && removedEmptyFields.length < _this.state.fieldValue.length;
if (shouldDiscardEmpty) {
var deletedField; // if the last visible field has been removed, remove its _id property before
// updating the internal state for 'fieldValue' so it accurately represents an
// empty field. If _id exists on an otherwise empty field property, it will
// force a PUT api call instead of a POST if the user tries to create a new item.
if (removedEmptyFields.length === 0) {
deletedField = (0, _extends2.default)({}, changedField);
delete deletedField._id;
}
_this.setState({
activeField: _EditableField2.EMPTY_VALUE,
disabledItem: _this.state.disabledItem.filter(function (item) {
return item !== changedField.id;
}),
fieldValue: removedEmptyFields.length > 0 ? removedEmptyFields : [deletedField],
initialFieldValue: _this.state.fieldValue
}, function () {
onCommit({
name: name,
value: _this.state.fieldValue,
data: {
cause: _EditableField2.CAUSE.BLUR,
operation: _EditableField2.OPERATION.DELETE,
item: changedField
}
});
onDiscard({
value: _this.state.fieldValue
});
onInputBlur({
name: name,
value: _this.state.fieldValue,
event: event
});
});
return;
}
var optionChanged = hasOptions && initialField ? initialField.option !== changedField.option : false;
if (!changedField.validated || optionChanged) {
_this.setState({
disabledItem: _this.state.disabledItem.concat(changedField.id)
}); // Get the next values and commit prior to validation so that
// we can use it in validation.
var updatedFieldValue = _this.state.fieldValue.map(function (field) {
// tested
if (field.id === changedField.id) {
return (0, _extends2.default)({}, changedField, {
validated: true
});
} // tested
return field;
}); // Allow references to this event to be maintained in the async
// code that follows.
event && event.persist && event.persist();
validate({
data: {
cause: _EditableField2.CAUSE.BLUR,
operation: updatedFieldValue.length > _this.state.initialFieldValue.length ? _EditableField2.OPERATION.CREATE : _EditableField2.OPERATION.UPDATE,
item: changedField
},
name: changedField.id,
value: changedField.value,
values: updatedFieldValue
}).then(function (validation) {
// Since this is async and the state of other fields may have changed,
// we need to recompute this.
updatedFieldValue = _this.state.fieldValue.map(function (field) {
// tested
if (field.id === changedField.id) {
var updatedProps = validation.isValid && validation.updatedProps ? validation.updatedProps : {};
return (0, _extends2.default)({}, changedField, {
validated: true
}, updatedProps);
} // tested
return field;
});
if (validation.isValid) {
// 1. Non-empty Value
if (changedField.value) {
_this.setState({
disabledItem: _this.state.disabledItem.filter(function (item) {
return item !== changedField.id;
}),
fieldValue: updatedFieldValue,
initialFieldValue: updatedFieldValue,
validationInfo: _this.state.validationInfo.filter(function (valItem) {
return valItem.name !== changedField.id;
})
}, function () {
onCommit({
name: name,
value: _this.state.fieldValue,
data: {
cause: _EditableField2.CAUSE.BLUR,
operation: updatedFieldValue.length > _this.state.initialFieldValue.length ? _EditableField2.OPERATION.CREATE : _EditableField2.OPERATION.UPDATE,
item: changedField
}
});
onInputBlur({
name: name,
value: _this.state.fieldValue,
event: event
});
/**
* Managing "Active Field"
*
* One consequence of the 'blur' activity being _always_ async (the result of being executed inside a Promise)
* is that the normal sequence of events is no longer executed in the "regular" flow.
*
* Sync (previous behaviour):
* 1. blur (sets activeField to '')
* 2. focus (sets activeField to whatever input was focused)
*
* Async (current behaviour):
* 1. blur ...validation Promise...
* 2. focus (sets activeField to whatever input was focused)
* 3. ...validation Promise comes back... blur sets activeField to '' <=== DAMN!
*
* To get back the correct behaviour, we leave 'focus' as is, which will _always_ set the activeField
* to the focused input. With that info, we can update the active field _after_ the blur
* setState, knowing that if the activeState in the state is different from what we had before
* it means the focus event kicked in.
*
* In multiple value EFs, We also need to check if the next element that receives focus is part of the
* same group.
*/
var unchangedByFocusEvent = _this.state.activeField === activeField;
var parentSelector = "[data-field-id=\"ef_" + _this.props.name + "\"]";
var nextElHasSameParent = (0, _node.nodesHaveSameParent)(parentSelector, event.relatedTarget, event.target);
if (!nextElHasSameParent) {
_this.setState({
activeField: unchangedByFocusEvent ? _EditableField2.EMPTY_VALUE : _this.state.activeField
});
}
});
} else {
// 2. Empty value
// If single value or multivalue field with just one value, clear the field but don't remove it
_this.setState({
activeField: _EditableField2.EMPTY_VALUE,
disabledItem: _this.state.disabledItem.filter(function (item) {
return item !== changedField.id;
}),
fieldValue: _this.state.fieldValue,
initialFieldValue: _this.state.fieldValue
}, function () {
onCommit({
name: name,
value: _this.state.fieldValue,
data: {
cause: _EditableField2.CAUSE.BLUR,
operation: _EditableField2.OPERATION.UPDATE,
item: _this.state.fieldValue.filter(function (field) {
return !Boolean(field.value);
})[0]
}
});
onInputBlur({
name: name,
value: _this.state.fieldValue,
event: event
});
});
}
} else {
_this.setState({
disabledItem: _this.state.disabledItem.filter(function (item) {
return item !== changedField.id;
}),
fieldValue: updatedFieldValue,
validationInfo: _this.state.validationInfo.concat(validation)
}, function () {
onInputBlur({
name: name,
value: _this.state.fieldValue,
event: event
});
});
}
}).catch(function () {
_this.setState({
disabledItem: _this.state.disabledItem.filter(function (item) {
return item !== name;
})
}, function () {
return _this.handleFieldEscapePress({
event: event,
name: name
});
});
});
return;
}
};
_this.handleInputChange = function (_ref3) {
var inputValue = _ref3.inputValue,
name = _ref3.name,
event = _ref3.event;
var onChange = _this.props.onChange;
var newFieldValue = _this.assignInputValueToFieldValue({
inputValue: inputValue,
name: name
});
_this.setState({
fieldValue: newFieldValue,
validationInfo: _this.state.validationInfo.filter(function (valItem) {
return valItem.name !== name;
})
}, function () {
onChange({
name: name,
value: newFieldValue,
event: event
});
});
};
_this.handleInputKeyDown = function (_ref4) {
var event = _ref4.event,
name = _ref4.name;
var isEnter = event.key === _Keys.key.ENTER;
var isEscape = event.key === _Keys.key.ESCAPE;
var value = _this.state.fieldValue;
_this.props.onInputKeyDown({
name: name,
value: value,
event: event
});
if (isEnter) {
return _this.handleFieldEnterPress({
event: event,
name: name
});
} else if (isEscape) {
return _this.handleFieldEscapePress({
event: event,
name: name
});
}
return new Promise(function (resolve, reject) {
reject();
});
};
_this.handleInputKeyPress = function (_ref5) {
var name = _ref5.name,
event = _ref5.event;
var value = _this.state.fieldValue;
_this.props.onInputKeyPress({
name: name,
value: value,
event: event
});
};
_this.handleInputKeyUp = function (_ref6) {
var name = _ref6.name,
event = _ref6.event;
var value = _this.state.fieldValue;
_this.props.onInputKeyUp({
name: name,
value: value,
event: event
});
};
_this.handleFieldEnterPress = function (_ref7) {
var event = _ref7.event,
name = _ref7.name;
var _this$props2 = _this.props,
validate = _this$props2.validate,
onEnter = _this$props2.onEnter,
onCommit = _this$props2.onCommit;
var _this$state2 = _this.state,
initialFieldValue = _this$state2.initialFieldValue,
fieldValue = _this$state2.fieldValue,
multipleValuesEnabled = _this$state2.multipleValuesEnabled;
var inputValue = event.currentTarget.value;
var impactedField = initialFieldValue.find(function (val) {
return val.id === name;
});
var valueDidNotChange = impactedField && inputValue === impactedField.value;
return new Promise(function (resolve) {
var cachedEvent = (0, _extends2.default)({}, event); // Case 1: in multi-value fields if value is empty
// Do nothing
if (multipleValuesEnabled && inputValue === _EditableField2.EMPTY_VALUE) {
return;
} // Case 2: value was not changed
// Just change active status
else if (valueDidNotChange) {
_this.setState({
activeField: _EditableField2.EMPTY_VALUE,
maskTabIndex: name
}, function () {
resolve();
onEnter({
name: name,
value: fieldValue,
event: cachedEvent
});
});
} else {
// Case 3: value was changed
var _impactedField = fieldValue.find(function (val) {
return val.id === name;
}); // Get the next values and commit prior to validation so that
// we can use it in validation.
var updatedFieldValue = _this.updateFieldValue({
name: name,
value: inputValue
}); // Skip if the field was marked as validated
if (!_impactedField.validated) {
_this.setState({
disabledItem: _this.state.disabledItem.concat(name)
}); // Allow references to this event to be maintained in the async
// code that follows.
event && event.persist && event.persist();
validate({
data: {
cause: _EditableField2.CAUSE.ENTER,
operation: updatedFieldValue.length > initialFieldValue.length ? _EditableField2.OPERATION.CREATE : _EditableField2.OPERATION.UPDATE,
item: updatedFieldValue.filter(function (field) {
return field.id === name;
})[0]
},
name: name,
value: inputValue,
values: updatedFieldValue
}).then(function (validation) {
if (validation.isValid) {
// Since this is async and the state of other fields may have changed,
// we need to recompute this.
updatedFieldValue = _this.updateFieldValue({
name: name,
value: inputValue,
updatedProps: validation.updatedProps || {}
});
_this.setState({
activeField: _EditableField2.EMPTY_VALUE,
disabledItem: _this.state.disabledItem.filter(function (item) {
return item !== name;
}),
fieldValue: updatedFieldValue,
initialFieldValue: updatedFieldValue,
maskTabIndex: name,
validationInfo: _this.state.validationInfo.filter(function (valItem) {
return valItem.name === name;
})
}, function () {
resolve();
onCommit({
name: name,
value: updatedFieldValue,
data: {
cause: _EditableField2.CAUSE.ENTER,
operation: updatedFieldValue.length > initialFieldValue.length ? _EditableField2.OPERATION.CREATE : _EditableField2.OPERATION.UPDATE,
item: updatedFieldValue.filter(function (field) {
return field.id === name;
})[0]
}
});
onEnter({
name: name,
value: updatedFieldValue,
event: cachedEvent
});
});
} else {
updatedFieldValue = fieldValue.map(function (field) {
if (field.id === name) {
return (0, _extends2.default)({}, field, {
validated: true
});
}
return field;
});
_this.setState({
activeField: name,
disabledItem: _this.state.disabledItem.filter(function (item) {
return item !== name;
}),
fieldValue: updatedFieldValue,
validationInfo: _this.state.validationInfo.concat(validation)
}, function () {
resolve();
onEnter({
name: name,
value: updatedFieldValue,
event: cachedEvent
});
});
}
}).catch(function () {
_this.setState({
disabledItem: _this.state.disabledItem.filter(function (item) {
return item !== name;
})
}, function () {
return _this.handleFieldEscapePress({
event: event,
name: name
});
});
});
}
}
});
};
_this.updateFieldValue = function (_ref8) {
var value = _ref8.value,
name = _ref8.name,
_ref8$updatedProps = _ref8.updatedProps,
updatedProps = _ref8$updatedProps === void 0 ? {} : _ref8$updatedProps;
var fieldValue = _this.state.fieldValue;
return fieldValue.map(function (val) {
if (val.id === name) {
return (0, _extends2.default)({}, val, updatedProps, {
value: value,
validated: true
});
}
return val;
});
};
_this.handleFieldEscapePress = function (_ref9) {
var event = _ref9.event,
name = _ref9.name;
var _this$props3 = _this.props,
onEscape = _this$props3.onEscape,
onDiscard = _this$props3.onDiscard;
var initialFieldValue = _this.state.initialFieldValue;
var cachedEvent = (0, _extends2.default)({}, event);
return new Promise(function (resolve) {
// Change active status and return fieldValue to initialValue
_this.setState({
activeField: _EditableField2.EMPTY_VALUE,
fieldValue: initialFieldValue,
maskTabIndex: name
}, function () {
resolve();
onEscape({
name: name,
value: initialFieldValue,
event: cachedEvent
});
onDiscard({
value: initialFieldValue
});
});
});
};
_this.handleMaskValueKeyDown = function (_ref10) {
var event = _ref10.event,
name = _ref10.name;
var isEnter = event.key === _Keys.key.ENTER;
var isEscape = event.key === _Keys.key.ESCAPE;
if (isEnter || isEscape) {
_this.setState({
maskTabIndex: null
}, function () {
var inputNode = document.getElementById(name);
isEnter && inputNode && inputNode.focus();
});
}
};
_this.handleOptionFocus = function (_ref11) {
var name = _ref11.name,
event = _ref11.event;
var onOptionFocus = _this.props.onOptionFocus;
_this.setState({
activeField: name
}, function () {
onOptionFocus({
name: name,
value: _this.state.fieldValue,
event: event
});
});
};
_this.handleOptionSelection = function (_ref12) {
var name = _ref12.name,
selection = _ref12.selection;
var _this$props4 = _this.props,
onChange = _this$props4.onChange,
onOptionChange = _this$props4.onOptionChange,
onCommit = _this$props4.onCommit;
var fieldValue = _this.state.fieldValue;
var newFieldValue = [];
var changed = false;
var hasBeenValidated = '';
var label = typeof selection === 'string' ? selection : selection.label;
for (var _iterator = _createForOfIteratorHelperLoose(fieldValue), _step; !(_step = _iterator()).done;) {
var value = _step.value;
var temp = (0, _extends2.default)({}, value);
if (temp.id === name && temp.option !== label) {
temp.option = label;
changed = true;
}
if (temp.id === name && temp.validated) {
hasBeenValidated = temp.id;
}
newFieldValue.push(temp);
}
if (changed) {
var isItemInvalid;
if (hasBeenValidated !== '') {
isItemInvalid = _this.state.validationInfo.find(function (val) {
return val.name === hasBeenValidated;
});
}
var item = newFieldValue.filter(function (field) {
return field.id === name;
})[0];
_this.setState({
fieldValue: newFieldValue,
activeField: name
}, function () {
if (!isItemInvalid && item.value !== '') {
onCommit({
name: name,
value: newFieldValue,
data: {
cause: _EditableField2.CAUSE.OPTION_SELECTION,
operation: _EditableField2.OPERATION.UPDATE,
item: item
}
});
}
onOptionChange({
name: name,
selection: selection,
value: newFieldValue
});
onChange({
name: name,
value: newFieldValue
});
});
}
};
_this.handleAddValue = function () {
var onAdd = _this.props.onAdd;
var _this$state3 = _this.state,
fieldValue = _this$state3.fieldValue,
defaultOption = _this$state3.defaultOption;
var isNotSingleEmptyValue = fieldValue[fieldValue.length - 1].value !== _EditableField2.EMPTY_VALUE;
if (isNotSingleEmptyValue) {
var name = _this.props.name;
var newValueObject = (0, _EditableField6.createNewValueFieldObject)(_EditableField2.EMPTY_VALUE, name, defaultOption);
var newFieldValue = fieldValue.concat(newValueObject);
var newState = {
fieldValue: newFieldValue,
activeField: newValueObject.id
};
_this.setState(newState, function () {
onAdd({
name: name,
value: newFieldValue
});
});
}
};
_this.handleDeleteAction = function (_ref13) {
var action = _ref13.action,
name = _ref13.name,
event = _ref13.event;
var _this$props5 = _this.props,
onCommit = _this$props5.onCommit,
onDelete = _this$props5.onDelete;
var _this$state4 = _this.state,
defaultOption = _this$state4.defaultOption,
fieldValue = _this$state4.fieldValue;
var cachedEvent = (0, _extends2.default)({}, event);
var updatedFieldValue = []; // Clearing value
// When there is only one item in the fieldValue array
if (fieldValue.length === 1) {
var emptyValue = {
// The id is the input id and we will need to keep this to recycle
// the field, but we need to drop all other data associated with it.
id: fieldValue[0].id,
value: _EditableField2.EMPTY_VALUE,
validated: false
};
if (!(0, _lodash2.default)(defaultOption)) {
emptyValue.option = defaultOption;
}
updatedFieldValue = [emptyValue];
} else {
// Deleting value
// Remove the item from the array
updatedFieldValue = fieldValue.filter(function (val) {
return val.id !== name;
});
}
_this.setState({
fieldValue: updatedFieldValue,
initialFieldValue: updatedFieldValue
}, function () {
onDelete({
name: name,
value: _this.state.fieldValue,
event: event
});
onCommit({
name: name,
value: _this.state.fieldValue,
data: {
cause: _EditableField2.CAUSE.DELETE_ACTION,
operation: _EditableField2.OPERATION.DELETE,
item: fieldValue.filter(function (field) {
return field.id === name;
})[0]
}
});
if ((0, _lodash.default)(action.callback)) {
action.callback({
name: name,
action: action,
value: fieldValue,
event: cachedEvent
});
}
});
};
_this.handleCustomAction = function (_ref14) {
var action = _ref14.action,
name = _ref14.name,
event = _ref14.event;
var fieldValue = _this.state.fieldValue;
if ((0, _lodash.default)(action.callback)) {
action.callback({
name: name,
action: action,
value: fieldValue,
event: event
});
}
};
_this.renderAddButton = function () {
var _this$props6 = _this.props,
disabled = _this$props6.disabled,
addButtonProps = _this$props6.addButtonProps;
var _this$state5 = _this.state,
fieldValue = _this$state5.fieldValue,
multipleValuesEnabled = _this$state5.multipleValuesEnabled;
var className = addButtonProps.className,
onClick = addButtonProps.onClick,
rest = (0, _objectWithoutPropertiesLoose2.default)(addButtonProps, ["className", "onClick"]);
var isLastValueEmpty = fieldValue[fieldValue.length - 1].value === _EditableField2.EMPTY_VALUE;
var isSingleAndEmpty = fieldValue.length === 1 && isLastValueEmpty;
var invalidValuePresent = _this.state.validationInfo.filter(function (valItem) {
return !valItem.isValid;
}).length > 0;
return multipleValuesEnabled && !isSingleAndEmpty && !disabled ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_EditableField.AddButtonUI, (0, _extends2.default)({
className: (0, _classnames.default)(_EditableField6.EDITABLEFIELD_CLASSNAMES.addButton, className),
type: "button",
onClick: (0, _lodash2.default)(onClick) ? _this.handleAddValue : function (e) {
onClick(e);
_this.handleAddValue();
},
disabled: isLastValueEmpty || invalidValuePresent
}, rest, {
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.default, {
name: _EditableField2.ACTION_ICONS.plus,
size: "24"
})
})) : null;
};
_this.renderFields = function () {
var _this$props7 = _this.props,
name = _this$props7.name,
disabled = _this$props7.disabled,
emphasizeTopValue = _this$props7.emphasizeTopValue,
type = _this$props7.type,
rest = (0, _objectWithoutPropertiesLoose2.default)(_this$props7, ["name", "disabled", "emphasizeTopValue", "type"]);
var _this$state6 = _this.state,
actions = _this$state6.actions,
activeField = _this$state6.activeField,
disabledItem = _this$state6.disabledItem,
fieldValue = _this$state6.fieldValue,
maskTabIndex = _this$state6.maskTabIndex,
multipleValuesEnabled = _this$state6.multipleValuesEnabled,
valueOptions = _this$state6.valueOptions;
return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
className: _EditableField6.EDITABLEFIELD_CLASSNAMES.fieldWrapper,
children: [fieldValue.map(function (val, index) {
var isActive = activeField === val.id;
var isDisabled = disabled || val.disabled || _this.state.disabledItem.includes(val.id);
var valInfo = _this.state.validationInfo.find(function (valItem) {
return valItem.name === val.id;
});
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_EditableField.FieldUI, {
className: (0, _classnames.default)(_EditableField6.EDITABLEFIELD_CLASSNAMES.field, isDisabled && _EditableField6.STATES_CLASSNAMES.fieldDisabled, isActive && _EditableField6.STATES_CLASSNAMES.isActive, valueOptions && _EditableField6.STATES_CLASSNAMES.hasOptions, !Boolean(val.value) && _EditableField6.STATES_CLASSNAMES.isEmpty),
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_EditableField3.EditableFieldInput, (0, _extends2.default)({}, (0, _getValidProps.default)(rest), {
actions: actions,
disabled: isDisabled,
fieldValue: val,
isActive: isActive,
name: val.id,
type: type,
validationInfo: valInfo,
valueOptions: valueOptions,
onInputFocus: _this.handleInputFocus,
onInputBlur: _this.handleInputBlur,
onOptionFocus: _this.handleOptionFocus,
onOptionSelection: _this.handleOptionSelection,
onChange: _this.handleInputChange,
onKeyDown: _this.handleInputKeyDown,
onKeyPress: _this.handleInputKeyPress,
onKeyUp: _this.handleInputKeyUp
})), /*#__PURE__*/(0, _jsxRuntime.jsx)(_EditableField4.EditableFieldMask, (0, _extends2.default)({}, (0, _getValidProps.default)(rest), {
actions: actions,
disabled: isDisabled,
emphasize: multipleValuesEnabled && emphasizeTopValue && index === 0,
fieldValue: val,
maskTabIndex: maskTabIndex,
name: val.id,
type: type,
valueOptions: valueOptions,
validationInfo: valInfo,
onValueKeyDown: _this.handleMaskValueKeyDown
})), actions && Boolean(val.value) && disabledItem.indexOf(val.id) === -1 && !disabled ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_EditableField5.EditableFieldActions, {
actions: actions,
fieldValue: val,
name: val.id,
customAction: _this.handleCustomAction,
deleteAction: _this.handleDeleteAction,
validationInfo: valInfo
}) : null]
}, val.id);
}), _this.renderAddButton()]
});
};
_this.renderFieldsInline = function () {
var _this$props8 = _this.props,
name = _this$props8.name,
inline = _this$props8.inline,
type = _this$props8.type,
rest = (0, _objectWithoutPropertiesLoose2.default)(_this$props8, ["name", "inline", "type"]);
var _this$state7 = _this.state,
activeField = _this$state7.activeField,
fieldValue = _this$state7.fieldValue;
return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
className: _EditableField6.EDITABLEFIELD_CLASSNAMES.fieldWrapper,
children: fieldValue.map(function (val) {
var isActive = activeField === val.id;
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_EditableField.FieldUI, {
className: (0, _classnames.default)(_EditableField6.EDITABLEFIELD_CLASSNAMES.field, isActive && _EditableField6.STATES_CLASSNAMES.isActive, !Boolean(val.value) && _EditableField6.STATES_CLASSNAMES.isEmpty),
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_EditableField3.EditableFieldInput, (0, _extends2.default)({}, (0, _getValidProps.default)(rest), {
disabled: false,
fieldValue: val,
isActive: isActive,
inline: inline,
name: val.id,
type: type,
onInputFocus: _this.handleInputFocus,
onInputBlur: _this.handleInputBlur,
onOptionFocus: _this.handleOptionFocus,
onOptionSelection: _this.handleOptionSelection,
onChange: _this.handleInputChange,
onKeyDown: _this.handleInputKeyDown
}))
}, val.id);
})
});
};
var _actions = props.actions,
_name = props.name,
_defaultOption = props.defaultOption,
multipleValues = props.multipleValues,
_value = props.value,
_valueOptions = props.valueOptions;
var defaultStateOption = null;
if (_valueOptions) {
defaultStateOption = _defaultOption ? _defaultOption : _valueOptions[0];
}
var _initialFieldValue = (0, _EditableField6.normalizeFieldValue)({
value: _value,
name: _name,
defaultOption: defaultStateOption
});
_this.state = {
actions: (0, _EditableField6.generateFieldActions)(_actions),
activeField: _EditableField2.EMPTY_VALUE,
defaultOption: defaultStateOption,
disabledItem: [],
fieldValue: _initialFieldValue,
initialFieldValue: _initialFieldValue,
maskTabIndex: null,
multipleValuesEnabled: Array.isArray(_value) || multipleValues,
valueOptions: _valueOptions && Array.isArray(_valueOptions) ? _valueOptions.map(function (option) {
return {
id: option,
label: option,
value: option
};
}) : null,
validationInfo: []
};
return _this;
}
var _proto = EditableField.prototype;
_proto.shouldComponentUpdate = function shouldComponentUpdate(nextProps, nextState) {
if (!(0, _fastDeepEqual.default)(this.props.value, nextProps.value)) {
return true;
}
if (this.props.disabled !== nextProps.disabled) {
return true;
}
if (!(0, _fastDeepEqual.default)(this.state.fieldValue, nextState.fieldValue)) {
return true;
}
if (this.state.activeField !== nextState.activeField) {
return true;
}
if (this.state.maskTabIndex !== nextState.maskTabIndex) {
return true;
}
if (!(0, _fastDeepEqual.default)(this.state.disabledItem, nextState.disabledItem)) {
return true;
} // Tested
if (!(0, _fastDeepEqual.default)(this.state.validationInfo, nextState.validationInfo)) {
return true;
}
return false;
};
_proto.UNSAFE_componentWillReceiveProps = function UNSAFE_componentWillReceiveProps(nextProps) {
if ((0, _fastDeepEqual.default)(nextProps.value, this.props.value)) return;
var name = nextProps.name,
defaultOption = nextProps.defaultOption,
value = nextProps.value,
valueOptions = nextProps.valueOptions;
var defaultStateOption = null; // tested
if (valueOptions) {
defaultStateOption = defaultOption ? defaultOption : valueOptions[0];
}
var initialFieldValue = (0, _EditableField6.normalizeFieldValue)({
value: value,
name: name,
defaultOption: defaultStateOption,
currentFieldValue: this.state.fieldValue
});
if (!(0, _fastDeepEqual.default)(initialFieldValue, this.state.fieldValue)) {
this.setState({
fieldValue: initialFieldValue,
initialFieldValue: initialFieldValue
});
}
};
_proto.getClassName = function getClassName() {
var _this$props9 = this.props,
className = _this$props9.className,
size = _this$props9.size,
disabled = _this$props9.disabled,
floatingLabels = _this$props9.floatingLabels;
return (0, _classnames.default)(EditableField.className, className, disabled && _EditableField6.STATES_CLASSNAMES.fieldDisabled, size === _EditableField2.FIELDSIZES.lg && _EditableField6.STATES_CLASSNAMES.isLarge, floatingLabels && _EditableField6.STATES_CLASSNAMES.withFloatingLabels);
};
_proto.render = function render() {
var _this$props10 = this.props,
disabled = _this$props10.disabled,
floatingLabels = _this$props10.floatingLabels,
inline = _this$props10.inline,
label = _this$props10.label,
placeholder = _this$props10.placeholder,
name = _this$props10.name,
type = _this$props10.type,
value = _this$props10.value,
rest = (0, _objectWithoutPropertiesLoose2.default)(_this$props10, ["disabled", "floatingLabels", "inline", "label", "placeholder", "name", "type", "value"]);
var fieldValue = this.state.fieldValue;
if (inline) {
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_EditableField.EditableFieldUI, (0, _extends2.default)({}, (0, _getValidProps.default)(rest), {
"data-field-id": "ef_" + name,
className: this.getClassName(),
ref: this.setEditableNode,
inline: true,
children: this.renderFieldsInline()
}));
}
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_EditableField.EditableFieldUI, (0, _extends2.default)({}, (0, _getValidProps.default)(rest), {
"data-field-id": "ef_" + name,
className: this.getClassName(),
ref: this.setEditableNode,
children: [!floatingLabels ? /*#__PURE__*/(0, _jsxRuntime.jsx)("label", {
className: _EditableField6.EDITABLEFIELD_CLASSNAMES.label,
htmlFor: fieldValue[0].id,
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_EditableField.LabelTextUI, {
className: _EditableField6.EDITABLEFIELD_CLASSNAMES.labelText,
children: label || name
})
}) : null, this.renderFields()]
}));
};
return EditableField;
}(_react.default.Component);
exports.EditableField = EditableField;
EditableField.className = _EditableField6.EDITABLEFIELD_CLASSNAMES.component;
EditableField.defaultProps = {
addButtonProps: {},
'data-cy': 'EditableField',
defaultOption: null,
disabled: false,
emphasizeTopValue: false,
floatingLabels: false,
inline: false,
multipleValues: false,
size: _EditableField2.FIELDSIZES.md,
value: _EditableField2.EMPTY_VALUE,
innerRef: noop,
onAdd: noop,
onChange: noop,
onCommit: noop,
onDelete: noop,
onDiscard: noop,
onEnter: noop,
onEscape: noop,
onInputBlur: noop,
onInputFocus: noop,
onInputKeyDown: noop,
onInputKeyPress: noop,
onInputKeyUp: noop,
onOptionBlur: noop,
onOptionChange: noop,
onOptionFocus: noop,
type: _EditableField2.FIELDTYPES.text,
validate: function validate() {
return Promise.resolve({
isValid: true
});
}
};
EditableField.propTypes = {
/** Actions to attach to an EditableField (default includes 'delete') */
actions: _propTypes.default.any,
/** Add custom attributes to the add button on multiple value fields */
addButtonProps: _propTypes.default.object,
/** The className of the component. */
className: _propTypes.default.string,
/** If the EditableField is “option-enabled” by using the valueOptions array, the user can provide which of the options should be the default, if non provided, EditableField will choose the first option in the valueOptions array. */
defaultOption: _propTypes.default.any,
/** Disable the field */
disabled: _propTypes.default.bool,
/** In multi-value fields, bold the first value (to visually denote the default value, on a list of emails for example) */
emphasizeTopValue: _propTypes.default.bool,
/** Uses the "floating label" pattern with animation */
floatingLabels: _propTypes.default.bool,
/** Renders fields inline */
inline: _propTypes.default.bool,
/** The text for the EditableField label */
label: _propTypes.default.string,
/** If you want to force a multi-value field, set this to `true` */
multipleValues: _propTypes.default.bool,
/** The **unique** identifier for the EditableField - Ties label with input - Used to generate React `keys` - Used to manage correct handling (adding, deleting, editing) of multiple-value fields */
name: _propTypes.default.string,
/** Text for the placholder */
placeholder: _propTypes.default.string,
/** Field size */
size: _propTypes.default.oneOf(['md', 'lg']),
/** The type of field, one of 'text', 'email', 'url', 'tel' , 'number’, 'password' */
type: _propTypes.default.oneOf(['text', 'email', 'url', 'tel', 'number', 'password']),
/** Initial value for the EditableField, user will normally provide a string or array of strings (in case multi-value enabled fields) which internally get converted to `FieldValues` */
value: _propTypes.default.any,
/** When the user wants a field with “options” (like “home”, “work” options for phone numbers) she passes an array of strings with the available options. EditableField will make sure to show the appropriate dropdown. The array of strings internally gets converted to an array of `Option`. `Option` type is the same as what Dropdown V2 accepts as items. */
valueOptions: _propTypes.default.any,
/** Function that validates the value, should always return a Promise that resolves to a Validation type */
validate: _propTypes.default.func,
/** Retrieve the inner DOM node. */
innerRef: _propTypes.default.func,
/** Fired when the input is focused */
onInputFocus: _propTypes.default.func,
/** Fired when the input is blurred */
onInputBlur: _propTypes.default.func,
/** Fired on the appropriate keyboard event */
onInputKeyDown: _propTypes.default.func,
/** Fired on the appropriate keyboard event */
onInputKeyPress: _propTypes.default.func,
/** Fired on the appropriate keyboard event */
onInputKeyUp: _propTypes.default.func,
/** Fired when the option trigger is focused */
onOptionFocus: _propTypes.default.func,
/** Fired when the option trigger is blurred */
onOptionBlur: _propTypes.default.func,
/** Fires when an option is changed/selected */
onOptionChange: _propTypes.default.func,
/** Fires when either the input or an option is changed */
onChange: _propTypes.default.func,
/** Fires when Enter is pressed on the input */
onEnter: _propTypes.default.func,
/** Fires when Escape is pressed on the input */
onEscape: _propTypes.default.func,
/** Fires when a value is added on multi-value fields */
onAdd: _propTypes.default.func,
/** Fires when a change is "saved" */
onCommit: _propTypes.default.func,
/** Fires on clearing or deleting a value */
onDelete: _propTypes.default.func,
/** Fires on discarding a value */
onDiscard: _propTypes.default.func,
/** Data attr for Cypress tests. */
'data-cy': _propTypes.default.string
};
var _default = EditableField;
exports.default = _default;