Liferay.Loader.define("segments-experiment-web@2.0.19/js/components/ClickGoalPicker/ClickGoalPicker.es", ['module', 'exports', 'require', '@frontend-taglib-clay$clayui/button', '@frontend-taglib-clay$clayui/icon', '@frontend-taglib-clay$clayui/layout', '@frontend-taglib-clay$clayui/link', '@frontend-taglib-clay$clayui/tooltip', 'frontend-js-react-web$classnames', 'frontend-js-react-web', 'frontend-js-web', 'frontend-js-react-web$prop-types', 'frontend-js-react-web$react', 'frontend-js-react-web$react-dom', './../../state/context.es', './reducer.es', './utils.es'], function (module, exports, require) {
  var define = undefined;
  var global = window;
  {
    Object.defineProperty(exports, "__esModule", {
      value: true
    });
    exports["default"] = void 0;

    var _button = _interopRequireDefault(require("@frontend-taglib-clay$clayui/button"));

    var _icon = _interopRequireDefault(require("@frontend-taglib-clay$clayui/icon"));

    var _layout = _interopRequireDefault(require("@frontend-taglib-clay$clayui/layout"));

    var _link = _interopRequireDefault(require("@frontend-taglib-clay$clayui/link"));

    var _tooltip = require("@frontend-taglib-clay$clayui/tooltip");

    var _classnames = _interopRequireDefault(require("frontend-js-react-web$classnames"));

    var _frontendJsReactWeb = require("frontend-js-react-web");

    var _frontendJsWeb = require("frontend-js-web");

    var _propTypes = _interopRequireDefault(require("frontend-js-react-web$prop-types"));

    var _react = _interopRequireDefault(require("frontend-js-react-web$react"));

    var _reactDom = _interopRequireDefault(require("frontend-js-react-web$react-dom"));

    var _context = require("./../../state/context.es");

    var _reducer = require("./reducer.es");

    var _utils = require("./utils.es");

    function _interopRequireDefault(obj) {
      return obj && obj.__esModule ? obj : { "default": obj };
    }

    function _slicedToArray(arr, i) {
      return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest();
    }

    function _nonIterableRest() {
      throw new TypeError("Invalid attempt to destructure non-iterable instance");
    }

    function _iterableToArrayLimit(arr, i) {
      if (!(Symbol.iterator in Object(arr) || Object.prototype.toString.call(arr) === "[object Arguments]")) {
        return;
      }var _arr = [];var _n = true;var _d = false;var _e = undefined;try {
        for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
          _arr.push(_s.value);if (i && _arr.length === i) break;
        }
      } catch (err) {
        _d = true;_e = err;
      } finally {
        try {
          if (!_n && _i["return"] != null) _i["return"]();
        } finally {
          if (_d) throw _e;
        }
      }return _arr;
    }

    function _arrayWithHoles(arr) {
      if (Array.isArray(arr)) return arr;
    }

    var useCallback = _react["default"].useCallback,
        useContext = _react["default"].useContext,
        useEffect = _react["default"].useEffect,
        useLayoutEffect = _react["default"].useLayoutEffect,
        useReducer = _react["default"].useReducer,
        useRef = _react["default"].useRef,
        useState = _react["default"].useState;
    var ESCAPE_KEYS = ['Escape', // Most browsers.
    'Esc' // IE and Edge.
    ];
    var POPOVER_PADDING = 16;
    var THROTTLE_INTERVAL_MS = 100;

    var DispatchContext = _react["default"].createContext();
    /**
     * Top-level entry point for displaying, selecting, editing and removing click
     * goal targets.
     */

    function ClickGoalPicker(_ref) {
      var _ref$allowEdit = _ref.allowEdit,
          allowEdit = _ref$allowEdit === void 0 ? true : _ref$allowEdit,
          onSelectClickGoalTarget = _ref.onSelectClickGoalTarget,
          target = _ref.target;

      var _useReducer = useReducer(_reducer.reducer, target, _reducer.getInitialState),
          _useReducer2 = _slicedToArray(_useReducer, 2),
          state = _useReducer2[0],
          dispatch = _useReducer2[1];

      var selectedTarget = state.selectedTarget;

      var _useContext = useContext(_context.StateContext),
          errors = _useContext.errors;

      var ref = useRef(state.selectedTarget);
      useEffect(function () {
        ref.current = selectedTarget;
      }, [selectedTarget]);
      var previousTarget = ref.current;

      if (selectedTarget != previousTarget) {
        if (onSelectClickGoalTarget) {
          onSelectClickGoalTarget(selectedTarget);
        }
      }

      var root = document.getElementById('content');

      if (!root) {
        console.error('Cannot render <SegmentsExperimentsClickGoal /> without #content element', document.querySelectorAll('section').length);
        return null;
      }

      return _react["default"].createElement(DispatchContext.Provider, {
        value: dispatch
      }, _react["default"].createElement(_reducer.StateContext.Provider, {
        value: state
      }, _react["default"].createElement("h4", {
        className: "mb-3 mt-4 sheet-subtitle"
      }, Liferay.Language.get('click-goal'), _react["default"].createElement(_icon["default"], {
        className: "lexicon-icon-sm ml-1 reference-mark text-warning",
        style: {
          verticalAlign: 'super'
        },
        symbol: "asterisk"
      })), state.selectedTarget && _react["default"].createElement(_layout["default"].ContentRow, {
        containerElement: "dl"
      }, _react["default"].createElement(_layout["default"].ContentCol, {
        containerElement: "dt"
      }, Liferay.Language.get('element'), ":"), _react["default"].createElement(_layout["default"].ContentCol, {
        className: "mb-0 ml-2 text-truncate-inline",
        containerElement: "dd",
        expand: true
      }, _react["default"].createElement(_link["default"], {
        className: "text-truncate",
        href: state.selectedTarget,
        onClick: function scrollIntoView(event) {
          var target = document.querySelector(state.selectedTarget);

          if (target) {
            target.scrollIntoView(); // Make sure nothing slides under the top nav.

            window.scrollBy(0, -100);
          }

          event.preventDefault();
          dispatch({
            type: 'activate'
          });
        },
        title: state.selectedTarget
      }, state.selectedTarget))), !state.selectedTarget && _react["default"].createElement("dl", null, _react["default"].createElement("dt", {
        className: "d-inline"
      }, Liferay.Language.get('element'), ":"), _react["default"].createElement("dd", {
        className: "d-inline ml-2 text-secondary"
      }, Liferay.Language.get('a-clickable-element-on-the-page-must-be-selected-to-be-measured'), errors.clickTargetError && _react["default"].createElement("div", {
        className: "font-weight-bold mt-2 text-danger"
      }, _react["default"].createElement(_icon["default"], {
        className: "mr-2",
        symbol: "exclamation-full"
      }), Liferay.Language.get('an-element-needs-to-be-set')))), allowEdit && _react["default"].createElement(_button["default"], {
        displayType: "secondary",
        onClick: function onClick() {
          return dispatch({
            type: 'activate'
          });
        },
        small: true
      }, state.selectedTarget ? Liferay.Language.get('edit-element') : Liferay.Language.get('set-element')), state.mode === 'active' ? _react["default"].createElement(ClickGoalPicker.OverlayContainer, {
        allowEdit: allowEdit,
        root: root
      }) : null));
    }

    /**
     * Responsible for performing the "full-screen takeover" and mounting the
     * <Overlay /> component when active.
     */
    function OverlayContainer(_ref2) {
      var allowEdit = _ref2.allowEdit,
          root = _ref2.root;
      var cssId = 'segments-experiments-click-goal-css-overrides';
      var dispatch = useContext(DispatchContext);
      var targetableElements = useRef(); // Before mount.

      if (!targetableElements.current) {
        var head = document.head;
        // Apply CSS overrides.

        var style = document.createElement('style');
        style.id = cssId;
        style.type = 'text/css';
        style.appendChild(document.createTextNode("\n\t\t\t#banner {\n\t\t\t\tcursor: not-allowed;\n\t\t\t}\n\t\t\t#banner a, #banner button {\n\t\t\t\tcursor: not-allowed;\n\t\t\t\tpointer-events: none;\n\t\t\t}\n\t\t\t#content {\n\t\t\t\tposition: relative;\n\t\t\t\tcursor: not-allowed;\n\t\t\t}\n\n\t\t\t.portlet-content-editable {\n\t\t\t\tborder-color: transparent;\n\t\t\t}\n\n\t\t\t.portlet-topper {\n\t\t\t\tvisibility: hidden;\n\t\t\t}\n\t\t"));
        head.appendChild(style); // This must happen after hiding the toppers.

        targetableElements.current = (0, _utils.getTargetableElements)(root);
      } // On unmount.


      useEffect(function () {
        return function () {
          // Remove CSS overrides.
          var style = document.getElementById(cssId);

          if (style) {
            style.parentNode.removeChild(style);
          }
        };
      }, []);
      var handleKeydown = useCallback(function (event) {
        if (ESCAPE_KEYS.includes(event.key)) {
          dispatch({
            type: 'deactivate'
          });
          event.preventDefault();
          (0, _utils.stopImmediatePropagation)(event);
        }
      }, [dispatch]);
      var handleClick = useCallback(function (event) {
        // Clicking anywhere other than a target aborts target selection.
        event.preventDefault();
        (0, _utils.stopImmediatePropagation)(event);
        dispatch({
          type: 'deactivate'
        });
      }, [dispatch]);
      (0, _frontendJsReactWeb.useEventListener)('keydown', handleKeydown, true, document);
      (0, _frontendJsReactWeb.useEventListener)('click', handleClick, false, document);
      return _reactDom["default"].createPortal(_react["default"].createElement(ClickGoalPicker.Overlay, {
        allowEdit: allowEdit,
        root: root,
        targetableElements: targetableElements.current
      }), root);
    }

    /**
     * Covers the main content surface of the page (the "#content" element)
     * and draws UI over each targetable element.
     */
    function Overlay(_ref3) {
      var allowEdit = _ref3.allowEdit,
          root = _ref3.root,
          targetableElements = _ref3.targetableElements;

      var _useContext2 = useContext(_reducer.StateContext),
          editingTarget = _useContext2.editingTarget,
          selectedTarget = _useContext2.selectedTarget;

      var _useState = useState((0, _utils.getRootElementGeometry)(root)),
          _useState2 = _slicedToArray(_useState, 2),
          geometry = _useState2[0],
          setGeometry = _useState2[1];

      var handleResize = useCallback((0, _frontendJsWeb.throttle)(function () {
        setGeometry((0, _utils.getRootElementGeometry)(root));
      }, THROTTLE_INTERVAL_MS), [root]); // For now, treat scrolling just like resizing.

      (0, _frontendJsReactWeb.useEventListener)('resize', handleResize, false, window); // TODO: also consider scrolling of elements with "overflow: auto/scroll";

      (0, _frontendJsReactWeb.useEventListener)('scroll', handleResize, false, window);
      return _react["default"].createElement("div", {
        className: "lfr-segments-experiment-click-goal-root"
      }, targetableElements.filter(function (element) {
        if (allowEdit === true) {
          return true;
        }

        if ('#' + element.id === selectedTarget) {
          return true;
        }

        return false;
      }).map(function (element) {
        var selector = "#".concat(element.id);
        var mode = editingTarget === selector && allowEdit ? 'editing' : selectedTarget === selector ? 'selected' : 'inactive';
        return _react["default"].createElement(ClickGoalPicker.Target, {
          allowEdit: allowEdit,
          element: element,
          geometry: geometry,
          key: selector,
          mode: mode,
          selector: selector
        });
      }));
    }

    /**
     * Draws three controls above/on-top-of/below a potential click goal target:
     *
     * - A <TargetTopper />, above the target, which labels the target and can be
     *   used to undo the selection of that target.
     * - An rectangle on-top-of the target which can be clicked on to select it.
     * - A <TargetPopover />, below the target, that provides contextual information
     *   and a button to confirm the selection of that target.
     */
    function Target(_ref4) {
      var allowEdit = _ref4.allowEdit,
          element = _ref4.element,
          geometry = _ref4.geometry,
          mode = _ref4.mode,
          selector = _ref4.selector;
      var dispatch = useContext(DispatchContext);

      var _getElementGeometry = (0, _utils.getElementGeometry)(element),
          bottom = _getElementGeometry.bottom,
          height = _getElementGeometry.height,
          left = _getElementGeometry.left,
          right = _getElementGeometry.right,
          top = _getElementGeometry.top,
          width = _getElementGeometry.width;

      if (!bottom && !top && !right && !left) {
        return null;
      }

      // At this point we don't know the dimensions of our children, but we do
      // know whether we have more space on the left or right of our target, so we
      // flip based on that.


      var spaceOnLeft = left - geometry.left;
      var spaceOnRight = geometry.right - right;
      var spaceOnTop = top - geometry.top;
      var align = spaceOnRight > spaceOnLeft ? 'left' : 'right'; // TODO: make tooltip match mock and switch to Clay v3 tooltips directly
      // instead of using lfr-portal-tooltip.

      return _react["default"].createElement("div", {
        className: "lfr-segments-experiment-click-goal-target",
        style: {
          alignItems: align === 'left' ? 'flex-start' : 'flex-end',
          left: align === 'left' ? spaceOnLeft : null,
          right: align === 'right' ? spaceOnRight : null,
          top: spaceOnTop
        }
      }, _react["default"].createElement(_tooltip.ClayTooltipProvider, null, _react["default"].createElement("div", {
        className: (0, _classnames["default"])('lfr-segments-experiment-click-goal-target-overlay', {
          'lfr-segments-experiment-click-goal-target-overlay-editing': mode === 'editing',
          'lfr-segments-experiment-click-goal-target-overlay-selected': mode === 'selected'
        }),
        "data-target-selector": selector,
        "data-tooltip-align": "bottom-left",
        onClick: function handleClick(event) {
          dispatch({
            selector: selector,
            type: 'editTarget'
          });
          (0, _utils.stopImmediatePropagation)(event);
        },
        style: {
          height: height,
          width: width
        },
        title: mode === 'inactive' ? Liferay.Language.get('click-element-to-set-as-click-target-for-your-goal') : ''
      })), mode !== 'inactive' && _react["default"].createElement(ClickGoalPicker.TargetTopper, {
        allowEdit: allowEdit,
        element: element,
        geometry: geometry,
        isEditing: mode === 'editing',
        selector: selector
      }), mode === 'editing' && _react["default"].createElement(ClickGoalPicker.TargetPopover, {
        selector: selector
      }));
    }

    /**
     * Drawn above a click target, and includes a button to undo the selection of
     * that target.
     */
    function TargetTopper(_ref5) {
      var allowEdit = _ref5.allowEdit,
          geometry = _ref5.geometry,
          isEditing = _ref5.isEditing,
          selector = _ref5.selector;
      var dispatch = useContext(DispatchContext);
      var topperRef = useRef();

      var _useState3 = useState(0),
          _useState4 = _slicedToArray(_useState3, 2),
          top = _useState4[0],
          setTop = _useState4[1];

      var _useState5 = useState(null),
          _useState6 = _slicedToArray(_useState5, 2),
          width = _useState6[0],
          setWidth = _useState6[1];

      useLayoutEffect(function () {
        if (topperRef.current) {
          var _topperRef$current$ge = topperRef.current.getBoundingClientRect(),
              height = _topperRef$current$ge.height,
              left = _topperRef$current$ge.left,
              _width = _topperRef$current$ge.width;

          setTop(-height);
          setWidth(Math.min(geometry.width - (left - geometry.left), _width));
        }
      }, [geometry.left, geometry.width]);

      return _react["default"].createElement("div", {
        className: (0, _classnames["default"])({
          'd-flex': true,
          'lfr-segments-experiment-click-goal-target-topper': true,
          'lfr-segments-experiment-click-goal-target-topper-editing': isEditing,
          'px-2': true,
          small: true,
          'text-white': true
        }),
        onClick: _utils.stopImmediatePropagation,
        ref: topperRef,
        style: {
          maxWidth: width !== null ? "".concat(width, "px") : null,
          top: "".concat(top, "px")
        }
      }, _react["default"].createElement("span", {
        className: "mr-2 text-truncate"
      }, isEditing ? selector : Liferay.Language.get('target')), allowEdit && _react["default"].createElement(_button["default"], {
        className: "lfr-segments-experiment-click-goal-target-delete small text-white",
        displayType: "unstyled",
        onClick: function handleClick(event) {
          (0, _utils.stopImmediatePropagation)(event);
          dispatch({
            selector: '',
            type: 'selectTarget'
          });
        }
      }, _react["default"].createElement(_icon["default"], {
        symbol: "times-circle"
      })));
    }

    /**
     * Drawn below a click target, and provides contextual information and a button
     * to confirm the selection of that target.
     */
    function TargetPopover(_ref6) {
      var selector = _ref6.selector;
      var dispatch = useContext(DispatchContext);
      var buttonRef = useRef();

      var _useState7 = useState(null),
          _useState8 = _slicedToArray(_useState7, 2),
          buttonWidth = _useState8[0],
          setButtonWidth = _useState8[1];

      useLayoutEffect(function () {
        if (buttonRef.current) {
          setButtonWidth(buttonRef.current.offsetWidth);
        }
      }, []); // The +1 here is to avoid unwanted wrapping of the button.

      var maxWidth = buttonWidth ? "".concat(buttonWidth + POPOVER_PADDING * 2 + 1, "px") : 'none';

      return _react["default"].createElement("div", {
        className: "lfr-segments-experiment-click-goal-target-popover p-3",
        onClick: _utils.stopImmediatePropagation,
        style: {
          maxWidth: maxWidth
        }
      }, _react["default"].createElement("div", {
        className: "mb-2 text-secondary text-truncate",
        title: selector
      }, selector), _react["default"].createElement(_button["default"], {
        onClick: function handleClick() {
          dispatch({
            selector: selector,
            type: 'selectTarget'
          });
        },
        ref: buttonRef
      }, Liferay.Language.get('set-element-as-click-target')));
    }

    ClickGoalPicker.Overlay = Overlay;
    ClickGoalPicker.OverlayContainer = OverlayContainer;
    ClickGoalPicker.Target = Target;
    ClickGoalPicker.TargetPopover = TargetPopover;
    ClickGoalPicker.TargetTopper = TargetTopper;
    var _default = ClickGoalPicker;
    exports["default"] = _default;
    //# sourceMappingURL=ClickGoalPicker.es.js.map
  }
});
//# sourceMappingURL=ClickGoalPicker.es.js.map