{"version":3,"file":"keyboard_list_navigation.cjs","sources":["../../../common/mixins/keyboard_list_navigation.js"],"sourcesContent":["import Dom from './dom';\n\nconst ERROR_INVALID_LIST_ELEMENT = (\n  'listElementKey is required or the referenced ' +\n  'element doesn\\'t exist. Received listElement: '\n);\n\n/**\n * Usage: `mixins: [keyboardNavigationMixin(options)]`\n *\n * This mixin provides some common data and methods to navigate a list of items\n * (such as a dropdown or select menu) by keyboard.\n *\n * To be effective, you must bind the onUpKey and onDownKey events, usually to\n * the root element of the component.\n *\n * @param listItemRole\n * @param indexKey\n * @param idKey\n * @param listElementKey\n * @param activeItemKey\n * @param openMethod\n * @param afterHighlightMethod\n * @param beginningOfListMethod\n * @param endOfListMethod\n * @param scrollToOnHighlight\n * @param focusOnKeyboardNavigation\n * @displayName Keyboard Navigation Mixin\n */\nexport default ({\n  // Role of the list items in the component. This is used to identify the list items\n  // so you must update this if the role of your list items is anything other than 'option'\n  listItemRole = 'option',\n  // Key of the data prop that will be added to the component.\n  indexKey = 'highlightIndex',\n  idKey = 'highlightId',\n  // Key of the method that references the list element.\n  listElementKey = 'listRef',\n  // Optional, Key of the computed prop that references the currently active item element.\n  activeItemKey = '',\n  // Optional, name of the method that toggles the list visibility. Used for\n  // opening the list when up or down is pressed.\n  openMethod = null,\n  // Optional, method to call when the highlightIndex is changed.\n  afterHighlightMethod = null,\n  // Optional, method to call when the highlightIndex goes past the beginning of the list.\n  beginningOfListMethod = null,\n  // Optional, method to call when the highlightIndex goes past the end of the list.\n  endOfListMethod = null,\n  // Scroll the active element into view when highlighted by a keyboard event.\n  scrollToOnHighlight = true,\n  // Focus the active element on keyboard navigation.\n  focusOnKeyboardNavigation = false,\n} = {}) => ({\n  mixins: [Dom],\n\n  data () {\n    return {\n      [indexKey]: -1,\n      [idKey]: '',\n      scrollToOnHighlight,\n      focusOnKeyboardNavigation,\n    };\n  },\n\n  provide () {\n    return {\n      highlightId: () => this[idKey],\n    };\n  },\n\n  methods: {\n    // Returns the list element\n    // this[listElement]() can return a Vue component, in which case we need to target\n    // the $el property, or it can simply be an html element.\n    _getListElement () {\n      return this[listElementKey]()?.$el || this[listElementKey]();\n    },\n\n    // Gets the length of all the items in the list, uses the listItemRole param to determine\n    // whether an element is a list item.\n    _itemsLength () {\n      const listItems = this._getListItemNodes();\n\n      if (listItems === null) {\n        return 0;\n      }\n\n      return listItems.length;\n    },\n\n    // Gets all the list item nodes within the list element\n    _getListItemNodes () {\n      const listElement = this._getListElement();\n\n      if (!listElement) {\n        console.error(ERROR_INVALID_LIST_ELEMENT, listElement);\n        return null;\n      }\n\n      return Array.from(listElement.querySelectorAll(`[role=\"${listItemRole}\"], #sr-only-close-button`));\n    },\n\n    onUpKey () {\n      if (openMethod) {\n        this[openMethod](true);\n      }\n      if (this[indexKey] > 0) {\n        this.setHighlightIndex(this[indexKey] - 1);\n      } else if (beginningOfListMethod) {\n        this[beginningOfListMethod]();\n      }\n      this.scrollActiveItemIntoViewIfNeeded();\n      this.focusActiveItemIfNeeded();\n    },\n\n    onDownKey () {\n      if (openMethod) {\n        this[openMethod](true);\n      }\n      if (this[indexKey] < this._itemsLength() - 1) {\n        this.setHighlightIndex(this[indexKey] + 1);\n      } else if (endOfListMethod) {\n        this[endOfListMethod]();\n      }\n      this.scrollActiveItemIntoViewIfNeeded();\n      this.focusActiveItemIfNeeded();\n    },\n\n    onHomeKey () {\n      this.jumpToBeginning();\n      this.scrollActiveItemIntoViewIfNeeded();\n      this.focusActiveItemIfNeeded();\n    },\n\n    onEndKey () {\n      this.jumpToEnd();\n      this.scrollActiveItemIntoViewIfNeeded();\n      this.focusActiveItemIfNeeded();\n    },\n\n    onNavigationKey (key) {\n      const listItems = this._getListItemNodes();\n\n      const matchingItems = listItems.filter(item => {\n        const content = item.textContent.trim().toLowerCase();\n        return content.startsWith(key.toLowerCase());\n      });\n\n      if (matchingItems.length <= 0) {\n        return;\n      }\n\n      const highlightedMatchingItemIndex = matchingItems.findIndex(item => {\n        return this[indexKey] === listItems.indexOf(item);\n      });\n\n      const nextHighlightedItemIndex = listItems.indexOf(\n        highlightedMatchingItemIndex < matchingItems.length - 1\n          ? matchingItems[highlightedMatchingItemIndex + 1]\n          : matchingItems[0],\n      );\n\n      this.setHighlightIndex(nextHighlightedItemIndex);\n      this.scrollActiveItemIntoViewIfNeeded();\n      this.focusActiveItemIfNeeded();\n    },\n\n    isValidLetter (key) {\n      if (key.length > 1) {\n        return false;\n      }\n\n      return (key >= 'a' && key <= 'z') || (key >= 'A' && key <= 'Z');\n    },\n\n    jumpToBeginning () {\n      this.setHighlightIndex(0);\n    },\n\n    jumpToEnd () {\n      this.setHighlightIndex(this._itemsLength() - 1);\n    },\n\n    setHighlightIndex (num) {\n      this[indexKey] = num;\n      this[idKey] = this._getItemId(num);\n\n      if (this._itemsLength() && afterHighlightMethod) {\n        this[afterHighlightMethod](num);\n      }\n    },\n\n    setHighlightId (id) {\n      this[idKey] = id;\n      this[indexKey] = this._getItemIndex(id);\n\n      if (this._itemsLength() && afterHighlightMethod) {\n        this[afterHighlightMethod](this._getItemIndex(id));\n      }\n    },\n\n    _getItemIndex (id) {\n      const listElement = this._getListElement();\n      if (!listElement) {\n        return;\n      }\n\n      const listItems = Array.from(listElement.querySelectorAll(`[role=\"${listItemRole}\"], #sr-only-close-button`));\n      return listItems.indexOf(listElement.querySelector(`#${id}`));\n    },\n\n    _getItemId (index) {\n      const listElement = this._getListElement();\n      if (!listElement) {\n        return;\n      }\n\n      return listElement.querySelectorAll(`[role=\"${listItemRole}\"], #sr-only-close-button`)[index]?.id;\n    },\n\n    scrollActiveItemIntoViewIfNeeded () {\n      if (!this.scrollToOnHighlight) {\n        return;\n      }\n      const activeItemEl = this[activeItemKey];\n      if (activeItemEl) {\n        // When listElementKey is not passed,\n        // scrollElementIntoViewIfNeeded will default to the immediate wrapper of the item.\n        const listElement = this._getListElement();\n        this.scrollElementIntoViewIfNeeded(activeItemEl, null, null, listElement);\n      }\n    },\n\n    focusActiveItemIfNeeded () {\n      if (!this.focusOnKeyboardNavigation) {\n        return;\n      }\n      const activeItemEl = this[activeItemKey];\n      if (activeItemEl) {\n        activeItemEl.focus();\n      }\n    },\n  },\n});\n"],"names":["Dom"],"mappings":"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"}