@lyra/form-builder
Version:
Lyra form builder
429 lines (351 loc) • 12.4 kB
JavaScript
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _linkIcon = require('part:@lyra/base/link-icon');
var _linkIcon2 = _interopRequireDefault(_linkIcon);
var _fold = require('part:@lyra/components/edititem/fold');
var _fold2 = _interopRequireDefault(_fold);
var _popover = require('part:@lyra/components/dialogs/popover');
var _popover2 = _interopRequireDefault(_popover);
var _fullscreen = require('part:@lyra/components/dialogs/fullscreen');
var _fullscreen2 = _interopRequireDefault(_fullscreen);
var _default = require('part:@lyra/components/dialogs/default');
var _default2 = _interopRequireDefault(_default);
var _content = require('part:@lyra/components/dialogs/content');
var _content2 = _interopRequireDefault(_content);
var _status = require('part:@lyra/components/validation/status');
var _status2 = _interopRequireDefault(_status);
var _sortable = require('part:@lyra/components/lists/sortable');
var _router = require('part:@lyra/base/router');
var _barsIcon = require('part:@lyra/base/bars-icon');
var _barsIcon2 = _interopRequireDefault(_barsIcon);
var _FormBuilderInput = require('../../FormBuilderInput');
var _PatchEvent = require('../../PatchEvent');
var _PatchEvent2 = _interopRequireDefault(_PatchEvent);
var _Preview = require('../../Preview');
var _Preview2 = _interopRequireDefault(_Preview);
var _resolveTypeName = require('../../utils/resolveTypeName');
var _pathUtils = require('../../utils/pathUtils');
var PathUtils = _interopRequireWildcard(_pathUtils);
var _ConfirmButton = require('./ConfirmButton');
var _ConfirmButton2 = _interopRequireDefault(_ConfirmButton);
var _ItemValue = require('./styles/ItemValue.css');
var _ItemValue2 = _interopRequireDefault(_ItemValue);
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/* eslint-disable complexity */
/*:: import type {Node} from 'react'*/
/*:: import type {Path} from '../../typedefs/path'*/
/*:: import type {Type, Marker} from '../../typedefs'*/
/*:: import type {ArrayType, ItemValue} from './typedefs'*/
const DragHandle = (0, _sortable.createDragHandle)(() => _react2.default.createElement(
'span',
{ className: _ItemValue2.default.dragHandle },
_react2.default.createElement(_barsIcon2.default, null)
));
const CLOSE_ACTION = {
name: 'close',
title: 'Close'
};
const CANCEL_ACTION = {
name: 'close',
title: 'Cancel'
};
const DELETE_ACTION = {
name: 'delete',
kind: 'simple',
title: 'Delete',
color: 'danger',
secondary: true
};
/*:: type Props = {
type: ArrayType,
value: ItemValue,
level: number,
markers: Array<Marker>,
layout?: 'media' | 'default',
onRemove: ItemValue => void,
onChange: (PatchEvent, ItemValue) => void,
onFocus: Path => void,
onBlur: void => void,
readOnly: ?boolean,
focusPath: Path
}*/
function pathSegmentFrom(value) {
return { _key: value._key };
}
function hasFocusInPath(path, value) {
return path.length === 1 && PathUtils.isSegmentEqual(path[0], pathSegmentFrom(value));
}
const IGNORE_KEYS = ['_key', '_type', '_weak'];
function isEmpty(value) {
return Object.keys(value).every(key => IGNORE_KEYS.includes(key));
}
class RenderItemValue extends _react2.default.Component /*:: <Props>*/ {
constructor(...args) {
var _temp;
return _temp = super(...args), this.handleEditStart = event => {
this.setFocus([PathUtils.FOCUS_TERMINATOR]);
}, this.handleFocus = () => {
this.setFocus();
}, this.handleEditStop = () => {
if (isEmpty(this.props.value)) {
this.handleRemove();
} else {
this.setFocus();
}
}, this.handleKeyPress = (event /*: SyntheticKeyboardEvent<*>*/) => {
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
this.setFocus([PathUtils.FOCUS_TERMINATOR]);
}
}, this.handleRemove = () => {
var _props = this.props;
const onRemove = _props.onRemove,
value = _props.value;
onRemove(value);
}, this.handleChange = (event /*: PatchEvent*/) => {
var _props2 = this.props;
const onChange = _props2.onChange,
value = _props2.value;
onChange(event, value);
}, this.setFocusArea = (el /*: ?FocusArea*/) => {
this._focusArea = el;
}, this.handleDialogAction = action => {
if (action.name === 'close') {
this.handleEditStop();
}
if (action.name === 'delete') {
// Needs a proper confirm dialog later
// eslint-disable-next-line no-alert
if (window.confirm('Do you really want to delete?')) {
this.handleRemove();
}
}
}, _temp;
}
componentDidMount() {
var _props3 = this.props;
const focusPath = _props3.focusPath,
value = _props3.value;
if (hasFocusInPath(focusPath, value)) {
this.focus();
}
}
componentDidUpdate(prevProps) {
const hadFocus = hasFocusInPath(prevProps.focusPath, prevProps.value);
const hasFocus = hasFocusInPath(this.props.focusPath, this.props.value);
if (!hadFocus && hasFocus) {
this.focus();
}
}
getMemberType() /*: ?Type*/ {
var _props4 = this.props;
const value = _props4.value,
type = _props4.type;
const itemTypeName = (0, _resolveTypeName.resolveTypeName)(value);
return type.of.find(memberType => memberType.name === itemTypeName);
}
setFocus(path /*: Path*/ = []) {
var _props5 = this.props;
const value = _props5.value,
onFocus = _props5.onFocus;
onFocus([{ _key: value._key }, ...path]);
}
focus() {
if (this._focusArea) {
this._focusArea.focus();
}
}
renderEditItemForm(item /*: ItemValue*/) /*: Node*/ {
var _props6 = this.props;
const type = _props6.type,
markers = _props6.markers,
focusPath = _props6.focusPath,
onFocus = _props6.onFocus,
onBlur = _props6.onBlur,
readOnly = _props6.readOnly;
const options = type.options || {};
const memberType = this.getMemberType() || {};
const childMarkers = markers.filter(marker => marker.path.length > 1);
const content = _react2.default.createElement(_FormBuilderInput.FormBuilderInput, {
type: memberType,
level: 0,
value: isEmpty(item) ? undefined : item,
onChange: this.handleChange,
onFocus: onFocus,
onBlur: onBlur,
focusPath: focusPath,
readOnly: readOnly || memberType.readOnly,
markers: childMarkers,
path: [{ _key: item._key }]
});
// test focus issues by uncommenting the next line
// return content
if (options.editModal === 'fullscreen') {
return _react2.default.createElement(
_fullscreen2.default,
{
title: memberType.title,
onClose: this.handleEditStop,
isOpen: true
},
content
);
}
if (options.editModal === 'fold') {
return _react2.default.createElement(
'div',
{ className: _ItemValue2.default.popupAnchorRelative },
_react2.default.createElement(
_fold2.default,
{
title: `Edit ${memberType.title}`,
onClose: this.handleEditStop
},
content
)
);
}
const dialogSize = 'medium';
const isItemEmpty = isEmpty(item);
const actions = [isItemEmpty ? CANCEL_ACTION : CLOSE_ACTION, !isItemEmpty && !readOnly && DELETE_ACTION].filter(Boolean);
if (options.editModal === 'popover') {
return _react2.default.createElement(
'div',
{ className: _ItemValue2.default.popupAnchor },
_react2.default.createElement(
_popover2.default,
{
title: `Edit ${memberType.title}`,
onClose: this.handleEditStop,
onEscape: this.handleEditStop,
onClickOutside: this.handleEditStop,
actions: actions,
onAction: this.handleDialogAction
},
_react2.default.createElement(
_content2.default,
{ size: dialogSize },
content
)
)
);
}
return _react2.default.createElement(
_default2.default,
{
onClose: this.handleEditStop,
key: item._key,
title: `Edit ${memberType.title}`,
actions: actions,
onAction: this.handleDialogAction,
showCloseButton: false
},
_react2.default.createElement(
'div',
{ className: _ItemValue2.default.defaultDialogContent },
_react2.default.createElement(
_content2.default,
{ size: dialogSize },
content
)
)
);
}
renderItem() {
var _props7 = this.props;
const value = _props7.value,
markers = _props7.markers,
type = _props7.type,
readOnly = _props7.readOnly;
const options = type.options || {};
const isGrid = options.layout === 'grid';
const isSortable = !readOnly && !type.readOnly && options.sortable !== false;
const previewLayout = isGrid ? 'media' : 'default';
const validation = markers.filter(marker => marker.type === 'validation');
const errors = validation.filter(marker => marker.level === 'error');
const scopedValidation = validation.map(marker => {
if (marker.path.length <= 1) {
return marker;
}
const level = marker.level === 'error' ? 'errors' : 'warnings';
return Object.assign({}, marker, {
item: marker.item.cloneWithMessage(`Contains ${level}`)
});
});
return _react2.default.createElement(
'div',
{ className: errors.length > 0 ? _ItemValue2.default.innerWithError : _ItemValue2.default.inner },
!isGrid && isSortable && _react2.default.createElement(DragHandle, null),
_react2.default.createElement(
'div',
{
tabIndex: 0,
onClick: this.handleEditStart,
onKeyPress: this.handleKeyPress,
className: _ItemValue2.default.previewWrapper
},
_react2.default.createElement(
'div',
{
tabIndex: -1,
ref: this.setFocusArea,
className: _ItemValue2.default.previewWrapperHelper,
onFocus: this.handleFocus
},
_react2.default.createElement(_Preview2.default, {
layout: previewLayout,
value: value,
type: this.getMemberType()
})
)
),
_react2.default.createElement(
'div',
{ className: isGrid ? _ItemValue2.default.functionsInGrid : _ItemValue2.default.functions },
_react2.default.createElement(
'div',
{ className: _ItemValue2.default.validationStatus },
_react2.default.createElement(_status2.default, { markers: scopedValidation })
),
value._ref && _react2.default.createElement(
_router.IntentLink,
{
className: _ItemValue2.default.linkToReference,
intent: 'edit',
params: { id: value._ref }
},
_react2.default.createElement(_linkIcon2.default, null)
),
!readOnly && _react2.default.createElement(_ConfirmButton2.default, {
title: 'Remove this item',
onConfirm: this.handleRemove
})
)
);
}
render() {
var _props8 = this.props;
const value = _props8.value,
focusPath = _props8.focusPath,
type = _props8.type;
const options = type.options || {};
const isGrid = options.layout === 'grid';
const isExpanded = PathUtils.isExpanded(value, focusPath);
return _react2.default.createElement(
'div',
{ className: isGrid ? _ItemValue2.default.gridItem : _ItemValue2.default.listItem },
this.renderItem(),
isExpanded && this.renderEditItemForm(value)
);
}
}
exports.default = RenderItemValue;
RenderItemValue.defaultProps = {
level: 0,
markers: []
};