idyll-document
Version:
The Idyll runtime, implemented as a React component.
1,274 lines (1,067 loc) • 63.6 kB
JavaScript
'use strict';
var _extends = require('@babel/runtime/helpers/extends');
var _classCallCheck = require('@babel/runtime/helpers/classCallCheck');
var _createClass = require('@babel/runtime/helpers/createClass');
var _inherits = require('@babel/runtime/helpers/inherits');
var _possibleConstructorReturn = require('@babel/runtime/helpers/possibleConstructorReturn');
var _getPrototypeOf = require('@babel/runtime/helpers/getPrototypeOf');
var React = require('react');
var _slicedToArray = require('@babel/runtime/helpers/slicedToArray');
var _assertThisInitialized = require('@babel/runtime/helpers/assertThisInitialized');
var _defineProperty = require('@babel/runtime/helpers/defineProperty');
var _objectWithoutProperties = require('@babel/runtime/helpers/objectWithoutProperties');
var ReactDOM = require('react-dom');
var scrollparent = require('scrollparent');
var scrollMonitor = require('scrollmonitor');
var _toArray = require('@babel/runtime/helpers/toArray');
var DOM = require('react-dom-factories');
var changeCase = require('change-case');
var entries = require('object.entries');
var values = require('object.values');
var ReactTooltip = require('react-tooltip');
var idyllAst = require('idyll-ast');
var equal = require('fast-deep-equal');
var layouts = require('idyll-layouts');
var themes = require('idyll-themes');
var _typeof = require('@babel/runtime/helpers/typeof');
var falafel = require('falafel');
var sync = require('csv-parse/sync');
var compile = require('idyll-compiler');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
function _interopNamespace(e) {
if (e && e.__esModule) return e;
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n["default"] = e;
return Object.freeze(n);
}
var _extends__default = /*#__PURE__*/_interopDefaultLegacy(_extends);
var _classCallCheck__default = /*#__PURE__*/_interopDefaultLegacy(_classCallCheck);
var _createClass__default = /*#__PURE__*/_interopDefaultLegacy(_createClass);
var _inherits__default = /*#__PURE__*/_interopDefaultLegacy(_inherits);
var _possibleConstructorReturn__default = /*#__PURE__*/_interopDefaultLegacy(_possibleConstructorReturn);
var _getPrototypeOf__default = /*#__PURE__*/_interopDefaultLegacy(_getPrototypeOf);
var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
var _slicedToArray__default = /*#__PURE__*/_interopDefaultLegacy(_slicedToArray);
var _assertThisInitialized__default = /*#__PURE__*/_interopDefaultLegacy(_assertThisInitialized);
var _defineProperty__default = /*#__PURE__*/_interopDefaultLegacy(_defineProperty);
var _objectWithoutProperties__default = /*#__PURE__*/_interopDefaultLegacy(_objectWithoutProperties);
var ReactDOM__default = /*#__PURE__*/_interopDefaultLegacy(ReactDOM);
var scrollparent__default = /*#__PURE__*/_interopDefaultLegacy(scrollparent);
var scrollMonitor__default = /*#__PURE__*/_interopDefaultLegacy(scrollMonitor);
var _toArray__default = /*#__PURE__*/_interopDefaultLegacy(_toArray);
var DOM__default = /*#__PURE__*/_interopDefaultLegacy(DOM);
var entries__default = /*#__PURE__*/_interopDefaultLegacy(entries);
var values__default = /*#__PURE__*/_interopDefaultLegacy(values);
var ReactTooltip__default = /*#__PURE__*/_interopDefaultLegacy(ReactTooltip);
var equal__default = /*#__PURE__*/_interopDefaultLegacy(equal);
var layouts__namespace = /*#__PURE__*/_interopNamespace(layouts);
var themes__namespace = /*#__PURE__*/_interopNamespace(themes);
var _typeof__default = /*#__PURE__*/_interopDefaultLegacy(_typeof);
var falafel__default = /*#__PURE__*/_interopDefaultLegacy(falafel);
var compile__default = /*#__PURE__*/_interopDefaultLegacy(compile);
var _excluded$4 = ["component", "children"];
function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
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; }
var _componentMap = new WeakMap();
var ReactJsonSchema = /*#__PURE__*/function () {
function ReactJsonSchema(componentMap) {
_classCallCheck__default["default"](this, ReactJsonSchema);
if (componentMap) this.setComponentMap(componentMap);
}
_createClass__default["default"](ReactJsonSchema, [{
key: "parseSchema",
value: function parseSchema(schema) {
var element = null;
var elements = null;
if (Array.isArray(schema)) {
elements = this.parseSubSchemas(schema);
} else {
element = this.createComponent(schema);
}
return element || elements;
}
}, {
key: "parseSubSchemas",
value: function parseSubSchemas() {
var subSchemas = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
var Components = [];
var index = 0;
var _iterator = _createForOfIteratorHelper(subSchemas),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var subSchema = _step.value;
if (typeof subSchema === 'string') {
Components.push(subSchema);
} else {
subSchema.key = typeof subSchema.key !== 'undefined' ? subSchema.key : index;
Components.push(this.parseSchema(subSchema));
index++;
}
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
return Components;
}
}, {
key: "createComponent",
value: function createComponent(schema) {
if (schema.type) {
if (schema.type === 'textnode') return schema.value;
}
schema.component;
schema.children;
var rest = _objectWithoutProperties__default["default"](schema, _excluded$4);
var Component = this.resolveComponent(schema);
var Children = this.resolveComponentChildren(schema);
return /*#__PURE__*/React.createElement(Component, rest, Children);
}
}, {
key: "resolveComponent",
value: function resolveComponent(schema) {
var componentMap = this.getComponentMap();
var Component; // bail early if there is no component name
if (!schema.hasOwnProperty('component')) {
throw new Error('ReactJsonSchema could not resolve a component due to a missing component attribute in the schema.');
} // if it's already a ref bail early
if (schema.component === Object(schema.component)) {
return schema.component;
}
var _schema$component$spl = schema.component.split('.'),
_schema$component$spl2 = _toArray__default["default"](_schema$component$spl),
name = _schema$component$spl2[0],
subs = _schema$component$spl2.slice(1); // find the def in the provided map
if (componentMap) {
Component = componentMap[name];
if (!Component) Component = componentMap[changeCase.paramCase(name)];
if (!Component) Component = componentMap[changeCase.pascalCase(name)];
for (var i = 0; i < subs.length; i++) {
Component = Component["default"][subs[i]] || Component[subs[i]];
}
} // if still nothing found it's a native DOM component or an error
if (!Component) {
if (DOM__default["default"].hasOwnProperty(name)) {
Component = schema.component;
} else {
console.warn("Could not find an implementation for: ".concat(schema.component));
return function () {
return /*#__PURE__*/React__default["default"].createElement("div", {
style: {
color: 'black',
border: 'solid 1px red'
}
}, /*#__PURE__*/React__default["default"].createElement("pre", null, "Could not find an implementation for: ", schema.component));
};
}
} // if there is a default prop (CommonJS) return that
return Component["default"] || Component;
}
}, {
key: "resolveComponentChildren",
value: function resolveComponentChildren(schema) {
var children = schema.hasOwnProperty('children') ? this.parseSchema(schema.children) : [];
return children.length ? children : undefined;
}
}, {
key: "getComponentMap",
value: function getComponentMap() {
return _componentMap.get(this);
}
}, {
key: "setComponentMap",
value: function setComponentMap(componentMap) {
_componentMap.set(this, componentMap);
}
}]);
return ReactJsonSchema;
}();
var _excluded$3 = ["idyll", "updateProps", "hasError"];
function _createSuper$3(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$3(); return function _createSuperInternal() { var Super = _getPrototypeOf__default["default"](Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf__default["default"](this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn__default["default"](this, result); }; }
function _isNativeReflectConstruct$3() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
var generatePlaceholder = function generatePlaceholder(name) {
return /*#__PURE__*/function (_React$PureComponent) {
_inherits__default["default"](_class, _React$PureComponent);
var _super = _createSuper$3(_class);
function _class(props) {
var _this;
_classCallCheck__default["default"](this, _class);
_this = _super.call(this, props);
console.warn("Warning: attempting to use component named ".concat(name, ", but it wasn't found"));
return _this;
}
_createClass__default["default"](_class, [{
key: "render",
value: function render() {
var _this$props = this.props;
_this$props.idyll;
_this$props.updateProps;
_this$props.hasError;
var props = _objectWithoutProperties__default["default"](_this$props, _excluded$3);
return /*#__PURE__*/React__default["default"].createElement("div", props);
}
}]);
return _class;
}(React__default["default"].PureComponent);
};
var _excluded$2 = ["idyll", "updateProps", "hasError"];
function _createSuper$2(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$2(); return function _createSuperInternal() { var Super = _getPrototypeOf__default["default"](Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf__default["default"](this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn__default["default"](this, result); }; }
function _isNativeReflectConstruct$2() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
var AuthorTool = /*#__PURE__*/function (_React$PureComponent) {
_inherits__default["default"](AuthorTool, _React$PureComponent);
var _super = _createSuper$2(AuthorTool);
function AuthorTool(props) {
var _this;
_classCallCheck__default["default"](this, AuthorTool);
_this = _super.call(this, props);
_this.state = {
isAuthorView: false,
debugHeight: 0,
componentHeight: 0,
hasPressedButton: false
};
_this.handleClick = _this.handleClick.bind(_assertThisInitialized__default["default"](_this));
return _this;
} // For all available props in metaValues, display them
// If runtimeValues has a value for given prop, display it
// Returns this in a single table row <tr>
_createClass__default["default"](AuthorTool, [{
key: "handleTableValues",
value: function handleTableValues(metaValues, runtimeValues) {
return metaValues.props.map(function (prop) {
var runtimeValue = runtimeValues.props[prop.name];
var currentPropValue = null;
if (runtimeValue !== undefined) {
if (runtimeValue && {}.toString.call(runtimeValue) === '[object Function]') {
currentPropValue = /*#__PURE__*/React__default["default"].createElement("em", null, "function");
} else {
currentPropValue = runtimeValue;
}
}
return /*#__PURE__*/React__default["default"].createElement("tr", {
key: JSON.stringify(prop),
className: "props-table-row"
}, /*#__PURE__*/React__default["default"].createElement("td", null, prop.name), /*#__PURE__*/React__default["default"].createElement("td", {
className: "props-table-type"
}, prop.type), /*#__PURE__*/React__default["default"].createElement("td", null, prop.example), /*#__PURE__*/React__default["default"].createElement("td", null, currentPropValue));
});
} // Returns authoring information for the prop values in table format
// and includes a link to the docs page at the bottom
}, {
key: "handleFormatComponent",
value: function handleFormatComponent(runtimeValues) {
var _this2 = this;
var metaValues = runtimeValues.type._idyll;
var componentName = metaValues.name; // Docs use lowercase component name for link
var componentLowerCase = componentName.charAt(0).toLowerCase() + componentName.slice(1);
var componentDocsLink = 'https://idyll-lang.org/docs/components/default/' + componentLowerCase;
var showProps = this.handleTableValues(metaValues, runtimeValues);
var _this$state = this.state,
isAuthorView = _this$state.isAuthorView,
debugHeight = _this$state.debugHeight,
componentHeight = _this$state.componentHeight;
var currentDebugHeight = isAuthorView ? debugHeight : 0;
var marginToGive = isAuthorView ? 15 : 0; // If a component's height is too small, button will overlap with table
// so add margin to get a minimal height (40px seems fine)
var marginAboveTable = componentHeight < 40 && isAuthorView ? 40 - componentHeight : 0;
return /*#__PURE__*/React__default["default"].createElement("div", {
className: "debug-collapse",
style: {
height: currentDebugHeight + 'px',
marginBottom: marginToGive + 'px',
marginTop: marginAboveTable + 'px'
}
}, /*#__PURE__*/React__default["default"].createElement("div", {
className: "author-component-view",
ref: function ref(inner) {
return _this2.innerHeight = inner;
}
}, /*#__PURE__*/React__default["default"].createElement("table", {
className: "props-table"
}, /*#__PURE__*/React__default["default"].createElement("tbody", null, /*#__PURE__*/React__default["default"].createElement("tr", {
className: "props-table-row"
}, /*#__PURE__*/React__default["default"].createElement("th", null, "Prop"), /*#__PURE__*/React__default["default"].createElement("th", null, "Type"), /*#__PURE__*/React__default["default"].createElement("th", null, "Example"), /*#__PURE__*/React__default["default"].createElement("th", null, "Current Value")), showProps)), /*#__PURE__*/React__default["default"].createElement("div", {
className: "icon-links"
}, /*#__PURE__*/React__default["default"].createElement("a", {
className: "icon-link",
href: componentDocsLink
}, /*#__PURE__*/React__default["default"].createElement("img", {
className: "icon-link-image",
src: "https://raw.githubusercontent.com/google/material-design-icons/master/action/svg/design/ic_description_24px.svg?sanitize=true"
})), /*#__PURE__*/React__default["default"].createElement("a", {
className: "icon-link",
href: componentDocsLink
}, /*#__PURE__*/React__default["default"].createElement("span", {
style: {
fontFamily: 'courier',
fontSize: '12px',
marginTop: '8px'
}
}, "docs")))));
} // Flips between whether we are in the author view of a component
}, {
key: "handleClick",
value: function handleClick() {
var _this3 = this;
this.setState(function (prevState) {
return {
isAuthorView: !prevState.isAuthorView,
debugHeight: _this3.innerHeight.getBoundingClientRect().height
};
});
if (!this.state.hasPressedButton) {
this.setState({
componentHeight: this._refContainer.getBoundingClientRect().height,
hasPressedButton: true
});
}
} // Returns an entire author view, including the component itself,
// a quill icon to indicate whether we're hovering in the component,
// and debugging information when the icon is pressed
}, {
key: "render",
value: function render() {
var _this4 = this;
var _this$props = this.props;
_this$props.idyll;
_this$props.updateProps;
_this$props.hasError;
var props = _objectWithoutProperties__default["default"](_this$props, _excluded$2);
var addBorder = this.state.isAuthorView ? {
boxShadow: '5px 5px 10px 1px lightGray',
transition: 'box-shadow 0.35s linear',
padding: '0px 10px 10px',
margin: '0px -10px 20px'
} : null;
var putButtonBack = this.state.isAuthorView ? {
right: '10px',
top: '3px'
} : null;
return /*#__PURE__*/React__default["default"].createElement("div", {
className: "component-debug-view",
style: addBorder,
ref: function ref(_ref) {
return _this4._refContainer = _ref;
}
}, props.component, /*#__PURE__*/React__default["default"].createElement("button", {
className: "author-view-button",
style: putButtonBack,
onClick: this.handleClick,
"data-tip": true,
"data-for": props.uniqueKey
}), /*#__PURE__*/React__default["default"].createElement(ReactTooltip__default["default"], {
className: "button-tooltip",
id: props.uniqueKey,
type: "info",
effect: "solid",
place: "bottom" // TODO not showing up ?
,
disable: this.state.isAuthorView
}, /*#__PURE__*/React__default["default"].createElement("div", {
className: "tooltip-header"
}, props.authorComponent.type._idyll.name, " Component"), /*#__PURE__*/React__default["default"].createElement("div", {
className: "tooltip-subtitle"
}, "Click for more info")), this.handleFormatComponent(props.authorComponent));
}
}]);
return AuthorTool;
}(React__default["default"].PureComponent);
var _excluded$1 = ["__vars__", "__expr__", "idyllASTNode", "hasHook", "initialState", "isHTMLNode", "refName", "onEnterViewFully", "onEnterView", "onExitViewFully", "onExitView", "fullWidth"],
_excluded2$1 = ["idyll", "hasError", "updateProps"],
_excluded3$1 = ["component", "children", "__vars__", "__expr__"];
function ownKeys$1(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$1(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys$1(Object(source), !0).forEach(function (key) { _defineProperty__default["default"](target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys$1(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
var _require = require('idyll-ast'),
cloneNode = _require.cloneNode,
getChildren = _require.getChildren,
getNodeName = _require.getNodeName,
getNodeType = _require.getNodeType,
getProperties = _require.getProperties,
isTextNode = _require.isTextNode,
removeNodes = _require.removeNodes;
var isPropertyAccess = function isPropertyAccess(node) {
var index = node.parent.source().indexOf(".".concat(node.name));
if (index === -1) {
return false;
}
var proxyString = '__idyllStateProxy';
if (index >= proxyString.length) {
if (node.parent.source().substr(index - proxyString.length, proxyString.length) === proxyString) {
return false;
}
}
return true;
};
var isObjectKey = function isObjectKey(node) {
return node.parent.type === 'Property' && node.parent.key === node;
};
var buildExpression = function buildExpression(acc, expr, isEventHandler) {
var identifiers = [];
var modifiedExpression = '';
try {
modifiedExpression = falafel__default["default"](isEventHandler ? expr : "var __idyllReturnValue = ".concat(expr || 'undefined'), function (node) {
switch (node.type) {
case 'Identifier':
var skip = isPropertyAccess(node) || isObjectKey(node);
if (Object.keys(acc).indexOf(node.name) > -1) {
identifiers.push(node.name);
if (!skip) {
node.update('__idyllStateProxy.' + node.source());
}
}
break;
}
});
} catch (e) {
console.error(e);
}
if (!isEventHandler) {
return "\n ((context) => {\n var __idyllStateProxy = new Proxy({}, {\n get: (_, prop) => {\n return context[prop];\n },\n set: (_, prop, value) => {\n console.warn('Warning, trying to set a value in a property expression.');\n }\n });\n ".concat(modifiedExpression, ";\n return __idyllReturnValue;\n })(this)");
}
return "\n ((context) => {\n var __idyllExpressionExecuted = false;\n var __idyllStateProxy = new Proxy({\n ".concat(identifiers.map(function (key) {
return "".concat(key, ": ").concat(key !== 'refs' ? "context.__idyllCopy(context['".concat(key, "'])") : "context['".concat(key, "']"));
}).join(', '), "\n }, {\n get: (target, prop) => {\n return target[prop];\n },\n set: (target, prop, value) => {\n if (__idyllExpressionExecuted) {\n var newState = {};\n newState[prop] = value;\n context.__idyllUpdate(newState);\n }\n target[prop] = value;\n return true;\n }\n });\n ").concat(modifiedExpression, ";\n context.__idyllUpdate({\n ").concat(identifiers.filter(function (key) {
return key !== 'refs';
}).map(function (key) {
return "".concat(key, ": __idyllStateProxy['").concat(key, "']");
}).join(', '), "\n });\n __idyllExpressionExecuted = true;\n })(this)\n ");
};
var evalExpression = function evalExpression(acc, expr, key, context) {
var isEventHandler = key && (key.match(/^on[A-Z].*/) || key.match(/^handle[A-Z].*/));
var e = buildExpression(acc, expr, isEventHandler);
if (isEventHandler) {
return function () {
eval(e);
}.bind(Object.assign({}, acc, context || {}, {
__idyllCopy: function copy(o) {
if (_typeof__default["default"](o) !== 'object') return o;
var output, v, key;
output = Array.isArray(o) ? [] : {};
for (key in o) {
v = o[key];
output[key] = _typeof__default["default"](v) === 'object' ? copy(v) : v;
}
return output;
}
}));
}
try {
return function (evalString) {
try {
return eval('(' + evalString + ')');
} catch (err) {
console.warn('Error occurred in Idyll expression');
}
}.call(Object.assign({}, acc), e);
} catch (err) {}
};
var getVars = function getVars(arr) {
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var formatAccumulatedValues = function formatAccumulatedValues(acc) {
var ret = {};
Object.keys(acc).forEach(function (key) {
var accVal = acc[key];
if (typeof accVal.update !== 'undefined' && typeof accVal.value !== 'undefined') {
ret[key] = accVal.value;
} else {
ret[key] = accVal;
}
});
return ret;
};
var pluck = function pluck(acc, val) {
var variableType = getNodeType(val);
var attrs = getProperties(val) || {};
if (!attrs.name || !attrs.value) return attrs;
var nameValue = attrs.name.value;
var valueType = attrs.value.type;
var valueValue = attrs.value.value;
switch (valueType) {
case 'value':
acc[nameValue] = valueValue;
break;
case 'variable':
if (context.hasOwnProperty(valueValue)) {
acc[nameValue] = context[valueValue];
} else {
acc[nameValue] = evalExpression(context, expr);
}
break;
case 'expression':
var expr = valueValue;
if (variableType === 'var') {
acc[nameValue] = evalExpression(Object.assign({}, context, formatAccumulatedValues(acc)), expr);
} else {
acc[nameValue] = {
value: evalExpression(Object.assign({}, context, formatAccumulatedValues(acc)), expr),
update: function update(newState, oldState) {
var context = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
return evalExpression(Object.assign({}, oldState, newState, context), expr);
}
};
}
}
return acc;
};
return arr.reduce(pluck, {});
};
var filterIdyllProps = function filterIdyllProps(props, filterInjected) {
props.__vars__;
props.__expr__;
props.idyllASTNode;
props.hasHook;
props.initialState;
props.isHTMLNode;
props.refName;
props.onEnterViewFully;
props.onEnterView;
props.onExitViewFully;
props.onExitView;
props.fullWidth;
var rest = _objectWithoutProperties__default["default"](props, _excluded$1);
if (filterInjected) {
rest.idyll;
rest.hasError;
rest.updateProps;
var ret = _objectWithoutProperties__default["default"](rest, _excluded2$1);
return ret;
}
return rest;
};
var getData = function getData(arr) {
var datasets = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var pluck = function pluck(acc, val) {
var nameValue = getProperties(val).name.value;
var sourceValue = getProperties(val).source.value;
var async = getProperties(val).async ? getProperties(val).async.value : false;
if (async) {
var initialValue = getProperties(val).initialValue ? JSON.parse(getProperties(val).initialValue.value) : [];
var dataPromise = new Promise(function (res) {
return res(initialValue);
});
if (typeof fetch !== 'undefined') {
dataPromise = fetch(sourceValue).then(function (res) {
if (res.status >= 400) {
throw new Error("Error Status ".concat(res.status, " occurred while fetching data from ").concat(sourceValue, ". If you are using a file to load the data and not a url, make sure async is not set to true."));
}
if (sourceValue.endsWith('.csv')) {
return res.text().then(function (resString) {
return sync.parse(resString, {
cast: true,
columns: true,
skip_empty_lines: true,
ltrim: true,
rtrim: true
});
})["catch"](function (e) {
console.error("Error while parsing csv: ".concat(e));
});
}
return res.json()["catch"](function (e) {
return console.error(e);
});
})["catch"](function (e) {
console.error(e);
});
} else if (typeof window !== 'undefined') {
console.warn('Could not find fetch.');
}
acc.asyncData[nameValue] = {
initialValue: initialValue,
dataPromise: dataPromise
};
} else {
acc.syncData[nameValue] = datasets[nameValue];
}
return acc;
};
return arr.reduce(pluck, {
syncData: {},
asyncData: {}
});
};
var splitAST = function splitAST(ast) {
var state = {
vars: [],
derived: [],
data: [],
elements: []
};
var handleNode = function handleNode(storeElements) {
return function (node) {
var type = getNodeType(node);
var children = getChildren(node);
if (type === 'var') {
state.vars.push(node);
} else if (state[type]) {
state[type].push(node);
} else if (storeElements) {
state.elements.push(node);
}
if (!children || children.length === 1 && isTextNode(children[0])) {
return;
}
children.forEach(handleNode(false));
};
};
ast.forEach(handleNode(true));
return state;
}; //Properties that add logic to components for callbacks.
var hooks = ['onEnterView', 'onEnterViewFully', 'onExitView', 'onExitViewFully'];
var scrollMonitorEvents = {
onEnterView: 'enterViewport',
onEnterViewFully: 'fullyEnterViewport',
onExitView: 'partiallyExitViewport',
onExitViewFully: 'exitViewport'
};
var translate = function translate(ast) {
var attrConvert = function attrConvert(props, node) {
var reducedProps = {
idyllASTNode: node
};
for (var propName in props) {
var name = propName;
var type = props[propName].type;
var value = props[propName].value;
if (type == 'variable') {
if (!reducedProps.__vars__) {
reducedProps.__vars__ = {};
}
reducedProps.__vars__[name] = value;
}
if (type == 'expression') {
if (!reducedProps.__expr__) {
reducedProps.__expr__ = {};
}
reducedProps.__expr__[name] = value;
}
if (hooks.includes(name)) {
reducedProps.hasHook = true;
}
reducedProps[name] = value;
}
return reducedProps;
};
var tNode = function tNode(node) {
if (isTextNode(node)) return node;
var name = getNodeName(node);
var attrs = getProperties(node);
if (!attrs) {
attrs = {};
}
var children = getChildren(node);
return _objectSpread$1(_objectSpread$1({
component: name
}, attrConvert(attrs, node)), {}, {
children: children.map(tNode)
});
};
return splitAST(getChildren(ast)).elements.map(tNode);
};
var mapTree = function mapTree(tree, mapFn) {
var filterFn = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : function () {
return true;
};
var depth = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
var walkFn = function walkFn(depth) {
return function (acc, node) {
//To check for textnodes
if (node.component) {
//To check for children
if (node.children) {
node.children = node.children.reduce(walkFn(depth + 1), []);
}
}
if (filterFn(node)) {
acc.push(mapFn(node, depth));
}
return acc;
};
};
var value = tree.reduce(walkFn(depth), []);
return value;
};
var filterASTForDocument = function filterASTForDocument(ast) {
return removeNodes(cloneNode(ast), function (node) {
return getNodeName(node) === 'meta';
});
};
var findWrapTargets = function findWrapTargets(schema, state, components) {
//Custom components
var targets = []; //Name of custom components
var componentNames = Object.keys(components);
componentNames.forEach(function (component, i) {
var words = component.split('-');
for (var _i = 0; _i < words.length; _i++) {
words[_i] = words[_i].charAt(0).toUpperCase() + words[_i].substring(1);
}
componentNames[i] = words.join('').toLowerCase();
}); //Array of keys for the runtime state passed.
//Walk the whole tree, collect and return the nodes
//for wrapping
mapTree(schema, function (node) {
if (node.component === 'textnode') {
return node;
} //Custom components will have hooks attached to them
if (node.hasHook) {
targets.push(node);
return node;
}
if (node.component) {
var checkName = node.component.toLowerCase().split('-').join('');
if (componentNames.includes(checkName)) {
targets.push(node);
return node;
}
}
node.component;
node.children;
var __vars__ = node.__vars__,
__expr__ = node.__expr__,
props = _objectWithoutProperties__default["default"](node, _excluded3$1);
var expressions = Object.keys(__expr__ || {});
var variables = Object.keys(__vars__ || {});
for (var prop in props) {
if (variables.includes(prop) || expressions.includes(prop)) {
targets.push(node);
return node;
}
}
return node;
});
return targets;
};
var _excluded = ["watchItem", "callbacks", "container", "recalculateLocation", "offsets"],
_excluded2 = ["children"],
_excluded3 = ["idyllASTNode"],
_excluded4 = ["idyllASTNode"],
_excluded5 = ["component", "children", "idyllASTNode", "key", "__vars__", "__expr__"];
function _createSuper$1(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$1(); return function _createSuperInternal() { var Super = _getPrototypeOf__default["default"](Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf__default["default"](this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn__default["default"](this, result); }; }
function _isNativeReflectConstruct$1() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
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__default["default"](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; }
var updatePropsCallbacks = [];
var updateRefsCallbacks = [];
var scrollWatchers = [];
var scrollOffsets = {};
var refCache = {};
var evalContext = {};
var scrollContainer;
var getLayout$1 = function getLayout(layout) {
return layouts__namespace[layout.trim()] || {};
};
var getTheme$1 = function getTheme(theme) {
return themes__namespace[theme.trim()] || {};
};
var getRefs = function getRefs() {
var refs = {};
if (!scrollContainer) {
return refCache;
}
scrollWatchers.forEach(function (watcher) {
// left and right props assume no horizontal scrolling
var watchItem = watcher.watchItem;
watcher.callbacks;
watcher.container;
watcher.recalculateLocation;
watcher.offsets;
var watcherProps = _objectWithoutProperties__default["default"](watcher, _excluded);
refs[watchItem.dataset.ref] = _objectSpread(_objectSpread(_objectSpread({}, watcherProps), refCache[watchItem.dataset.ref]), {}, {
domNode: watchItem
});
});
return _objectSpread(_objectSpread({}, refCache), refs);
};
var wrapperKey = 0;
var createWrapper = function createWrapper(_ref) {
var theme = _ref.theme,
layout = _ref.layout,
authorView = _ref.authorView,
textEditComponent = _ref.textEditComponent,
userViewComponent = _ref.userViewComponent,
userInlineViewComponent = _ref.userInlineViewComponent,
wrapTextComponents = _ref.wrapTextComponents;
return /*#__PURE__*/function (_React$PureComponent) {
_inherits__default["default"](Wrapper, _React$PureComponent);
var _super = _createSuper$1(Wrapper);
function Wrapper(props) {
var _this;
_classCallCheck__default["default"](this, Wrapper);
_this = _super.call(this, props);
_this.key = wrapperKey++;
_this.ref = {};
_this.onUpdateRefs = _this.onUpdateRefs.bind(_assertThisInitialized__default["default"](_this));
_this.onUpdateProps = _this.onUpdateProps.bind(_assertThisInitialized__default["default"](_this));
var vars = values__default["default"](props.__vars__);
var exps = values__default["default"](props.__expr__);
_this.usesRefs = exps.some(function (v) {
return v && v.includes('refs.');
});
_this.state = {
hasError: false,
error: null
}; // listen for props updates IF we care about them
if (vars.length || exps.length) {
// called with new doc state
// when any component calls updateProps()
updatePropsCallbacks.push(_this.onUpdateProps);
_this.state = _this.onUpdateProps(props.initialState, Object.keys(props), true);
} // listen for ref updates IF we care about them
if (props.hasHook || _this.usesRefs) {
updateRefsCallbacks.push(_this.onUpdateRefs);
}
return _this;
}
_createClass__default["default"](Wrapper, [{
key: "componentDidCatch",
value: function componentDidCatch(error, info) {
this.setState({
hasError: true,
error: error
});
}
}, {
key: "onUpdateProps",
value: function onUpdateProps(newState, changedKeys, initialRender) {
var _this$props = this.props,
__vars__ = _this$props.__vars__,
__expr__ = _this$props.__expr__; // were there changes to any vars we track?
// or vars our expressions reference?
var shouldUpdate = initialRender || changedKeys.some(function (k) {
return values__default["default"](__vars__).includes(k) || values__default["default"](__expr__).some(function (expr) {
return expr.includes(k);
});
}); // if nothing we care about changed bail out and don't re-render
if (!shouldUpdate) return; // update this component's state
var nextState = {}; // pull in the latest value for any tracked vars
Object.keys(__vars__).forEach(function (key) {
nextState[key] = newState[__vars__[key]];
}); // re-run this component's expressions using the latest doc state
Object.keys(__expr__).forEach(function (key) {
nextState[key] = evalExpression(_objectSpread(_objectSpread({}, newState), {}, {
refs: getRefs()
}), __expr__[key], key, evalContext);
});
if (initialRender) {
return Object.assign({
hasError: false
}, nextState);
} // trigger a re-render of this component
// and more importantly, its wrapped component
this.setState(Object.assign({
hasError: false,
error: null
}, nextState));
}
}, {
key: "onUpdateRefs",
value: function onUpdateRefs(newState) {
var __expr__ = this.props.__expr__;
if (this.usesRefs) {
var nextState = {
refs: newState.refs
};
entries__default["default"](__expr__).forEach(function (_ref2) {
var _ref3 = _slicedToArray__default["default"](_ref2, 2),
key = _ref3[0],
val = _ref3[1];
if (!val.includes('refs.')) {
return;
}
nextState[key] = evalExpression(newState, val, key, evalContext);
}); // trigger a render with latest state
this.setState(nextState);
}
}
}, {
key: "componentWillUnmount",
value: function componentWillUnmount() {
var propsIndex = updatePropsCallbacks.indexOf(this.onUpdateProps);
if (propsIndex > -1) updatePropsCallbacks.splice(propsIndex, 1);
var refsIndex = updateRefsCallbacks.indexOf(this.onUpdateRefs);
if (refsIndex > -1) updateRefsCallbacks.splice(refsIndex, 1);
}
}, {
key: "render",
value: function render() {
var _this2 = this;
var state = filterIdyllProps(this.state, this.props.isHTMLNode);
var _filterIdyllProps = filterIdyllProps(this.props, this.props.isHTMLNode),
children = _filterIdyllProps.children,
passThruProps = _objectWithoutProperties__default["default"](_filterIdyllProps, _excluded2);
var childComponent = null;
var uniqueKey = "".concat(this.key, "-help");
var returnComponent = React__default["default"].Children.map(children, function (c, i) {
childComponent = c;
return /*#__PURE__*/React__default["default"].cloneElement(c, _objectSpread(_objectSpread({
key: "".concat(_this2.key, "-").concat(i),
idyll: {
theme: getTheme$1(theme),
layout: getLayout$1(layout),
authorView: authorView
}
}, state), passThruProps));
});
if (this.state.hasError) {
returnComponent = /*#__PURE__*/React__default["default"].createElement("div", {
style: {
border: 'solid red 1px',
padding: 10
}
}, this.state.error.message);
}
var metaData = childComponent.type._idyll;
if (authorView) {
// ensure inline elements do not have this overlay
if (metaData && metaData.name === 'TextContainer' || ['TextContainer', 'DragDropContainer'].includes(childComponent.type.name)) {
return returnComponent;
} else if (textEditComponent && metaData && wrapTextComponents.includes(metaData.name.toLowerCase())) {
var ViewComponent = textEditComponent;
return /*#__PURE__*/React__default["default"].createElement(ViewComponent, {
idyllASTNode: this.props.idyllASTNode
}, childComponent);
} else if (!metaData || metaData.displayType === undefined || metaData.displayType !== 'inline') {
var _ViewComponent = userViewComponent || AuthorTool;
return /*#__PURE__*/React__default["default"].createElement(_ViewComponent, {
idyllASTNode: this.props.idyllASTNode,
component: returnComponent,
authorComponent: childComponent,
uniqueKey: uniqueKey
});
} else if (metaData.displayType === 'inline') {
var InlineViewComponent = userInlineViewComponent || userViewComponent || AuthorTool;
return /*#__PURE__*/React__default["default"].createElement(InlineViewComponent, {
idyllASTNode: this.props.idyllASTNode,
component: returnComponent,
authorComponent: childComponent,
uniqueKey: uniqueKey
});
}
}
return returnComponent;
}
}]);
return Wrapper;
}(React__default["default"].PureComponent);
};
var getDerivedValues = function getDerivedValues(dVars) {
var o = {};
Object.keys(dVars).forEach(function (key) {
return o[key] = dVars[key].value;
});
return o;
};
var IdyllRuntime = /*#__PURE__*/function (_React$PureComponent2) {
_inherits__default["default"](IdyllRuntime, _React$PureComponent2);
var _super2 = _createSuper$1(IdyllRuntime);
function IdyllRuntime(props) {
var _this3;
_classCallCheck__default["default"](this, IdyllRuntime);
_this3 = _super2.call(this, props);
_this3.state = {};
_this3.scrollListener = _this3.scrollListener.bind(_assertThisInitialized__default["default"](_this3));
_this3.initScrollListener = _this3.initScrollListener.bind(_assertThisInitialized__default["default"](_this3));
var ast = filterASTForDocument(props.ast);
var _splitAST = splitAST(idyllAst.getChildren(ast)),
vars = _splitAST.vars,
derived = _splitAST.derived,
data = _splitAST.data;
_splitAST.elements;
var Wrapper = createWrapper({
theme: props.theme,
layout: props.layout,
authorView: props.authorView,
textEditComponent: props.textEditComponent,
userViewComponent: props.userViewComponent,
userInlineViewComponent: props.userInlineViewComponent,
wrapTextComponents: props.wrapTextComponents
});
var hasInitialized = false;
var initialContext = {}; // Initialize a custom context
var _initializeCallbacks = [];
var _mountCallbacks = [];
var _updateCallbacks = [];
_this3._onInitializeState = function () {
_initializeCallbacks.forEach(function (cb) {
cb();
});
};
_this3._onMount = function () {
_mountCallbacks.forEach(function (cb) {
cb();
});
};
_this3._onUpdateState = function (newData) {
_updateCallbacks.forEach(function (cb) {
cb(newData);
});
};
if (typeof props.context === 'function') {
props.context({
update: function update(newState) {
if (!hasInitialized) {
initialContext = Object.assign(initialContext, newState);
} else {
_this3.updateState(newState);
}
},
data: function data() {
return _this3.state;
},
onInitialize: function onInitialize(cb) {
_initializeCallbacks.push(cb);
},
onMount: function onMount(cb) {
_mountCallbacks.push(cb);
},
onUpdate: function onUpdate(cb) {
_updateCallbacks.push(cb);
}
});
}
var dataStore = getData(data, props.datasets);
var initialState = Object.assign({}, _objectSpread(_objectSpread({}, getVars(vars, initialContext)), dataStore.syncData), initialContext, props.initialState ? props.initialState : {});
var asyncDataStore = dataStore.asyncData;
var asyncDataStoreKeys = Object.keys(asyncDataStore);
asyncDataStoreKeys.forEach(function (key) {
_this3.state[key] = asyncDataStore[key].initialValue;
});
asyncDataStoreKeys.map(function (key) {
asyncDataStore[key].dataPromise.then(function (res) {
_this3.updateState(_objectSpread(_objectSpread({}, _this3.state), {}, _defineProperty__default["default"]({}, key, res)));
})["catch"](function (e) {
return console.error('Error while resolving the data' + e);
});
});
var derivedVars = _this3.derivedVars = getVars(derived, initialState);
var state = _this3.state = _objectSpread(_objectSpread(_objectSpread({}, _this3.state), initialState), getDerivedValues(derivedVars));
_this3.updateState = function (newState) {
// merge new doc state with old
var newMergedState = _objectSpread(_objectSpread({}, _this3.state), newState); // update derived values
var newDerivedValues = getDerivedValues(getVars(derived, newMergedState));
var nextState = _objectSpread(_objectSpread({}, newMergedState), newDerivedValues);
var changedMap = {};
var changedKeys = Object.keys(state).reduce(function (acc, k) {
if (!equal__default["default"](state[k], nextState[k])) {
acc.push(k);
changedMap[k] = nextState[k] || state[k];
}
return acc;
}, []); // Update doc state reference.
// We re-use the same object here so that
// IdyllRuntime.state can be accurately checked in tests
state = Object.ass