<commit_before>/**
 * @license
 * Copyright 2016 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {html} from '@polymer/polymer/lib/utils/html-tag';
import {customElement, property, observe} from '@polymer/decorators';

declare global {
  interface HTMLElementTagNameMap {
    'gr-select': GrSelect;
  }
}

/**
 * GrSelect `gr-select` component.
 */
@customElement('gr-select')
export class GrSelect extends PolymerElement {
  static get template() {
    return html` <slot></slot> `;
  }

  @property({type: String, notify: true})
  bindValue?: string | number | boolean;

  get nativeSelect() {
    // gr-select is not a shadow component
    // TODO(taoalpha): maybe we should convert
    // it into a shadow dom component instead
    // TODO(TS): should warn if no `select` detected.
    return this.querySelector('select')!;
  }

  @observe('bindValue')
  _updateValue() {
    // It's possible to have a value of 0.
    if (this.bindValue !== undefined) {
      // Set for chrome/safari so it happens instantly
      this.nativeSelect.value = String(this.bindValue);
      // Async needed for firefox to populate value. It was trying to do it
      // before options from a dom-repeat were rendered previously.
      // See https://bugs.chromium.org/p/gerrit/issues/detail?id=7735
      setTimeout(() => {
        this.nativeSelect.value = String(this.bindValue);
      }, 1);
    }
  }

  _valueChanged() {
    this.bindValue = this.nativeSelect.value;
  }

  override focus() {
    this.nativeSelect.focus();
  }

  constructor() {
    super();
    this.addEventListener('change', () => this._valueChanged());
    this.addEventListener('dom-change', () => this._updateValue());
  }

  override ready() {
    super.ready();
    // If not set via the property, set bind-value to the element value.
    if (this.bindValue === undefined && this.nativeSelect.options.length > 0) {
      this.bindValue = this.nativeSelect.value;
    }
  }
}<commit_msg>Migrate gr-select to Lit<commit_after>/**
 * @license
 * Copyright 2016 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
import {html, LitElement, PropertyValues} from 'lit';
import {customElement} from 'lit/decorators';
import {BindValueChangeEvent} from '../../../types/events';
import {fire} from '../../../utils/event-util';

declare global {
  interface HTMLElementTagNameMap {
    'gr-select': GrSelect;
  }
  interface HTMLElementEventMap {
    'bind-value-changed': BindValueChangeEvent;
  }
}

/**
 * GrSelect `gr-select` component.
 * TODO: Figure out if this class still has merit over native <select>
 */
@customElement('gr-select')
export class GrSelect extends LitElement {
  private _bindValue?: string | number | boolean;

  get bindValue() {
    return this._bindValue;
  }

  set bindValue(bindValue: string | number | boolean | undefined) {
    if (this._bindValue === bindValue) return;
    this._bindValue = bindValue;
    this._updateValue();
    // It's possible to have a value of 0.
    if (this.bindValue !== undefined) {
      // Set for chrome/safari so it happens instantly
      this.nativeSelect.value = String(this.bindValue);
      // Async needed for firefox to populate value. It was trying to do it
      // before options from a dom-repeat were rendered previously.
      // See https://bugs.chromium.org/p/gerrit/issues/detail?id=7735
      setTimeout(() => {
        this.nativeSelect.value = String(this.bindValue);
      }, 1);
    }
    // TODO: bind-value-changed is polymer-specific.  Move to a new event
    // name and rely on ValueChangedEvent instead of BindValueChangeEvent.
    fire(this, 'bind-value-changed', {value: this.convert(this._bindValue)});
  }

  get nativeSelect() {
    return this.querySelector('select')!;
  }

  constructor() {
    super();
    this.addEventListener('change', () => {
      this.bindValue = this.nativeSelect.value;
    });
  }

  override updated(changedProperties: PropertyValues) {
    super.updated(changedProperties);
    // If not set via the property, set bind-value to the element value.
    if (this.bindValue === undefined && this.nativeSelect.options.length > 0) {
      this.bindValue = this.nativeSelect.value;
    }
  }

  override render() {
    return html`<slot></slot>`;
  }

  _updateValue() {
    // It's possible to have a value of 0.
    if (this.bindValue !== undefined) {
      // Set for chrome/safari so it happens instantly
      this.nativeSelect.value = this.convert(this.bindValue) ?? '';
      // Async needed for firefox to populate value. It was trying to do it
      // before options from a dom-repeat were rendered previously.
      // See https://bugs.chromium.org/p/gerrit/issues/detail?id=7735
      setTimeout(() => {
        this.nativeSelect.value = this.convert(this.bindValue) ?? '';
      }, 1);
    }
  }

  private convert(value: string | boolean | number | undefined) {
    if (value === undefined) return undefined;
    if (typeof value === 'string') return value;
    return String(value);
  }

  override focus() {
    this.nativeSelect.focus();
  }
}
{'fraction_non_alphanumeric': 0.13434876000781099, 'fraction_numerical': 0.006248779535247022, 'mean_word_length': 3.058637083993661, 'pattern_counts': {'":': 0, '<': 8, '<?xml version=': 0, '>': 16, 'https://': 3, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1788211', 'n_tokens_mistral': 1555, 'n_tokens_neox': 1492, 'n_words': 419}