/**
 * @license
 * Copyright Tyler Technologies, Inc. 
 * License: Apache-2.0
 */
/**
 * @license
 * Copyright 2023 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 *
 * Adapted and influenced from [Material Web](https://github.com/material-components/material-web).
 * The original source code can be found at: [GitHub](https://github.com/material-components/material-web/blob/main/internal/aria/aria.ts)
 */
import { toggleAttribute } from '@tylertech/forge-core';
import { supportsElementInternalsAria } from './feature-detection';
/**
 * Reflective ARIA properties.
 */
export const ARIA_PROPERTIES = [
    'ariaAtomic',
    'ariaAutoComplete',
    'ariaBusy',
    'ariaChecked',
    'ariaColCount',
    'ariaColIndex',
    'ariaColSpan',
    'ariaCurrent',
    'ariaDisabled',
    'ariaExpanded',
    'ariaHasPopup',
    'ariaHidden',
    'ariaInvalid',
    'ariaKeyShortcuts',
    'ariaLabel',
    'ariaLevel',
    'ariaLive',
    'ariaModal',
    'ariaMultiLine',
    'ariaMultiSelectable',
    'ariaOrientation',
    'ariaPlaceholder',
    'ariaPosInSet',
    'ariaPressed',
    'ariaReadOnly',
    'ariaRequired',
    'ariaRoleDescription',
    'ariaRowCount',
    'ariaRowIndex',
    'ariaRowSpan',
    'ariaSelected',
    'ariaSetSize',
    'ariaSort',
    'ariaValueMax',
    'ariaValueMin',
    'ariaValueNow',
    'ariaValueText'
];
/**
 * An object mapping all ARIA attributes to their corresponding properties.
 *
 * This is required because the property name cannot be reliably inferred from the attribute name.
 */
const ARIA_ATTRIBUTES_TO_PROPERTIES = {
    'aria-atomic': 'ariaAtomic',
    'aria-autocomplete': 'ariaAutoComplete',
    'aria-busy': 'ariaBusy',
    'aria-checked': 'ariaChecked',
    'aria-colcount': 'ariaColCount',
    'aria-colindex': 'ariaColIndex',
    'aria-colspan': 'ariaColSpan',
    'aria-current': 'ariaCurrent',
    'aria-disabled': 'ariaDisabled',
    'aria-description': 'ariaDescription',
    'aria-expanded': 'ariaExpanded',
    'aria-haspopup': 'ariaHasPopup',
    'aria-hidden': 'ariaHidden',
    'aria-invalid': 'ariaInvalid',
    'aria-keyshortcuts': 'ariaKeyShortcuts',
    'aria-label': 'ariaLabel',
    'aria-level': 'ariaLevel',
    'aria-live': 'ariaLive',
    'aria-modal': 'ariaModal',
    'aria-multiline': 'ariaMultiLine',
    'aria-multiselectable': 'ariaMultiSelectable',
    'aria-orientation': 'ariaOrientation',
    'aria-placeholder': 'ariaPlaceholder',
    'aria-posinset': 'ariaPosInSet',
    'aria-pressed': 'ariaPressed',
    'aria-readonly': 'ariaReadOnly',
    'aria-required': 'ariaRequired',
    'aria-roledescription': 'ariaRoleDescription',
    'aria-rowcount': 'ariaRowCount',
    'aria-rowindex': 'ariaRowIndex',
    'aria-rowspan': 'ariaRowSpan',
    'aria-selected': 'ariaSelected',
    'aria-setsize': 'ariaSetSize',
    'aria-sort': 'ariaSort',
    'aria-valuemax': 'ariaValueMax',
    'aria-valuemin': 'ariaValueMin',
    'aria-valuenow': 'ariaValueNow',
    'aria-valuetext': 'ariaValueText',
    'role': 'role'
};
/**
 * Gets the ARIA attribute corresponding to a given ARIA property.
 *
 * @param property An ARIA mixin property.
 * @returns An ARIA attribute name.
 */
export function ariaPropertyToAttribute(property) {
    return property
        .replace('aria', 'aria-')
        // IDREF attributes also include an "Element" or "Elements" suffix
        .replace(/Elements?/g, '')
        .toLowerCase();
}
/**
 * Gets the ARIA property corresponding to a given ARIA attribute.
 *
 * @param attribute An ARIA attribute name.
 * @returns An ARIA mixin property.
 */
export function ariaAttributeToProperty(attribute) {
    return ARIA_ATTRIBUTES_TO_PROPERTIES[attribute];
}
/**
 * Applies default ARIA to an element through ElementInternals if supported. Otherwise, ARIA
 * attributes are set directly on the element and stored in additional `data-default-*` attributes
 * for restoration in case attributes are overwritten during the element's lifecycle.
 *
 * This fallback is needed for browsers that don't support ARIA in ElementInternals, such as most
 * recent versions of Firefox.
 *
 * Because new attributes may be sprouted on the element, it is necessary to call this after the
 * element has been connected to the DOM.
 *
 * @param element - The element to set up ARIA attributes for.
 * @param internals - The ElementInternals object to use for setting ARIA attributes if supported.
 * @param properties - An object containing ARIA properties and their values to set as defaults.
 * @param options - A `DefaultAriaOptions` object.
 *
 * @example
 * class ButtonComponent extends BaseComponent {
 *  public readonly internals: ElementInternals;
 *
 *  constructor() {
 *   super();
 *   this.internals = this.attachInternals();
 *  }
 *
 *  public connectedCallback(): void {
 *    setDefaultAria(this, this.internals, {
 *     role: 'button'
 *    });
 *   }
 * }
 */
export function setDefaultAria(element, internals, properties, { setAttribute } = { setAttribute: true }) {
    Object.entries(properties).forEach(([key, value]) => {
        if (supportsElementInternalsAria()) {
            internals[key] = value;
        }
        const attribute = ariaPropertyToAttribute(key);
        if (setAttribute || !element.hasAttribute(attribute)) {
            toggleAttribute(element, value != null, attribute, value);
        }
    });
}
