text: "use strict";
  Object.defineProperty(exports, "__esModule", { value: true });
  exports.Toolbar = exports.toolbarClassName = void 0;
  var tslib_1 = require("tslib");
  var accessibility_1 = require("@fluentui/accessibility");
  var react_bindings_1 = require("@fluentui/react-bindings");
  var react_component_event_listener_1 = require("@fluentui/react-component-event-listener");
  var react_component_ref_1 = require("@fluentui/react-component-ref");
  var react_icons_northstar_1 = require("@fluentui/react-icons-northstar");
  var customPropTypes = require("@fluentui/react-proptypes");
  var _ = require("lodash");
  var PropTypes = require("prop-types");
  var React = require("react");
  var utils_1 = require("../../utils");
  var ToolbarCustomItem_1 = require("./ToolbarCustomItem");
  var ToolbarDivider_1 = require("./ToolbarDivider");
  var ToolbarItem_1 = require("./ToolbarItem");
  var ToolbarItemWrapper_1 = require("./ToolbarItemWrapper");
  var ToolbarItemIcon_1 = require("./ToolbarItemIcon");
  var ToolbarMenu_1 = require("./ToolbarMenu");
  var ToolbarMenuDivider_1 = require("./ToolbarMenuDivider");
  var ToolbarMenuItem_1 = require("./ToolbarMenuItem");
  var ToolbarMenuRadioGroup_1 = require("./ToolbarMenuRadioGroup");
  var ToolbarMenuRadioGroupWrapper_1 = require("./ToolbarMenuRadioGroupWrapper");
  var ToolbarRadioGroup_1 = require("./ToolbarRadioGroup");
  var toolbarVariablesContext_1 = require("./toolbarVariablesContext");
  var ToolbarMenuItemSubmenuIndicator_1 = require("./ToolbarMenuItemSubmenuIndicator");
  var ToolbarMenuItemIcon_1 = require("./ToolbarMenuItemIcon");
  var ToolbarMenuItemActiveIndicator_1 = require("./ToolbarMenuItemActiveIndicator");
  var toolbarMenuContext_1 = require("./toolbarMenuContext");
  var Box_1 = require("../Box/Box");
  var WAS_FOCUSABLE_ATTRIBUTE = 'data-was-focusable';
  exports.toolbarClassName = 'ui-toolbar';
  /**
   * A Toolbar is a container for grouping a set of controls, often action controls (e.g. buttons) or input controls (e.g. checkboxes).
   *
   * @accessibility
   *  * Implements [ARIA Toolbar](https://www.w3.org/TR/wai-aria-practices-1.1/#toolbar) design pattern.
   * @accessibilityIssues
   * [Issue 988424: VoiceOver narrates selected for button in toolbar](https://bugs.chromium.org/p/chromium/issues/detail?id=988424)
   * [In toolbars that can toggle items in a menu, VoiceOver narrates "1" for menuitemcheckbox/radio when checked.](https://github.com/microsoft/fluentui/issues/14064)
   */
  exports.Toolbar = react_bindings_1.compose(function (props, ref, composeOptions) {
      var context = react_bindings_1.useFluentContext();
      var _a = react_bindings_1.useTelemetry(composeOptions.displayName, context.telemetry), setStart = _a.setStart, setEnd = _a.setEnd;
      setStart();
      var accessibility = props.accessibility, className = props.className, children = props.children, design = props.design, getOverflowItems = props.getOverflowItems, items = props.items, overflow = props.overflow, overflowItem = props.overflowItem, overflowOpen = props.overflowOpen, overflowSentinel = props.overflowSentinel, styles = props.styles, variables = props.variables;
      var overflowContainerRef = React.useRef();
      var overflowItemWrapperRef = React.useRef();
      var overflowSentinelRef = React.useRef();
      var offsetMeasureRef = React.useRef();
      var containerRef = React.useRef();
      // index of the last visible item in Toolbar, the rest goes to overflow menu
      var lastVisibleItemIndex = React.useRef();
      var animationFrameId = React.useRef();
      var getA11Props = react_bindings_1.useAccessibility(accessibility, {
          debugName: composeOptions.displayName,
          rtl: context.rtl,
      });
      var classes = react_bindings_1.useStyles(composeOptions.displayName, {
          className: exports.toolbarClassName,
          composeOptions: composeOptions,
          mapPropsToStyles: function () { return ({
              overflowOpen: overflowOpen,
          }); },
          mapPropsToInlineStyles: function () { return ({
              className: className,
              design: design,
              styles: styles,
              variables: variables,
          }); },
          rtl: context.rtl,
          unstable_props: props,
      }).classes;
      var ElementType = react_bindings_1.getElementType(props);
      var slotProps = composeOptions.resolveSlotProps(props);
      var unhandledProps = react_bindings_1.useUnhandledProps(composeOptions.handledProps, props);
      var hide = function (el) {
          if (el.style.visibility === 'hidden') {
              return;
          }
          if (context.target.activeElement === el || el.contains(context.target.activeElement)) {
              if (containerRef.current) {
                  var firstFocusableItem = react_bindings_1.getFirstFocusable(containerRef.current, containerRef.current.firstElementChild);
                  if (firstFocusableItem) {
                      firstFocusableItem.focus();
                  }
              }
          }
          el.style.visibility = 'hidden';
          var wasFocusable = el.getAttribute(accessibility_1.IS_FOCUSABLE_ATTRIBUTE);
          if (wasFocusable) {
              el.setAttribute(WAS_FOCUSABLE_ATTRIBUTE, wasFocusable);
          }
          el.setAttribute(accessibility_1.IS_FOCUSABLE_ATTRIBUTE, 'false');
      };
      var show = function (el) {
          if (el.style.visibility !== 'hidden') {
              return false;
          }
          el.style.visibility = '';
          var wasFocusable = el.getAttribute(WAS_FOCUSABLE_ATTRIBUTE);
          if (wasFocusable) {
              el.setAttribute(accessibility_1.IS_FOCUSABLE_ATTRIBUTE, wasFocusable);
              el.removeAttribute(WAS_FOCUSABLE_ATTRIBUTE);
          }
          else {
              el.removeAttribute(accessibility_1.IS_FOCUSABLE_ATTRIBUTE);
          }
          return true;
      };
      /**
       * Checks if `item` overflows a `container`.
       * TODO: check and fix all margin combination
       */
      var isItemOverflowing = function (itemBoundingRect, containerBoundingRect) {
          return itemBoundingRect.right > containerBoundingRect.right || itemBoundingRect.left < containerBoundingRect.left;
      };
      /**
       * Checks if `item` would collide with eventual position of `overflowItem`.
       */
      var wouldItemCollide = function ($item, itemBoundingRect, overflowItemBoundingRect, containerBoundingRect) {
          var actualWindow = context.target.defaultView;
          var wouldCollide;
          if (context.rtl) {
              var itemLeftMargin = parseFloat(actualWindow.getComputedStyle($item).marginLeft) || 0;
              wouldCollide =
                  itemBoundingRect.left - overflowItemBoundingRect.width - itemLeftMargin < containerBoundingRect.left;
              // console.log('Collision [RTL]', {
              //   wouldCollide,
              //   'itemBoundingRect.left': itemBoundingRect.left,
              //   'overflowItemBoundingRect.width': overflowItemBoundingRect.width,
              //   itemRightMargin: itemLeftMargin,
              //   sum: itemBoundingRect.left - overflowItemBoundingRect.width - itemLeftMargin,
              //   'overflowContainerBoundingRect.left': containerBoundingRect.left,
              // })
          }
          else {
              var itemRightMargin = parseFloat(actualWindow.getComputedStyle($item).marginRight) || 0;
              wouldCollide =
                  itemBoundingRect.right + overflowItemBoundingRect.width + itemRightMargin > containerBoundingRect.right;
              // console.log('Collision', {
              //   wouldCollide,
              //   'itemBoundingRect.right': itemBoundingRect.right,
              //   'overflowItemBoundingRect.width': overflowItemBoundingRect.width,
              //   itemRightMargin,
              //   sum: itemBoundingRect.right + overflowItemBoundingRect.width + itemRightMargin,
              //   'overflowContainerBoundingRect.right': containerBoundingRect.right,
              // })
          }
          return wouldCollide;
      };
      /**
       * Positions overflowItem next to lastVisible item
       * TODO: consider overflowItem margin
       */
      var setOverflowPosition = function ($overflowItem, $lastVisibleItem, lastVisibleItemRect, containerBoundingRect, absolutePositioningOffset) {
          var actualWindow = context.target.defaultView;
          if ($lastVisibleItem) {
              if (context.rtl) {
                  var lastVisibleItemMarginLeft = parseFloat(actualWindow.getComputedStyle($lastVisibleItem).marginLeft) || 0;
                  $overflowItem.style.right = containerBoundingRect.right -
                      lastVisibleItemRect.left +
                      lastVisibleItemMarginLeft +
                      absolutePositioningOffset.horizontal + "px";
              }
              else {
                  var lastVisibleItemRightMargin = parseFloat(actualWindow.getComputedStyle($lastVisibleItem).marginRight) || 0;
                  $overflowItem.style.left = lastVisibleItemRect.right -
                      containerBoundingRect.left +
                      lastVisibleItemRightMargin +
                      absolutePositioningOffset.horizontal + "px";
              }
          }
          else {
              // there is no last visible item -> position the overflow as the first item
              lastVisibleItemIndex.current = -1;
              if (context.rtl) {
                  $overflowItem.style.right = absolutePositioningOffset.horizontal + "px";
              }
              else {
                  $overflowItem.style.left = absolutePositioningOffset.horizontal + "px";
              }
          }
      };
      var hideOverflowItems = function () {
          var $overflowContainer = overflowContainerRef.current;
          var $overflowItem = overflowItemWrapperRef.current;
          var $overflowSentinel = overflowSentinelRef.current;
          var $offsetMeasure = offsetMeasureRef.current;
          if (!$overflowContainer || !$overflowItem || !$offsetMeasure) {
              return;
          }
          // workaround: when resizing window with popup opened the container contents scroll for some reason
          if (context.rtl) {
              $overflowContainer.scrollTo(Number.MAX_SAFE_INTEGER, 0);
          }
          else {
              $overflowContainer.scrollTop = 0;
              $overflowContainer.scrollLeft = 0;
          }
          var $items = $overflowContainer.children;
          var overflowContainerBoundingRect = $overflowContainer.getBoundingClientRect();
          var overflowItemBoundingRect = $overflowItem.getBoundingClientRect();
          var offsetMeasureBoundingRect = $offsetMeasure.getBoundingClientRect();
          // Absolute positioning offset
          // Overflow menu is absolutely positioned relative to root slot
          // If there is padding set on the root slot boundingClientRect computations use inner content box,
          // but absolute position is relative to root slot's PADDING box.
          // We compute absolute positioning offset
          // By measuring position of an offsetMeasure element absolutely positioned to 0,0.
          // TODO: replace by getComputedStyle('padding')
          var absolutePositioningOffset = {
              horizontal: context.rtl
                  ? offsetMeasureBoundingRect.right - overflowContainerBoundingRect.right
                  : overflowContainerBoundingRect.left - offsetMeasureBoundingRect.left,
              vertical: overflowContainerBoundingRect.top - offsetMeasureBoundingRect.top,
          };
          var isOverflowing = false;
          var $lastVisibleItem;
          var lastVisibleItemRect;
          // check all items from the last one back
          _.forEachRight($items, function ($item, i) {
              if ($item === $overflowItem || $item === $overflowSentinel) {
                  return true;
              }
              var itemBoundingRect = $item.getBoundingClientRect();
              // if the item is out of the crop rectangle, hide it
              if (isItemOverflowing(itemBoundingRect, overflowContainerBoundingRect)) {
                  isOverflowing = true;
                  // console.log('Overflow', i, {
                  //   item: [itemBoundingRect.left, itemBoundingRect.right],
                  //   crop: [
                  //     overflowContainerBoundingRect.left,
                  //     overflowContainerBoundingRect.right,
                  //     overflowContainerBoundingRect.width,
                  //   ],
                  //   container: $overflowContainer,
                  // })
                  hide($item);
                  return true;
              }
              // if there is an overflow, check collision of remaining items with eventual overflow position
              if (isOverflowing &&
                  !$lastVisibleItem &&
                  wouldItemCollide($item, itemBoundingRect, overflowItemBoundingRect, overflowContainerBoundingRect)) {
                  hide($item);
                  return true;
              }
              // Remember the last visible item
              if (!$lastVisibleItem) {
                  $lastVisibleItem = $item;
                  lastVisibleItemRect = itemBoundingRect;
                  lastVisibleItemIndex.current = i;
              }
              return show($item); // exit the loop when first visible item is found
          });
          // if there is an overflow,  position and show overflow item, otherwise hide it
          if (isOverflowing || overflowOpen) {
              $overflowItem.style.position = 'absolute';
              setOverflowPosition($overflowItem, $lastVisibleItem, lastVisibleItemRect, overflowContainerBoundingRect, absolutePositioningOffset);
              show($overflowItem);
          }
          else {
              lastVisibleItemIndex.current = items.length - 1;
              hide($overflowItem);
          }
          _.invoke(props, 'onOverflow', lastVisibleItemIndex.current + 1);
      };
      var collectOverflowItems = function () {
          // console.log('getOverflowItems()', items.slice(lastVisibleItemIndex.current + 1))
          return getOverflowItems
              ? getOverflowItems(lastVisibleItemIndex.current + 1)
              : items.slice(lastVisibleItemIndex.current + 1);
      };
      var getVisibleItems = function () {
          // console.log('allItems()', items)
          var end = overflowOpen ? lastVisibleItemIndex.current + 1 : items.length;
          // console.log('getVisibleItems()', items.slice(0, end))
          return items.slice(0, end);
      };
      var handleWindowResize = _.debounce(function (e) {
          hideOverflowItems();
          if (overflowOpen) {
              _.invoke(props, 'onOverflowOpenChange', e, tslib_1.__assign(tslib_1.__assign({}, props), { overflowOpen: false }));
          }
      }, 16);
      var renderItems = function (items) {
          return _.map(items, function (item) {
              var kind = _.get(item, 'kind', 'item');
              switch (kind) {
                  case 'divider':
                      return utils_1.createShorthand(composeOptions.slots.divider, item, {
                          defaultProps: function () { return slotProps.divider; },
                      });
                  case 'group':
                      return utils_1.createShorthand(composeOptions.slots.group, item, {
                          defaultProps: function () { return slotProps.group; },
                      });
                  case 'toggle':
                      return utils_1.createShorthand(composeOptions.slots.toggle, item, {
                          defaultProps: function () { return slotProps.toggle; },
                      });
                  case 'custom':
                      return utils_1.createShorthand(composeOptions.slots.customItem, item, {
                          defaultProps: function () { return slotProps.customItem; },
                      });
                  default:
                      return utils_1.createShorthand(composeOptions.slots.item, item, {
                          defaultProps: function () { return slotProps.item; },
                      });
              }
          });
      };
      var renderOverflowItem = function (overflowItem) {
          return utils_1.createShorthand(composeOptions.slots.overflowItem, overflowItem, {
              defaultProps: function () { return slotProps.overflowItem; },
              overrideProps: function (predefinedProps) {
                  var _a;
                  return ({
                      menu: {
                          items: overflowOpen ? collectOverflowItems() : [],
                          popper: tslib_1.__assign({ positionFixed: true }, (_a = predefinedProps.menu) === null || _a === void 0 ? void 0 : _a.popper),
                      },
                      menuOpen: overflowOpen,
                      onMenuOpenChange: function (e, _a) {
                          var menuOpen = _a.menuOpen;
                          _.invoke(props, 'onOverflowOpenChange', e, tslib_1.__assign(tslib_1.__assign({}, props), { overflowOpen: menuOpen }));
                      },
                      wrapper: {
                          ref: overflowItemWrapperRef,
                      },
                  });
              },
          });
      };
      // renders a sentinel div that maintains the toolbar dimensions when the the overflow menu is open
      // hidden elements are removed from the DOM
      var renderOverflowSentinel = function () { return (React.createElement(react_component_ref_1.Ref, { innerRef: function (element) {
              overflowSentinelRef.current = element;
          } }, Box_1.Box.create(overflowSentinel, {
          defaultProps: function () { return ({
              id: 'sentinel',
              className: classes.overflowSentinel,
          }); },
      }))); };
      React.useEffect(function () {
          var actualWindow = context.target.defaultView;
          actualWindow.cancelAnimationFrame(animationFrameId.current);
          // Heads up! There are cases (like opening a portal and rendering the Toolbar there immediately) when rAF is necessary
          animationFrameId.current = actualWindow.requestAnimationFrame(function () {
              hideOverflowItems();
          });
          return function () {
              var _a;
              if (animationFrameId.current !== undefined) {
                  (_a = context.target.defaultView) === null || _a === void 0 ? void 0 : _a.cancelAnimationFrame(animationFrameId.current);
                  animationFrameId.current = undefined;
              }
          };
      });
      var element = overflow ? (React.createElement(React.Fragment, null,
          React.createElement(react_component_ref_1.Ref, { innerRef: function (node) {
                  containerRef.current = node;
                  react_component_ref_1.handleRef(ref, node);
              } }, getA11Props.unstable_wrapWithFocusZone(React.createElement(ElementType, tslib_1.__assign({}, getA11Props('root', tslib_1.__assign({ className: classes.root }, unhandledProps))),
              React.createElement("div", { className: classes.overflowContainer, ref: overflowContainerRef },
                  React.createElement(toolbarMenuContext_1.ToolbarMenuContextProvider, { value: { slots: { menu: composeOptions.slots.menu } } },
                      React.createElement(toolbarVariablesContext_1.ToolbarVariablesProvider, { value: variables },
                          utils_1.childrenExist(children) ? children : renderItems(getVisibleItems()),
                          overflowSentinel && renderOverflowSentinel(),
                          renderOverflowItem(overflowItem)))),
              React.createElement("div", { className: classes.offsetMeasure, ref: offsetMeasureRef })))),
          React.createElement(react_component_event_listener_1.EventListener, { listener: handleWindowResize, target: context.target.defaultView, type: "resize" }))) : (React.createElement(react_component_ref_1.Ref, { innerRef: function (node) {
              containerRef.current = node;
              react_component_ref_1.handleRef(ref, node);
          } }, getA11Props.unstable_wrapWithFocusZone(React.createElement(ElementType, tslib_1.__assign({}, getA11Props('root', tslib_1.__assign({ className: classes.root }, unhandledProps))),
          React.createElement(toolbarMenuContext_1.ToolbarMenuContextProvider, { value: { slots: { menu: composeOptions.slots.menu } } },
              React.createElement(toolbarVariablesContext_1.ToolbarVariablesProvider, { value: variables }, utils_1.childrenExist(children) ? children : renderItems(items)))))));
      setEnd();
      return element;
  }, {
      className: exports.toolbarClassName,
      displayName: 'Toolbar',
      slots: {
          customItem: ToolbarCustomItem_1.ToolbarCustomItem,
          divider: ToolbarDivider_1.ToolbarDivider,
          item: ToolbarItem_1.ToolbarItem,
          group: ToolbarRadioGroup_1.ToolbarRadioGroup,
          toggle: ToolbarItem_1.ToolbarItem,
          overflowItem: ToolbarItem_1.ToolbarItem,
          menu: ToolbarMenu_1.ToolbarMenu,
      },
      slotProps: function () { return ({
          toggle: {
              accessibility: accessibility_1.toggleButtonBehavior,
          },
          overflowItem: {
              icon: React.createElement(react_icons_northstar_1.MoreIcon, { outline: true }),
          },
      }); },
      shorthandConfig: { mappedProp: 'content' },
      handledProps: [
          'accessibility',
          'as',
          'children',
          'className',
          'content',
          'design',
          'getOverflowItems',
          'items',
          'onOverflow',
          'onOverflowOpenChange',
          'overflow',
          'overflowItem',
          'overflowOpen',
          'overflowSentinel',
          'styles',
          'variables',
      ],
  });
  exports.Toolbar.propTypes = tslib_1.__assign(tslib_1.__assign({}, utils_1.commonPropTypes.createCommon()), { items: customPropTypes.collectionShorthandWithKindProp(['divider', 'item', 'group', 'toggle', 'custom']), overflow: PropTypes.bool, overflowOpen: PropTypes.bool, overflowSentinel: customPropTypes.shorthandAllowingChildren, overflowItem: customPropTypes.shorthandAllowingChildren, onOverflow: PropTypes.func, onOverflowOpenChange: PropTypes.func, getOverflowItems: PropTypes.func });
  exports.Toolbar.defaultProps = {
      accessibility: accessibility_1.toolbarBehavior,
      items: [],
      overflowItem: {},
      overflowSentinel: {},
  };
  exports.Toolbar.CustomItem = ToolbarCustomItem_1.ToolbarCustomItem;
  exports.Toolbar.Divider = ToolbarDivider_1.ToolbarDivider;
  exports.Toolbar.Item = ToolbarItem_1.ToolbarItem;
  exports.Toolbar.ItemWrapper = ToolbarItemWrapper_1.ToolbarItemWrapper;
  exports.Toolbar.ItemIcon = ToolbarItemIcon_1.ToolbarItemIcon;
  exports.Toolbar.Menu = ToolbarMenu_1.ToolbarMenu;
  exports.Toolbar.MenuDivider = ToolbarMenuDivider_1.ToolbarMenuDivider;
  exports.Toolbar.MenuItem = ToolbarMenuItem_1.ToolbarMenuItem;
  exports.Toolbar.MenuItemIcon = ToolbarMenuItemIcon_1.ToolbarMenuItemIcon;
  exports.Toolbar.MenuItemSubmenuIndicator = ToolbarMenuItemSubmenuIndicator_1.ToolbarMenuItemSubmenuIndicator;
  exports.Toolbar.MenuItemActiveIndicator = ToolbarMenuItemActiveIndicator_1.ToolbarMenuItemActiveIndicator;
  exports.Toolbar.MenuRadioGroup = ToolbarMenuRadioGroup_1.ToolbarMenuRadioGroup;
  exports.Toolbar.MenuRadioGroupWrapper = ToolbarMenuRadioGroupWrapper_1.ToolbarMenuRadioGroupWrapper;
  exports.Toolbar.RadioGroup = ToolbarRadioGroup_1.ToolbarRadioGroup;
  