Make progress on the input being focusable from an external label

This commit is contained in:
Oliver-Akins 2024-04-07 23:53:34 -06:00
parent 1c372415f4
commit 4efa89915a
3 changed files with 93 additions and 35 deletions

View file

@ -2,6 +2,10 @@
Attributes:
@property {string} name - The path to the value to update
@property {number} value - The actual value of the input
@property {number} min - The minimum value of the input
@property {number} max - The maximum value of the input
@property {number?} smallStep - The step size used for the buttons and arrow keys
@property {number?} largeStep - The step size used for the buttons + Ctrl and page up / down
Styling:
- `--height`: Controls the height of the element + the width of the buttons (default: 1.25rem)
@ -9,9 +13,15 @@ Styling:
*/
export class DotDungeonIncrementer extends HTMLElement {
static elementName = `dd-incrementer`;
static formAssociated = true;
static styles = ``;
#min;
#max;
#smallStep;
#largeStep;
#input;
#publicInput;
#sr;
@ -19,40 +29,47 @@ export class DotDungeonIncrementer extends HTMLElement {
constructor() {
super();
this._internals = this.attachInternals();
const value = this.getAttribute(`value`);
this.#min = parseInt(this.getAttribute(`min`) ?? 0);
this.#max = parseInt(this.getAttribute(`max`) ?? 0);
this.#smallStep = parseInt(this.getAttribute(`smallStep`) ?? 1);
this.#largeStep = parseInt(this.getAttribute(`largeStep`) ?? 5);
/*
This input exists for the sole purpose of making it so that the form data
works with this input without needing to do jank work arounds (even though
this on it's own is already a sort of jank work around).
*/
const hiddenInput = document.createElement(`input`);
hiddenInput.type = `hidden`;
hiddenInput.name = this.getAttribute(`name`);
hiddenInput.value = value;
this.#publicInput = hiddenInput;
this.appendChild(hiddenInput);
const sr = this.attachShadow({ mode: `open` });
const sr = this.attachShadow({
mode: `open`,
delegatesFocus: true
});
this.#sr = sr;
const container = document.createElement(`div`);
if (DotDungeonIncrementer.styles) this.#embedStyles();
// The input that the user can see / modify
const input = document.createElement(`input`);
this.#input = input;
input.type = `number`;
input.min = this.getAttribute(`min`);
input.max = this.getAttribute(`max`);
input.addEventListener(`change`, this.#updateValue.bind(this));
input.value = value;
const increment = document.createElement(`button`);
// input.id = this.id;
// this.removeAttribute(`id`);
// plus button
const increment = document.createElement(`span`);
increment.innerHTML = `+`;
increment.type = `button`;
// increment.type = `button`;
// increment.tabIndex = -1;
increment.classList.value = `increment`;
increment.addEventListener(`click`, this.#increment.bind(this));
const decrement = document.createElement(`button`);
// minus button
const decrement = document.createElement(`span`);
decrement.innerHTML = `-`;
decrement.type = `button`;
// decrement.type = `button`;
// decrement.tabIndex = -1;
decrement.classList.value = `decrement`;
decrement.addEventListener(`click`, this.#decrement.bind(this));
@ -65,6 +82,20 @@ export class DotDungeonIncrementer extends HTMLElement {
};
connectedCallback() {
/*
This input exists for the sole purpose of making it so that the form data
works with this input without needing to do jank work arounds, as Foundry
only listens for change events from a small subset of elements which makes
this a bit a jank work around as it is.
*/
const hiddenInput = document.createElement(`input`);
this.#publicInput = hiddenInput;
hiddenInput.type = `hidden`;
hiddenInput.value = this.#input.value;
hiddenInput.name = this.getAttribute(`name`);
// this.removeAttribute(`name`);
// this.appendChild(hiddenInput);
if (!DotDungeonIncrementer.styles) {
fetch(`./systems/dotdungeon/.styles/v3/components/incrementer.css`)
.then(r => r.text())
@ -75,6 +106,16 @@ export class DotDungeonIncrementer extends HTMLElement {
};
};
get value() {
return this.#input.value;
};
get form() {
return this._internals.form;
};
get type() {
return `number`;
};
#embedStyles() {
const style = document.createElement(`style`);
style.innerHTML = DotDungeonIncrementer.styles;
@ -82,20 +123,36 @@ export class DotDungeonIncrementer extends HTMLElement {
};
#updateValue() {
this.#publicInput.value = this.#input.value;
const event = new Event(`change`, { bubbles: true });
this.#publicInput.dispatchEvent(event);
let value = parseInt(this.#input.value);
if (this.getAttribute(`min`)) value = Math.max(this.#min, value);
if (this.getAttribute(`max`)) value = Math.min(this.#max, value);
this.#input.value = value;
if (this.#input.value === this.#publicInput.value) return;
this.#publicInput.value = value;
const event = new Event(`change`);
// this.#publicInput.dispatchEvent(event);
console.log(`#updateValue`)
this.dispatchEvent(event);
};
#increment() {
this.#input.value++;
#increment($e) {
let value = parseInt(this.#input.value);
value += $e.ctrlKey ? this.#largeStep : this.#smallStep;
this.#input.value = value;
this.#updateValue();
};
#decrement() {
this.#input.value--;
#decrement($e) {
let value = parseInt(this.#input.value);
value -= $e.ctrlKey ? this.#largeStep : this.#smallStep;
this.#input.value = value;
this.#updateValue();
};
focus() {
console.log(1)
super.focus();
}
};