@lyra/form-builder
Version:
Lyra form builder
300 lines (244 loc) • 9.76 kB
JavaScript
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _extends = Object.assign || 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; };
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _searchable = require('part:@lyra/components/selects/searchable');
var _searchable2 = _interopRequireDefault(_searchable);
var _default = require('part:@lyra/components/formfields/default');
var _default2 = _interopRequireDefault(_default);
var _Preview = require('../../Preview');
var _Preview2 = _interopRequireDefault(_Preview);
var _subscriptionManager = require('../../utils/subscriptionManager');
var _subscriptionManager2 = _interopRequireDefault(_subscriptionManager);
var _PatchEvent = require('../../../PatchEvent');
var _PatchEvent2 = _interopRequireDefault(_PatchEvent);
var _linkIcon = require('part:@lyra/base/link-icon');
var _linkIcon2 = _interopRequireDefault(_linkIcon);
var _router = require('part:@lyra/base/router');
var _ReferenceInput = require('./styles/ReferenceInput.css');
var _ReferenceInput2 = _interopRequireDefault(_ReferenceInput);
var _default3 = require('part:@lyra/components/buttons/default');
var _default4 = _interopRequireDefault(_default3);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
/* eslint-disable complexity */
/*:: import type {Reference, Type, Marker} from '../../typedefs'*/
/*:: import type {ObservableI} from '../../typedefs/observable'*/
/*:: type SearchHit = {
_id: string,
_type: string
}*/
/*:: type PreviewSnapshot = {
title: string,
description: string
}*/
/*:: type Props = {
value: ?Reference,
type: Type,
markers: Array<Marker>,
readOnly: ?boolean,
onSearch: (query: string, type: Type) => ObservableI<Array<SearchHit>>,
getPreviewSnapshot: (Reference, Type) => ObservableI<PreviewSnapshot>,
onChange: PatchEvent => void,
level: number
}*/
/*:: type State = {
isFetching: boolean,
hits: Array<SearchHit>,
previewSnapshot: ?PreviewSnapshot,
refCache: {[string]: SearchHit}
}*/
const MISSING_SNAPSHOT = {};
const getInitialState = () /*: State*/ => {
return {
isFetching: false,
hits: [],
previewSnapshot: null,
refCache: {}
};
};
class ReferenceInput extends _react2.default.Component /*:: <Props, State>*/ {
constructor(...args) {
var _temp;
return _temp = super(...args), this.state = getInitialState(), this.subscriptions = (0, _subscriptionManager2.default)('search', 'previewSnapshot'), this._lastQuery = '', this.handleFocus = () => {
if (this._lastQuery) {
this.search(this._lastQuery);
}
}, this.handleChange = (item /*: SearchHit*/) => {
const type = this.props.type;
this.props.onChange(_PatchEvent2.default.from((0, _PatchEvent.setIfMissing)({
_type: type.name,
_ref: item._id
}), type.weak === true ? (0, _PatchEvent.set)(true, ['_weak']) : (0, _PatchEvent.unset)(['_weak']), (0, _PatchEvent.set)(item._id, ['_ref'])));
}, this.handleFixWeak = () => {
const type = this.props.type;
this.props.onChange(_PatchEvent2.default.from(type.weak === true ? (0, _PatchEvent.set)(true, ['_weak']) : (0, _PatchEvent.unset)(['_weak'])));
}, this.handleClear = () => {
this.props.onChange(_PatchEvent2.default.from((0, _PatchEvent.unset)()));
}, this.handleSearch = (query /*: string*/) => {
this.search(query);
}, this.handleOpen = () => {
this.search('');
}, this.search = (query /*: string*/) => {
var _props = this.props;
const type = _props.type,
onSearch = _props.onSearch;
this.setState({
isFetching: true
});
this.subscriptions.replace('search', onSearch(query, type).subscribe((items /*: Array<SearchHit>*/) => {
const updatedCache = items.reduce((cache, item) => {
cache[item._id] = item;
return cache;
}, Object.assign({}, this.state.refCache));
this.setState({
hits: items,
isFetching: false,
refCache: updatedCache
});
}));
}, this.renderHit = (item /*: SearchHit*/) => {
const type = this.getMemberTypeFor(item._type);
return _react2.default.createElement(_Preview2.default, { type: type, value: item, layout: 'default' });
}, this.renderOpenItemElement = () => {
const value = this.props.value;
const previewSnapshot = this.state.previewSnapshot;
if (!value || !value._ref || previewSnapshot === MISSING_SNAPSHOT) {
return null;
}
return _react2.default.createElement(
_router.IntentLink,
{
title: previewSnapshot && `Open ${previewSnapshot.title}`,
intent: 'edit',
params: { id: value._ref }
},
_react2.default.createElement(_linkIcon2.default, null)
);
}, this.setInput = (input /*: ?SearchableSelect*/) => {
this._input = input;
}, _temp;
}
componentWillUnmount() {
this.subscriptions.unsubscribeAll();
}
componentDidMount() {
this.getPreviewSnapshot(this.props.value);
}
componentWillReceiveProps(nextProps /*: Props*/) {
if (nextProps.value !== this.props.value) {
this.setState(getInitialState());
this.getPreviewSnapshot(nextProps.value);
}
}
getPreviewSnapshot(value /*: Reference*/) {
if (!value || !value._ref) {
return;
}
var _props2 = this.props;
const getPreviewSnapshot = _props2.getPreviewSnapshot,
type = _props2.type;
this.subscriptions.replace('previewSnapshot', getPreviewSnapshot(value, type).subscribe(snapshot => {
this.setState({ previewSnapshot: snapshot || MISSING_SNAPSHOT });
}));
}
getMemberTypeFor(typeName /*: string*/) {
const type = this.props.type;
return type.to.find(ofType => ofType.type.name === typeName);
}
focus() {
if (this._input) {
this._input.focus();
}
}
render() {
var _props3 = this.props;
const type = _props3.type,
value = _props3.value,
level = _props3.level,
markers = _props3.markers,
readOnly = _props3.readOnly,
onSearch = _props3.onSearch,
getPreviewSnapshot = _props3.getPreviewSnapshot,
rest = _objectWithoutProperties(_props3, ['type', 'value', 'level', 'markers', 'readOnly', 'onSearch', 'getPreviewSnapshot']);
var _state = this.state;
const previewSnapshot = _state.previewSnapshot,
isFetching = _state.isFetching,
hits = _state.hits;
const valueFromHit = value && hits.find(hit => hit._id === value._ref);
const weakIs = value && value._weak ? 'weak' : 'strong';
const weakShouldBe = type.weak === true ? 'weak' : 'strong';
const isMissing = previewSnapshot === MISSING_SNAPSHOT;
const hasRef = value && value._ref;
const hasWeakMismatch = hasRef && !isMissing && weakIs !== weakShouldBe;
const validation = markers.filter(marker => marker.type === 'validation');
const errors = validation.filter(marker => marker.level === 'error');
let inputValue = value ? previewSnapshot && previewSnapshot.title : undefined;
if (previewSnapshot && !previewSnapshot.title) {
inputValue = 'Untitled document';
}
return _react2.default.createElement(
_default2.default,
{
markers: markers,
label: type.title,
level: level,
description: type.description
},
_react2.default.createElement(
'div',
{ className: hasWeakMismatch || isMissing ? _ReferenceInput2.default.hasWarnings : '' },
hasWeakMismatch && _react2.default.createElement(
'div',
{ className: _ReferenceInput2.default.weakRefMismatchWarning },
'Warning: This reference is ',
_react2.default.createElement(
'em',
null,
weakIs
),
', but should be',
' ',
_react2.default.createElement(
'em',
null,
weakShouldBe
),
' according to schema.',
_react2.default.createElement(
'div',
null,
_react2.default.createElement(
_default4.default,
{ onClick: this.handleFixWeak },
'Convert to ',
weakShouldBe
)
)
),
_react2.default.createElement(_searchable2.default, _extends({}, rest, {
placeholder: 'Type to search\u2026',
title: isMissing && hasRef ? `Document id: ${value._ref || 'unknown'}` : previewSnapshot && previewSnapshot.description,
customValidity: errors.length > 0 ? errors[0].item.message : '',
onOpen: this.handleOpen,
onFocus: this.handleFocus,
onSearch: this.handleSearch,
onChange: this.handleChange,
onClear: this.handleClear,
openItemElement: this.renderOpenItemElement,
value: valueFromHit || value,
inputValue: isMissing ? '<Unpublished or missing document>' : inputValue,
renderItem: this.renderHit,
isLoading: isFetching,
items: hits,
ref: this.setInput,
readOnly: readOnly
}))
)
);
}
}
exports.default = ReferenceInput;