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: Attributes:
@property {string} name - The path to the value to update @property {string} name - The path to the value to update
@property {number} value - The actual value of the input @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: Styling:
- `--height`: Controls the height of the element + the width of the buttons (default: 1.25rem) - `--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 { export class DotDungeonIncrementer extends HTMLElement {
static elementName = `dd-incrementer`; static elementName = `dd-incrementer`;
static formAssociated = true;
static styles = ``; static styles = ``;
#min;
#max;
#smallStep;
#largeStep;
#input; #input;
#publicInput; #publicInput;
#sr; #sr;
@ -19,40 +29,47 @@ export class DotDungeonIncrementer extends HTMLElement {
constructor() { constructor() {
super(); super();
this._internals = this.attachInternals();
const value = this.getAttribute(`value`); 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);
/* const sr = this.attachShadow({
This input exists for the sole purpose of making it so that the form data mode: `open`,
works with this input without needing to do jank work arounds (even though delegatesFocus: true
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` });
this.#sr = sr; this.#sr = sr;
const container = document.createElement(`div`); const container = document.createElement(`div`);
if (DotDungeonIncrementer.styles) this.#embedStyles(); if (DotDungeonIncrementer.styles) this.#embedStyles();
// The input that the user can see / modify
const input = document.createElement(`input`); const input = document.createElement(`input`);
this.#input = input; this.#input = input;
input.type = `number`; input.type = `number`;
input.min = this.getAttribute(`min`);
input.max = this.getAttribute(`max`);
input.addEventListener(`change`, this.#updateValue.bind(this)); input.addEventListener(`change`, this.#updateValue.bind(this));
input.value = value; 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.innerHTML = `+`;
increment.type = `button`; // increment.type = `button`;
// increment.tabIndex = -1;
increment.classList.value = `increment`; increment.classList.value = `increment`;
increment.addEventListener(`click`, this.#increment.bind(this)); increment.addEventListener(`click`, this.#increment.bind(this));
const decrement = document.createElement(`button`); // minus button
const decrement = document.createElement(`span`);
decrement.innerHTML = `-`; decrement.innerHTML = `-`;
decrement.type = `button`; // decrement.type = `button`;
// decrement.tabIndex = -1;
decrement.classList.value = `decrement`; decrement.classList.value = `decrement`;
decrement.addEventListener(`click`, this.#decrement.bind(this)); decrement.addEventListener(`click`, this.#decrement.bind(this));
@ -65,6 +82,20 @@ export class DotDungeonIncrementer extends HTMLElement {
}; };
connectedCallback() { 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) { if (!DotDungeonIncrementer.styles) {
fetch(`./systems/dotdungeon/.styles/v3/components/incrementer.css`) fetch(`./systems/dotdungeon/.styles/v3/components/incrementer.css`)
.then(r => r.text()) .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() { #embedStyles() {
const style = document.createElement(`style`); const style = document.createElement(`style`);
style.innerHTML = DotDungeonIncrementer.styles; style.innerHTML = DotDungeonIncrementer.styles;
@ -82,20 +123,36 @@ export class DotDungeonIncrementer extends HTMLElement {
}; };
#updateValue() { #updateValue() {
this.#publicInput.value = this.#input.value; let value = parseInt(this.#input.value);
const event = new Event(`change`, { bubbles: true }); if (this.getAttribute(`min`)) value = Math.max(this.#min, value);
this.#publicInput.dispatchEvent(event); 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() { #increment($e) {
this.#input.value++; let value = parseInt(this.#input.value);
value += $e.ctrlKey ? this.#largeStep : this.#smallStep;
this.#input.value = value;
this.#updateValue(); this.#updateValue();
}; };
#decrement() { #decrement($e) {
this.#input.value--; let value = parseInt(this.#input.value);
value -= $e.ctrlKey ? this.#largeStep : this.#smallStep;
this.#input.value = value;
this.#updateValue(); this.#updateValue();
}; };
focus() {
console.log(1)
super.focus();
}
}; };

View file

@ -26,7 +26,7 @@ div {
} }
} }
button, input { span, input {
border: none; border: none;
outline: none; outline: none;
background: none; background: none;
@ -36,7 +36,7 @@ button, input {
input { input {
font-family: inherit; font-family: inherit;
text-align: center; text-align: center;
padding: 0; padding: 2px 4px;
&::-webkit-inner-spin-button, &::-webkit-outer-spin-button { &::-webkit-inner-spin-button, &::-webkit-outer-spin-button {
-webkit-appearance: none; -webkit-appearance: none;
@ -46,16 +46,13 @@ input {
} }
} }
button { span {
aspect-ratio: 1 / 1; aspect-ratio: 1 / 1;
padding: 0; padding: 0;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
&:hover {
cursor: pointer; cursor: pointer;
}
} }
.increment { .increment {

View file

@ -11,12 +11,16 @@
</div> </div>
<div class="e-1dp panel bytes-panel"> <div class="e-1dp panel bytes-panel">
<label <label
for="{{meta.idp}}-player-inventory-supplies-input" for="{{meta.idp}}-player-inventory-supplies"
> >
Supplies Supplies
</label> </label>
<dd-incrementer name="system.supplies" value="{{system.supplies}}"></dd-incrementer> <dd-incrementer
{{!-- <input is="dd-incrementer"> --}} name="system.supplies"
value="{{system.supplies}}"
id="{{meta.idp}}-player-inventory-supplies"
min="0"
></dd-incrementer>
{{!-- <button {{!-- <button
type="button" type="button"
class="icon" class="icon"
@ -29,7 +33,7 @@
</button> </button>
<input <input
type="number" type="number"
id="{{meta.idp}}-player-inventory-supplies-input"
value="{{system.supplies}}" value="{{system.supplies}}"
> >
<button <button