{"version":3,"sources":["globals/internal/radio-group-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;GAEG;AACH,oBAAY,oBAAoB;IAC9B;;OAEG;IACH,QAAQ,KAAK;IAEb;;OAEG;IACH,OAAO,IAAI;CACZ;AAED,MAAM,WAAW,0BAA0B;IACzC;;OAEG;IACH,OAAO,EAAE,OAAO,CAAC;IAEjB;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;;;;OAKG;IACH,uBAAuB,CAAC,KAAK,EAAE,0BAA0B,GAAG,MAAM,CAAC;IAEnE;;OAEG;IACH,KAAK,IAAI,IAAI,CAAC;CACf;AAED,aAAK,kBAAkB,GAAG,gBAAgB,GAAG,0BAA0B,CAAC;AAExE;;;GAGG;AACH,cAAM,iBAAiB;IACrB;;OAEG;IACH,OAAO,CAAC,OAAO,CAAmD;IAElE,OAAO;IAIP;;;;;;OAMG;IACH,iBAAiB,CAAC,KAAK,EAAE,kBAAkB;IAc3C;;;OAGG;IACH,cAAc,CAAC,KAAK,EAAE,kBAAkB;IAmBxC;;;;OAIG;IACH,GAAG,CAAC,KAAK,EAAE,kBAAkB;IAY7B;;;;;OAKG;IACH,MAAM,CAAC,KAAK,EAAE,kBAAkB,EAAE,IAAI,GAAE,MAAmB;IAK3D;;;OAGG;IACH,MAAM,CAAC,KAAK,EAAE,kBAAkB;IAgBhC;;;;OAIG;IACH,QAAQ,CAAC,KAAK,EAAE,kBAAkB,EAAE,SAAS,EAAE,oBAAoB;IAWnE;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,UAAU,CAAiB;IAE1C;;;OAGG;IACH,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ;CAI9B;AAED,eAAe,iBAAiB,CAAC","file":"radio-group-manager.d.ts","sourcesContent":["/**\n * @license\n *\n * Copyright IBM Corp. 2019\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\n/**\n * The navigation direction.\n */\nexport enum NAVIGATION_DIRECTION {\n  /**\n   * Navigating backward.\n   */\n  BACKWARD = -1,\n\n  /**\n   * Navigating forward.\n   */\n  FORWARD = 1,\n}\n\nexport interface ManagedRadioButtonDelegate {\n  /**\n   * `true` if this radio button is selected.\n   */\n  checked: boolean;\n\n  /**\n   * The tab index.\n   */\n  tabIndex: number;\n\n  /**\n   * The name of the radio group.\n   */\n  name: string;\n\n  /**\n   * @param other A node to compare this radio button's DOM position in document with.\n   * @returns\n   *   An integer value, the same format as `Node.compareDocumentPosition` does,\n   *   whose bits represent the calling this radio button's relationship to the given node within the document.\n   */\n  compareDocumentPosition(other: ManagedRadioButtonDelegate): number;\n\n  /**\n   * Focuses on the radio button.\n   */\n  focus(): void;\n}\n\ntype ManagedRadioButton = HTMLInputElement | ManagedRadioButtonDelegate;\n\n/**\n * An object that manages radio groups in a document.\n * There must be only one instance for one document.\n */\nclass RadioGroupManager {\n  /**\n   * Radio groups, keyed by their names.\n   */\n  private _groups: { [name: string]: Set<ManagedRadioButton> } = {};\n\n  private constructor(document: Document) {\n    (this.constructor as typeof RadioGroupManager)._instances.set(document, this);\n  }\n\n  /**\n   * @param radio A radio button.\n   * @returns\n   *   `true` if the given radio button should be focusable, which is either:\n   *   - The radio button is selected\n   *   - No radio button is selected and the radio button is first one in the radio group\n   */\n  shouldBeFocusable(radio: ManagedRadioButton) {\n    if (radio.checked) {\n      return true;\n    }\n    const { name } = radio;\n    const group = this._groups[name];\n    const hasSelectedItemInGroup = group && Array.from(group).some(item => item.checked);\n    if (hasSelectedItemInGroup) {\n      return false;\n    }\n    const isFirstInGroup = !group || group.size === 1 || this.getSortedGroup(radio)[0] === radio;\n    return isFirstInGroup;\n  }\n\n  /**\n   * @param radio A radio button.\n   * @returns The sorted radio group the given radio button is in.\n   */\n  getSortedGroup(radio: ManagedRadioButton) {\n    const group = this._groups[radio.name];\n    return (\n      group &&\n      Array.from(group).sort((lhs, rhs) => {\n        const comparisonResult = (lhs as ManagedRadioButtonDelegate).compareDocumentPosition(rhs as ManagedRadioButtonDelegate);\n        // eslint-disable-next-line no-bitwise\n        if (comparisonResult & Node.DOCUMENT_POSITION_FOLLOWING || comparisonResult & Node.DOCUMENT_POSITION_CONTAINED_BY) {\n          return -1;\n        }\n        // eslint-disable-next-line no-bitwise\n        if (comparisonResult & Node.DOCUMENT_POSITION_PRECEDING || comparisonResult & Node.DOCUMENT_POSITION_CONTAINS) {\n          return 1;\n        }\n        return 0;\n      })\n    );\n  }\n\n  /**\n   * Manages a radio button.\n   * @param radio The radio button to manage.\n   * @returns This object.\n   */\n  add(radio: ManagedRadioButton) {\n    const { name } = radio;\n    if (name) {\n      const groups = this._groups;\n      if (!groups[name]) {\n        groups[name] = new Set<ManagedRadioButton>();\n      }\n      groups[name].add(radio);\n    }\n    return this;\n  }\n\n  /**\n   * Unmanages a radio button.\n   * @param radio The radio button to unmanage.\n   * @param name The old name of the radio button to unmanage.\n   * @returns `true` if `element` was actually managed.\n   */\n  delete(radio: ManagedRadioButton, name: string = radio.name) {\n    const group = this._groups[name];\n    return !group ? false : group.delete(radio);\n  }\n\n  /**\n   * Selects or focuses on a radio button.\n   * @param radio The radio button to select.\n   */\n  select(radio: ManagedRadioButton) {\n    const group = this._groups[radio.name];\n    if (group) {\n      // Updates the state of the one being selected up-front to avoid the state of no radio button is selected\n      radio.checked = true;\n      radio.tabIndex = 0;\n      radio.focus();\n      group.forEach(item => {\n        if (radio !== item) {\n          item.checked = false;\n          item.tabIndex = -1;\n        }\n      });\n    }\n  }\n\n  /**\n   * @param radio The currently selected radio button.\n   * @param direction The direction to navigate to.\n   * @returns The radio button that should be selected next.\n   */\n  navigate(radio: ManagedRadioButton, direction: NAVIGATION_DIRECTION) {\n    const sortedGroup = this.getSortedGroup(radio);\n    let newIndex = sortedGroup.indexOf(radio) + direction;\n    if (newIndex < 0) {\n      newIndex = sortedGroup.length - 1;\n    } else if (newIndex >= sortedGroup.length) {\n      newIndex = 0;\n    }\n    return sortedGroup[newIndex];\n  }\n\n  /**\n   * `RadioGroupManager` instances associated with documents.\n   */\n  private static _instances = new WeakMap();\n\n  /**\n   * @param document A document element.\n   * @returns The `RadioGroupManager` instance associated with the given document.\n   */\n  static get(document: Document) {\n    const found = this._instances.get(document);\n    return found || new RadioGroupManager(document);\n  }\n}\n\nexport default RadioGroupManager;\n"]}