System.register(["reactive-jsx", "./ui-aexpr.js", "active-expression"], function (_export, _context) {
  "use strict";

  var _children, _attributeStringLiteral, _attributes, _element, toDOMNode, ActiveExpression;

  return {
    setters: [function (_reactiveJsx) {
      _children = _reactiveJsx.children;
      _attributeStringLiteral = _reactiveJsx.attributeStringLiteral;
      _attributes = _reactiveJsx.attributes;
      _element = _reactiveJsx.element;
    }, function (_uiAexprJs) {
      toDOMNode = _uiAexprJs.toDOMNode;
    }, function (_activeExpression) {
      ActiveExpression = _activeExpression.BaseActiveExpression;
    }],
    execute: function () {
      _recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js = _recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js || {};
      _recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.childSpread = childSpread;
      _recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.childExpression = childExpression;
      _recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.childElement = childElement;
      _recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.childText = childText;
      _recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.children = children;
      _recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.attributeSpread = attributeSpread;
      _recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.attributeExpression = attributeExpression;
      _recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.attributeEmpty = attributeEmpty;
      _recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.attributeStringLiteral = attributeStringLiteral;
      _recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.attributes = attributes;
      _recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.element = element;
      _recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.addSourceLocation = addSourceLocation;
      _recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.composeElement = composeElement;
      _recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.isActiveGroup = isActiveGroup;
      _recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.ensureDOMNode = ensureDOMNode;
      _recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.getExpressionNode = getExpressionNode;
      _recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.getErrorNode = getErrorNode;
      _recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.getPendingNode = getPendingNode;
      _recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.basicCreateElement = basicCreateElement;
      _recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.addMetaData = addMetaData;
      _recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.toDOMNode = toDOMNode;
      _recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.ActiveExpression = ActiveExpression;


      /**
       * Resources for JSX Semantics
       * Web components in react: https://facebook.github.io/react/docs/web-components.html
       * Child lists and keys: https://facebook.github.io/react/docs/lists-and-keys.html
       * JSX babel transform helpers: https://github.com/babel/babel/blob/7.0/packages/babel-helper-builder-react-jsx/src/index.js
       */

      function addMetaData(element, data = {}) {
        return element.jsxMetaData = Object.assign(element.jsxMetaData || {}, data);
      }

      function basicCreateElement(tagName) {
        const element = document.createElement(tagName);

        _recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.addMetaData(element, { timeOffset: performance.now() });

        return element;
      }

      // cannot use JSX elements in implementation of JSX elements :(
      function getPendingNode() {
        const icon = _recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.basicCreateElement("i");
        icon.classList.add("fa", "fa-spinner", "fa-pulse", "fa-fw");
        const span = document.createElement("span");
        span.style.color = "yellow";
        span.appendChild(icon);
        span.appendChild(document.createTextNode("pending"));
        return span;
      }

      function getErrorNode(e) {
        const icon = _recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.basicCreateElement("i");
        icon.classList.add("fa", "fa-exclamation-triangle");
        const span = document.createElement("span");
        span.style.color = "red";
        span.appendChild(icon);
        span.appendChild(document.createTextNode(e));
        return span;
      }

      function getExpressionNode(expression) {
        if (expression instanceof Promise) {
          let promNode = _recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.getPendingNode();
          expression.then(val => promNode.replaceWith(_recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.getExpressionNode(val))).catch(e => promNode.replaceWith(_recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.getErrorNode(e)));
          return promNode;
        }
        if (expression instanceof _recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.ActiveExpression) {
          return _recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.toDOMNode.call(expression, value => {
            const node = _recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.getExpressionNode(value);
            // TODO: jsx-ray does not work on TextNodes, yet
            _recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.addMetaData(_recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.element, { aexpr: expression });
            return node;
          });
        }
        return _recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.ensureDOMNode(expression);
      }

      function ensureDOMNode(nodeOrObject) {
        if (nodeOrObject instanceof Node) {
          return nodeOrObject;
        }

        // Symbols needexplicitly need to be converted to strings
        if (typeof nodeOrObject === 'symbol') {
          return document.createTextNode(nodeOrObject.toString());
        }

        return document.createTextNode(nodeOrObject);
      }

      function isActiveGroup(obj) {
        return obj && obj.isActiveGroup;
      }

      function composeElement(tagElement, attributes, children) {
        for (let [key, value] of Object.entries(attributes)) {
          if (value instanceof Function) {
            // functions provided as attributes are used to create event listeners
            tagElement.addEventListener(key, value);
          } else {
            tagElement.setAttribute(key, value.toString());
          }
        }

        const roqsByReferenceNode = new WeakMap();
        function handleActiveGroup(nodeOrActiveGroup) {
          if (_recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.isActiveGroup(nodeOrActiveGroup)) {
            const referenceNode = _element("unused", _attributes(_attributeStringLiteral("style", "position: absotule")), _children(), {
              file: 'https://lively-kernel.org/lively4/rp19-jsx/src/client/reactive/reactive-jsx/reactive-jsx.js',
              end: {
                column: 72,
                line: 93
              },
              start: {
                column: 28,
                line: 93
              }
            });
            roqsByReferenceNode.set(referenceNode, nodeOrActiveGroup);
            return referenceNode; // use to insert elements of the ActiveGroup in the corresponding place
          } else {
            return nodeOrActiveGroup;
          }
        }
        function initActiveGroup(referenceNode) {
          if (roqsByReferenceNode.has(referenceNode)) {
            const activeGroup = roqsByReferenceNode.get(referenceNode);

            activeGroup.map(item => {
              const node = _recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.getExpressionNode(item);
              _recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.addMetaData(node, { item, activeGroup });
              return node;
            }).enter(node => {
              referenceNode.parentNode.insertBefore(node, referenceNode);
            }).exit(node => node.remove());
          }
        }

        children.map(handleActiveGroup).map(_recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.ensureDOMNode).forEach(child => {
          tagElement.appendChild(child);
          initActiveGroup(child);
        });

        return tagElement;
      }

      const isPromiseForJSXElement = Symbol('isPromiseForJSXElement');

      _export("isPromiseForJSXElement", isPromiseForJSXElement);

      _recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.isPromiseForJSXElement = isPromiseForJSXElement;
      function addSourceLocation(element, sourceLocation) {
        if (sourceLocation) {
          _recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.addMetaData(element, { sourceLocation });
        }
      }

      function element(tagName, attributes, children, sourceLocation) {
        const isWebComponent = tagName.includes('-');
        const handleAsync = isWebComponent || children.some(child => child && child instanceof Promise && child[_recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.isPromiseForJSXElement]);
        if (handleAsync) {
          let resolvedTag;
          const returnPromise = Promise.resolve(isWebComponent ? lively.create(tagName) : _recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.basicCreateElement(tagName)).then(element => {
            resolvedTag = element;
            _recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.addSourceLocation(resolvedTag, sourceLocation);
            return Promise.all(children.map(c => Promise.resolve(c)));
          }).then(resolvedChildren => _recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.composeElement(resolvedTag, attributes, resolvedChildren));
          returnPromise[_recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.isPromiseForJSXElement] = true;
          return returnPromise;
        } else {
          const tag = _recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.basicCreateElement(tagName);
          _recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.addSourceLocation(tag, sourceLocation);
          return _recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.composeElement(tag, attributes, children);
        }
      }

      _export("element", element);

      function attributes(...attrs) {
        return Object.assign({}, ...attrs);
      }

      _export("attributes", attributes);

      function attributeStringLiteral(key, value) {
        return { [key]: value };
      }

      _export("attributeStringLiteral", attributeStringLiteral);

      function attributeEmpty(key) {
        return { [key]: key };
      }

      _export("attributeEmpty", attributeEmpty);

      function attributeExpression(key, value) {
        return { [key]: value };
      }

      _export("attributeExpression", attributeExpression);

      function attributeSpread(obj) {
        return obj;
      }

      _export("attributeSpread", attributeSpread);

      function children(...children) {
        return [].concat(...children);
      }

      _export("children", children);

      function childText(text) {
        return [_recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.ensureDOMNode(text)];
      }

      _export("childText", childText);

      function childElement(jSXElement) {
        return [jSXElement];
      }

      // can take:
      // - a DOM node
      // - a JavaScript object or primitive
      // - a Promise
      // - an Active Expression

      _export("childElement", childElement);

      function childExpression(expression) {
        return [_recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.getExpressionNode(expression)];
      }

      _export("childExpression", childExpression);

      function childSpread(array) {
        // #TODO: <ul>{active-group}</ul> also gets the reactive behavior, do we want this?
        if (_recorder_._src_client_reactive_reactive_jsx_reactive_jsx_js.isActiveGroup(array)) {
          return [array];
        } else {
          return array;
        }
      }

      _export("childSpread", childSpread);
    }
  };
});