UNPKG

idyll-document

Version:

The Idyll runtime, implemented as a React component.

1,274 lines (1,067 loc) 63.6 kB
'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