<commit_before>import { forwardFocus } from "../core/dom.js";
import * as internal from "./internal.js";
import * as template from "../core/template.js";
import DelegateFocusMixin from "./DelegateFocusMixin.js";
import FormElementMixin from "./FormElementMixin.js";
import KeyboardDirectionMixin from "./KeyboardDirectionMixin.js";
import KeyboardMixin from "./KeyboardMixin.js";
import ReactiveElement from "../core/ReactiveElement.js";

const Base = DelegateFocusMixin(
  FormElementMixin(KeyboardMixin(KeyboardDirectionMixin(ReactiveElement)))
);

/**
 * Input element with buttons to increase or decrease the value
 *
 * @inherits ReactiveElement
 * @mixes DelegateFocusMixin
 * @mixes FormElementMixin
 * @mixes KeyboardDirectionMixin
 * @mixes KeyboardMixin
 * @part {input} input - the text input portion of the spin box
 * @part {button} button - the up and down buttons
 * @part up-button - the up button
 * @part down-button - the down button
 */
export class SpinBox extends Base {
  get [internal.defaultState]() {
    return Object.assign(super[internal.defaultState], {
      focused: false,
      focusOutline: null,
      focusOutlineOffset: null,
      buttonPartType: "button",
      inputPartType: "input",
      orientation: "vertical",
      step: 1,
      value: 0
    });
  }

  [internal.goDown]() {
    if (super[internal.goDown]) {
      super[internal.goDown]();
    }
    this.stepDown();
  }

  [internal.goUp]() {
    if (super[internal.goUp]) {
      super[internal.goUp]();
    }
    this.stepUp();
  }

  [internal.render](changed) {
    super[internal.render](changed);

    renderParts(this[internal.shadowRoot], this[internal.state], changed);

    if (this[internal.firstRender]) {
      this.addEventListener("focusin", () => {
        this[internal.setState]({ focused: true });
      });
      this.addEventListener("focusout", () => {
        this[internal.setState]({ focused: false });
      });
    }

    // Wire up handlers on new buttons.
    if (changed.buttonPartType) {
      this[internal.ids].downButton.addEventListener("mousedown", () => {
        this.stepDown();
      });
      this[internal.ids].upButton.addEventListener("mousedown", () => {
        this.stepUp();
      });
    }

    // Wire up event handler on new input.
    if (changed.inputPartType) {
      // Wire up handler on new input.
      this[internal.ids].input.addEventListener("input", () => {
        this.value = /** @type {any} */ (this[internal.ids].input).value;
      });

      this[internal.ids].input.addEventListener("focus", () => {
        setTimeout(() => {
          if (
            !this[internal.state].focusOutline ||
            !this[internal.state].focusOutlineOffset
          ) {
            const { outline, outlineOffset, outlineStyle } = getComputedStyle(
              this[internal.ids].input.inner
            );
            if (outlineStyle !== "none") {
              this[internal.setState]({
                focusOutline: outline,
                focusOutlineOffset: outlineOffset
              });
              console.log(outline);
            }
          }
        });
      });
    }

    // When buttons are clicked, keep focus on input.
    if (changed.buttonPartType || changed.inputPartType) {
      const input = this[internal.ids].input;
      const downButton = this[internal.ids].downButton;
      if (downButton instanceof HTMLElement && input instanceof HTMLElement) {
        forwardFocus(downButton, input);
      }
      const upButton = this[internal.ids].upButton;
      if (upButton instanceof HTMLElement && input instanceof HTMLElement) {
        forwardFocus(upButton, input);
      }
    }

    if (changed.focused || changed.focusOutline || changed.focusOutlineOffset) {
      const { focused, focusOutline, focusOutlineOffset } = this[
        internal.state
      ];
      if (focusOutline && focusOutlineOffset) {
        Object.assign(this.style, {
          outline: focused ? focusOutline : "none",
          outlineOffset: focused ? focusOutlineOffset : ""
        });
        Object.assign(this[internal.ids].input.inner.style, {
          outline: "none",
          outlineOffset: "0"
        });
      }
    }

    // Render value state to input.
    if (changed.value) {
      const { value } = this[internal.state];
      /** @type {any} */ (this[internal.ids].input).value = value;
    }
  }

  stepDown() {}

  stepUp() {}

  get [internal.template]() {
    return template.html`
      <style>
        :host {
          display: inline-grid;
        }

        [part~="input"] {
          grid-row-end: 3;
          grid-row-start: 1;
          text-align: right;
        }

        [part~="spin-button"] {
          grid-column: 2;
          user-select: none;
        }
      </style>
      <div id="input" part="input"></div><commit_msg>Fall back to our best shot at defining a focus ring style that approximates the browser's.<commit_after>import { forwardFocus } from "../core/dom.js";
import * as internal from "./internal.js";
import * as template from "../core/template.js";
import DelegateFocusMixin from "./DelegateFocusMixin.js";
import FormElementMixin from "./FormElementMixin.js";
import KeyboardDirectionMixin from "./KeyboardDirectionMixin.js";
import KeyboardMixin from "./KeyboardMixin.js";
import ReactiveElement from "../core/ReactiveElement.js";

const Base = DelegateFocusMixin(
  FormElementMixin(KeyboardMixin(KeyboardDirectionMixin(ReactiveElement)))
);

/**
 * Input element with buttons to increase or decrease the value
 *
 * @inherits ReactiveElement
 * @mixes DelegateFocusMixin
 * @mixes FormElementMixin
 * @mixes KeyboardDirectionMixin
 * @mixes KeyboardMixin
 * @part {input} input - the text input portion of the spin box
 * @part {button} button - the up and down buttons
 * @part up-button - the up button
 * @part down-button - the down button
 */
export class SpinBox extends Base {
  get [internal.defaultState]() {
    return Object.assign(super[internal.defaultState], {
      buttonPartType: "button",
      inputPartType: "input",
      orientation: "vertical",
      step: 1,
      value: 0
    });
  }

  [internal.goDown]() {
    if (super[internal.goDown]) {
      super[internal.goDown]();
    }
    this.stepDown();
  }

  [internal.goUp]() {
    if (super[internal.goUp]) {
      super[internal.goUp]();
    }
    this.stepUp();
  }

  [internal.render](changed) {
    super[internal.render](changed);

    renderParts(this[internal.shadowRoot], this[internal.state], changed);

    // Wire up handlers on new buttons.
    if (changed.buttonPartType) {
      this[internal.ids].downButton.addEventListener("mousedown", () => {
        this.stepDown();
      });
      this[internal.ids].upButton.addEventListener("mousedown", () => {
        this.stepUp();
      });
    }

    // Wire up event handler on new input.
    if (changed.inputPartType) {
      // Wire up handler on new input.
      this[internal.ids].input.addEventListener("input", () => {
        this.value = /** @type {any} */ (this[internal.ids].input).value;
      });

      // TODO: Avoid referencing inner
      this[internal.ids].input.style.outline = "none";
      this[internal.ids].input.inner.style.outline = "none";
    }

    // When buttons are clicked, keep focus on input.
    if (changed.buttonPartType || changed.inputPartType) {
      const input = this[internal.ids].input;
      const downButton = this[internal.ids].downButton;
      if (downButton instanceof HTMLElement && input instanceof HTMLElement) {
        forwardFocus(downButton, input);
      }
      const upButton = this[internal.ids].upButton;
      if (upButton instanceof HTMLElement && input instanceof HTMLElement) {
        forwardFocus(upButton, input);
      }
    }

    // Render value state to input.
    if (changed.value) {
      const { value } = this[internal.state];
      /** @type {any} */ (this[internal.ids].input).value = value;
    }
  }

  stepDown() {}

  stepUp() {}

  get [internal.template]() {
    return template.html`
      <style>
        :host {
          display: inline-grid;
        }

        :host(:focus-within) {
          outline-color: Highlight; /* Firefox */
          outline-color: -webkit-focus-ring-color; /* Everyone else */
          outline-style: auto;
          outline-width: 2px;
        }

        [part~="input"] {
          grid-row-end: 3;
          grid-row-start: 1;
          text-align: right;
        }

        [part~="spin-button"] {
          grid-column: 2;
          user-select: none;
        }
      </style>
      <div id="input" part="input"></div>
{'fraction_non_alphanumeric': 0.13684332598863505, 'fraction_numerical': 0.0013916270439522209, 'mean_word_length': 2.515695067264574, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 21, 'https://': 0, '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': '876290', 'n_tokens_mistral': 2532, 'n_tokens_neox': 2497, 'n_words': 558}