// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
 * @fileoverview 'settings-checkbox-list-entry' is a wrapper for cr-checkbox so
 * that it can have the correct accessibility behavior while inside an
 * iron-list. Because cr-checkbox passes its focus to its inner checkbox
 * element, screen readers are unable to infer a parent-child relationship
 * between the list element and the focused checkbox. As a result using the
 * roles listbox/option and annotating with aria-setsize/aria-posinset will not
 * work properly.
 *
 * To fix this 'settings-checkbox-list-entry' hijacks focus and prevents it from
 * going into the inner element, so that screenreaders will properly read
 * "(x of y)". This however changes the visuals so that when the element is
 * focused the entire row is highlighted instead of just the checkbox.
 *
 * Example usage:
 * <iron-list role="listbox" items="[[items]]">
 *   <template>
 *     <settings-checkbox-list-entry role="option"
 *         checked="[[isSelected_(item)]]"
 *         tabindex="[[tabIndex]]"
 *         aria-posinset$="[[addOneTo_(index)]]"
 *         aria-setsize$="[[items.length]]"
 *         on-change="toggleSelection_">
 *       [[item]]
 *     </settings-checkbox-list-entry>
 *   </template>
 * </iron-list>
 */
import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js';
import '../settings_shared.css.js';
import '../site_favicon.js';
import { PolymerElement } from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import { getTemplate } from './settings_checkbox_list_entry.html.js';
export class SettingsCheckboxListEntryElement extends PolymerElement {
    static get is() {
        return 'settings-checkbox-list-entry';
    }
    static get template() {
        return getTemplate();
    }
    static get properties() {
        return {
            // Used to set the status of the checkbox when the entry is created,
            // as well as when the list item for the entry changes.
            checked: {
                type: Boolean,
                value: false,
                observer: 'onCheckedChanged_',
            },
            // Reflects to the tabindex attribute. When it is negative (non-focusable)
            // aria-hidden will be set to "true", so that it will be ignored by screen
            // readers. This is needed because iron-list recycles its entries, so when
            // focusing an entry, the screen reader can be confused by other entries'
            // aria-posinset and aria-setsize attributes if they aren't aria-hidden.
            tabindex: {
                type: Number,
                value: 0,
                observer: 'onTabIndexChanged_',
                reflectToAttribute: true,
            },
        };
    }
    ready() {
        super.ready();
        this.addEventListener('click', this.onClick_);
        this.addEventListener('keydown', this.onKeyDown_);
        this.addEventListener('keyup', this.onKeyUp_);
    }
    onClick_() {
        this.$.checkbox.click();
    }
    // Handle key presses in the same way as cr-checkbox, because it no longer
    // receives focus.
    onKeyDown_(e) {
        if (e.key !== ' ' && e.key !== 'Enter') {
            return;
        }
        e.preventDefault();
        e.stopPropagation();
        if (e.repeat) {
            return;
        }
        if (e.key === 'Enter') {
            this.$.checkbox.click();
        }
    }
    onKeyUp_(e) {
        if (e.key === ' ' || e.key === 'Enter') {
            e.preventDefault();
            e.stopPropagation();
        }
        if (e.key === ' ') {
            this.$.checkbox.click();
        }
    }
    onCheckedChanged_() {
        this.setAttribute('aria-checked', String(this.$.checkbox.checked));
    }
    onTabIndexChanged_() {
        this.setAttribute('aria-hidden', this.tabindex >= 0 ? 'false' : 'true');
    }
}
customElements.define(SettingsCheckboxListEntryElement.is, SettingsCheckboxListEntryElement);
