{"version":3,"sources":["components/tabs/tabs.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AASH,OAAO,iBAAiB,EAAE,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AAC/F,OAAO,EAAE,2BAA2B,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACzG,OAAO,KAAK,MAAM,OAAO,CAAC;AAK1B,OAAO,EAAE,oBAAoB,EAAE,2BAA2B,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,SAAS,EAAE,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEjH;;;;;;;GAOG;AACH,cACM,MAAO,SAAQ,WAAoC;IACvD;;OAEG;IACH,OAAO,CAAC,oBAAoB,CAAC,CAAS;IAEtC;;OAEG;IACH,OAAO,CAAC,KAAK,CAAS;IAEtB;;OAEG;IACH,OAAO,CAAC,oBAAoB,CAAiC;IAE7D;;OAEG;IAEH,OAAO,CAAC,YAAY,CAAkB;IAEtC;;OAEG;IAGH,OAAO,CAAC,cAAc;IAOtB;;;OAGG;IAGH,OAAO,CAAC,eAAe;IAUvB;;;OAGG;IACH,OAAO,CAAC,0BAA0B;IAmBlC;;OAEG;IACH,OAAO,CAAC,eAAe;IAMvB;;;;;;;;;OASG;IACH,SAAS,CAAC,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,GAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAO;IA+BlF,SAAS,CAAC,YAAY,CAAC,KAAK,EAAE,UAAU;IAexC,SAAS,CAAC,cAAc,CAAC,EAAE,GAAG,EAAE,EAAE,aAAa;IAuD/C,SAAS,CAAC,mBAAmB,CAAC,YAAY,EAAE,KAAK;IAMjD;;OAEG;IAEH,WAAW,oBAA6B;IAExC;;OAEG;IAEH,2BAA2B,SAA8D;IAEzF;;OAEG;IAEH,yBAAyB,SAAuB;IAEhD;;OAEG;IAEH,cAAc,SAAM;IAEpB;;OAEG;IAEH,IAAI,YAAqB;IAEzB,YAAY,CAAC,iBAAiB,KAAA;IAqB9B,MAAM;IAqCN;;OAEG;IACH,MAAM,CAAC,YAAY,cAA2B;IAE9C;;OAEG;IACH,MAAM,KAAK,YAAY,WAEtB;IAED;;OAEG;IACH,MAAM,KAAK,mBAAmB,WAE7B;IAED;;OAEG;IACH,MAAM,KAAK,uBAAuB,WAEjC;IAED;;OAEG;IACH,MAAM,KAAK,oBAAoB,WAE9B;IAED;;;OAGG;IACH,MAAM,KAAK,iBAAiB,WAE3B;IAED;;OAEG;IACH,MAAM,KAAK,WAAW,WAErB;IAED,MAAM,CAAC,MAAM,MAAU;IAEvB;;;;;OAKG;IACH,MAAM,CAAC,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,EAAE;QAAE,UAAU,CAAC,EAAE,OAAO,CAAA;KAAE;CAYvE;AAED,eAAe,MAAM,CAAC","file":"tabs.d.ts","sourcesContent":["/**\n * @license\n *\n * Copyright IBM Corp. 2019, 2021\n *\n * This source code is licensed under the Apache-2.0 license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport { classMap } from 'lit-html/directives/class-map';\nimport { html, property, query, customElement } from 'lit-element';\nimport ChevronDown16 from '@carbon/icons/lib/chevron--down/16';\nimport settings from 'carbon-components/es/globals/js/settings';\nimport HostListenerMixin from '../../globals/mixins/host-listener';\nimport HostListener from '../../globals/decorators/host-listener';\nimport { find, forEach } from '../../globals/internal/collection-helpers';\nimport BXContentSwitcher, { NAVIGATION_DIRECTION } from '../content-switcher/content-switcher';\nimport { NAVIGATION_DIRECTION_NARROW, TABS_COLOR_SCHEME, TABS_KEYBOARD_ACTION, TABS_TYPE } from './defs';\nimport BXTab from './tab';\nimport styles from './tabs.scss';\n\nconst { prefix } = settings;\n\nexport { NAVIGATION_DIRECTION, NAVIGATION_DIRECTION_NARROW, TABS_COLOR_SCHEME, TABS_KEYBOARD_ACTION, TABS_TYPE };\n\n/**\n * Tabs.\n * @element bx-tabs\n * @fires bx-tabs-beingselected\n *   The custom event fired before a tab is selected upon a user gesture.\n *   Cancellation of this event stops changing the user-initiated selection.\n * @fires bx-tabs-selected - The custom event fired after a a tab is selected upon a user gesture.\n */\n@customElement(`${prefix}-tabs`)\nclass BXTabs extends HostListenerMixin(BXContentSwitcher) {\n  /**\n   * The latest status of this dropdown, for screen reader to accounce.\n   */\n  private _assistiveStatusText?: string;\n\n  /**\n   * `true` if the narrow mode dropdown should be open.\n   */\n  private _open = false;\n\n  /**\n   * The content of the selected item, used in the narrow mode.\n   */\n  private _selectedItemContent: DocumentFragment | null = null;\n\n  /**\n   * The DOM element for the trigger button in narrow mode.\n   */\n  @query('#trigger')\n  private _triggerNode!: HTMLDivElement;\n\n  /**\n   * Handles `focus` event handler on this element.\n   */\n  @HostListener('focusin')\n  // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to\n  private _handleFocusIn() {\n    const { selectorItem } = this.constructor as typeof BXTabs;\n    forEach(this.querySelectorAll(selectorItem), item => {\n      (item as BXTab).inFocus = true;\n    });\n  }\n\n  /**\n   * Handles `blur` event handler on this element.\n   * @param event The event.\n   */\n  @HostListener('focusout')\n  // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to\n  private _handleFocusOut({ relatedTarget }: FocusEvent) {\n    if (!this.contains(relatedTarget as Node)) {\n      const { selectorItem } = this.constructor as typeof BXTabs;\n      forEach(this.querySelectorAll(selectorItem), item => {\n        (item as BXTab).inFocus = false;\n      });\n      this._handleUserInitiatedToggle(false);\n    }\n  }\n\n  /**\n   * Handles user-initiated toggling the open state.\n   * @param [force] If specified, forces the open state to the given one.\n   */\n  private _handleUserInitiatedToggle(force: boolean = !this._open) {\n    this._open = force;\n    if (this._open) {\n      this._assistiveStatusText = this.selectingItemsAssistiveText;\n    } else {\n      const {\n        selectedItemAssistiveText,\n        triggerContent,\n        _assistiveStatusText: assistiveStatusText,\n        _selectedItemContent: selectedItemContent,\n      } = this;\n      const selectedItemText = (selectedItemContent && selectedItemContent.textContent) || triggerContent;\n      if (selectedItemText && assistiveStatusText !== selectedItemAssistiveText) {\n        this._assistiveStatusText = selectedItemText;\n      }\n    }\n    this.requestUpdate();\n  }\n\n  /**\n   * Clears the selection of tabs.\n   */\n  private _clearHighlight() {\n    forEach(this.querySelectorAll((this.constructor as typeof BXTabs).selectorItem), item => {\n      (item as BXTab).highlighted = false;\n    });\n  }\n\n  /**\n   * Navigates through tabs.\n   * @param direction `-1` to navigate backward, `1` to navigate forward.\n   * @param [options] The options.\n   * @param [options.immediate]\n   *   `true` to make it \"immediate selection change\" mode, which does:\n   *\n   *   * Starts with the selected item\n   *   * Going prev/next item immediately changes the selection\n   */\n  protected _navigate(direction: number, { immediate }: { immediate?: boolean } = {}) {\n    const { selectorItem, selectorItemHighlighted, selectorItemSelected } = this.constructor as typeof BXTabs;\n    const nextItem = this._getNextItem(\n      this.querySelector(immediate ? selectorItemSelected : selectorItemHighlighted) as BXTab,\n      direction\n    );\n    if (!nextItem) {\n      return;\n    }\n\n    if (immediate) {\n      this._handleUserInitiatedSelectItem(nextItem as BXTab);\n    } else {\n      forEach(this.querySelectorAll(selectorItem), item => {\n        (item as BXTab)[immediate ? 'selected' : 'highlighted'] = nextItem === item;\n      });\n    }\n\n    // Using `{ block: 'nearest' }` to prevent scrolling unless scrolling is absolutely necessary.\n    // `scrollIntoViewOptions` seems to work in latest Safari despite of MDN/caniuse table.\n    // IE falls back to the old behavior.\n    nextItem.scrollIntoView({ block: 'nearest' });\n\n    const nextItemText = nextItem.textContent;\n    if (nextItemText) {\n      this._assistiveStatusText = nextItemText;\n    }\n    this.requestUpdate();\n  }\n\n  @HostListener('click')\n  protected _handleClick(event: MouseEvent) {\n    const { target } = event;\n    if (this === target) {\n      this._handleUserInitiatedToggle();\n    } else if ((target as BXTab).value === this.value) {\n      // Clicking on selected item, simply closes the narrow mode dropdown\n      this._handleUserInitiatedToggle(false);\n    } else {\n      // Trying to select the item\n      // If the custom event of the selection is canceled, we don't close the narrow mode dropdown\n      super._handleClick(event);\n    }\n  }\n\n  @HostListener('keydown')\n  protected _handleKeydown({ key }: KeyboardEvent) {\n    const { _open: open, _triggerNode: triggerNode } = this;\n    const narrowMode = Boolean(triggerNode.offsetParent);\n    const action = (this.constructor as typeof BXTabs).getAction(key, { narrowMode });\n    if (!open && narrowMode) {\n      // Menu closed in narrow mode\n      switch (action) {\n        case TABS_KEYBOARD_ACTION.NAVIGATING:\n          this._handleUserInitiatedToggle(true);\n          // If this menu gets open with an arrow key, resets the highlight\n          this._clearHighlight();\n          break;\n        case TABS_KEYBOARD_ACTION.TRIGGERING:\n          this._handleUserInitiatedToggle(true);\n          break;\n        default:\n          break;\n      }\n    } else {\n      switch (action) {\n        case TABS_KEYBOARD_ACTION.CLOSING:\n          this._handleUserInitiatedToggle(false);\n          break;\n        case TABS_KEYBOARD_ACTION.NAVIGATING:\n          {\n            const direction = narrowMode ? NAVIGATION_DIRECTION_NARROW[key] : NAVIGATION_DIRECTION[key];\n            if (direction) {\n              this._navigate(direction, { immediate: !narrowMode });\n            }\n          }\n          break;\n        case TABS_KEYBOARD_ACTION.TRIGGERING:\n          {\n            const { selectorItemHighlighted } = this.constructor as typeof BXTabs;\n            const highlightedItem = this.querySelector(selectorItemHighlighted) as BXTab;\n            if (highlightedItem) {\n              if (highlightedItem.value === this.value) {\n                // Selecting an already-selected item, simply closes the narrow mode dropdown\n                this._handleUserInitiatedToggle(false);\n              } else {\n                // Trying to select the item\n                // If the custom event of the selection is canceled, we don't close the narrow mode dropdown\n                this._handleUserInitiatedSelectItem(highlightedItem);\n              }\n            } else {\n              this._handleUserInitiatedToggle();\n            }\n          }\n          break;\n        default:\n          break;\n      }\n    }\n  }\n\n  protected _selectionDidChange(itemToSelect: BXTab) {\n    super._selectionDidChange(itemToSelect);\n    this._assistiveStatusText = this.selectedItemAssistiveText;\n    this._handleUserInitiatedToggle(false);\n  }\n\n  /**\n   * The color scheme.\n   */\n  @property({ attribute: 'color-scheme', reflect: true })\n  colorScheme = TABS_COLOR_SCHEME.REGULAR;\n\n  /**\n   * An assistive text for screen reader to announce, telling the open state.\n   */\n  @property({ attribute: 'selecting-items-assistive-text' })\n  selectingItemsAssistiveText = 'Selecting items. Use up and down arrow keys to navigate.';\n\n  /**\n   * An assistive text for screen reader to announce, telling that an item is selected.\n   */\n  @property({ attribute: 'selected-item-assistive-text' })\n  selectedItemAssistiveText = 'Selected an item.';\n\n  /**\n   * The content of the trigger button for narrow mode.\n   */\n  @property({ attribute: 'trigger-content' })\n  triggerContent = '';\n\n  /**\n   * Tabs type.\n   */\n  @property({ reflect: true })\n  type = TABS_TYPE.REGULAR;\n\n  shouldUpdate(changedProperties) {\n    super.shouldUpdate(changedProperties);\n    const { selectorItem } = this.constructor as typeof BXTabs;\n    if (changedProperties.has('type')) {\n      forEach(this.querySelectorAll(selectorItem), elem => {\n        (elem as BXTab).type = this.type;\n      });\n    }\n    if (changedProperties.has('value')) {\n      const item = find(this.querySelectorAll(selectorItem), elem => (elem as BXTab).value === this.value);\n      if (item) {\n        const range = this.ownerDocument!.createRange();\n        range.selectNodeContents(item);\n        this._selectedItemContent = range.cloneContents();\n      } else {\n        this._selectedItemContent = null;\n      }\n    }\n    return true;\n  }\n\n  render() {\n    const {\n      triggerContent,\n      _assistiveStatusText: assistiveStatusText,\n      _open: open,\n      _selectedItemContent: selectedItemContent,\n    } = this;\n    const triggerClasses = classMap({\n      [`${prefix}--tabs-trigger`]: true,\n      [`${prefix}--tabs-trigger--open`]: open,\n    });\n    const listClasses = classMap({\n      [`${prefix}--tabs__nav`]: true,\n      [`${prefix}--tabs__nav--hidden`]: !open,\n    });\n    return html`\n      <div\n        id=\"trigger\"\n        role=\"button\"\n        class=\"${triggerClasses}\"\n        aria-labelledby=\"trigger-label\"\n        aria-expanded=\"${String(open)}\"\n        aria-haspopup=\"listbox\"\n        aria-owns=\"tablist\"\n        aria-controls=\"tablist\">\n        <span id=\"trigger-label\" class=\"${prefix}--tabs-trigger-text\"> ${selectedItemContent || triggerContent} </span>\n        ${ChevronDown16({ 'aria-hidden': 'true' })}\n      </div>\n      <ul id=\"tablist\" role=\"tablist\" class=\"${listClasses}\">\n        <slot></slot>\n      </ul>\n      <div class=\"${prefix}--assistive-text\" role=\"status\" aria-live=\"assertive\" aria-relevant=\"additions text\">\n        ${assistiveStatusText}\n      </div>\n    `;\n  }\n\n  /**\n   * Symbols of keys that triggers opening/closing menu and selecting/deselecting menu item.\n   */\n  static TRIGGER_KEYS = new Set([' ', 'Enter']);\n\n  /**\n   * A selector that will return tabs.\n   */\n  static get selectorItem() {\n    return `${prefix}-tab`;\n  }\n\n  /**\n   * A selector that will return enabled tabs.\n   */\n  static get selectorItemEnabled() {\n    return `${prefix}-tab:not([disabled])`;\n  }\n\n  /**\n   * A selector that will return highlighted tabs.\n   */\n  static get selectorItemHighlighted() {\n    return `${prefix}-tab[highlighted]`;\n  }\n\n  /**\n   * A selector that will return selected tabs.\n   */\n  static get selectorItemSelected() {\n    return `${prefix}-tab[selected]`;\n  }\n\n  /**\n   * The name of the custom event fired before a tab is selected upon a user gesture.\n   * Cancellation of this event stops changing the user-initiated selection.\n   */\n  static get eventBeforeSelect() {\n    return `${prefix}-tabs-beingselected`;\n  }\n\n  /**\n   * The name of the custom event fired after a a tab is selected upon a user gesture.\n   */\n  static get eventSelect() {\n    return `${prefix}-tabs-selected`;\n  }\n\n  static styles = styles;\n\n  /**\n   * @param key The key symbol.\n   * @param [options] The options.\n   * @param [options.narrowMode] `true` to get the action for narrow mode.\n   * @returns A action for dropdown for the given key symbol.\n   */\n  static getAction(key: string, { narrowMode }: { narrowMode?: boolean }) {\n    if (key === 'Escape') {\n      return TABS_KEYBOARD_ACTION.CLOSING;\n    }\n    if (key in (narrowMode ? NAVIGATION_DIRECTION_NARROW : NAVIGATION_DIRECTION)) {\n      return TABS_KEYBOARD_ACTION.NAVIGATING;\n    }\n    if (narrowMode && this.TRIGGER_KEYS.has(key)) {\n      return TABS_KEYBOARD_ACTION.TRIGGERING;\n    }\n    return TABS_KEYBOARD_ACTION.NONE;\n  }\n}\n\nexport default BXTabs;\n"]}