more fixes

This commit is contained in:
konnorrogers
2025-06-05 17:32:39 -04:00
parent 5501133c64
commit b7bfc57a77
4 changed files with 85 additions and 92 deletions

View File

@@ -286,4 +286,4 @@ Mark a slider as required using the `required` attribute. Users must interact wi
<br />
<button type="submit">Submit</button>
</form>
```
```

View File

@@ -12,9 +12,9 @@ import formControlStyles from '../../styles/component/form-control.css';
import appearanceStyles from '../../styles/utilities/appearance.css';
import sizeStyles from '../../styles/utilities/size.css';
import { LocalizeController } from '../../utilities/localize.js';
import type WaButton from '../button/button.js';
import '../icon/icon.js';
import styles from './input.css';
import { submitOnEnter } from '../../internal/submit-on-enter.js';
/**
* @summary Inputs collect data from the user.
@@ -245,51 +245,7 @@ export default class WaInput extends WebAwesomeFormAssociatedElement {
}
private handleKeyDown(event: KeyboardEvent) {
const hasModifier = event.metaKey || event.ctrlKey || event.shiftKey || event.altKey;
// Pressing enter when focused on an input should submit the form like a native input, but we wait a tick before
// submitting to allow users to cancel the keydown event if they need to
if (event.key === 'Enter' && !hasModifier) {
setTimeout(() => {
//
// When using an Input Method Editor (IME), pressing enter will cause the form to submit unexpectedly. One way
// to check for this is to look at event.isComposing, which will be true when the IME is open.
//
// See https://github.com/shoelace-style/shoelace/pull/988
//
if (!event.defaultPrevented && !event.isComposing) {
const form = this.getForm();
if (!form) {
return;
}
const formElements = [...form.elements];
// If we're the only formElement, we submit like a native input.
if (formElements.length === 1) {
form.requestSubmit(null);
return;
}
const button = formElements.find(
(el: HTMLButtonElement) => el.type === 'submit' && !el.matches(':disabled'),
) as undefined | HTMLButtonElement | WaButton;
// No button found, don't submit.
if (!button) {
return;
}
if (button.tagName.toLowerCase() === 'button') {
form.requestSubmit(button);
} else {
// requestSubmit() wont work with `<wa-button>`
button.click();
}
}
});
}
submitOnEnter(event, this)
}
private handlePasswordToggle() {

View File

@@ -13,6 +13,7 @@ import { LocalizeController } from '../../utilities/localize.js';
import '../tooltip/tooltip.js';
import type WaTooltip from '../tooltip/tooltip.js';
import styles from './slider.css';
import { submitOnEnter } from '../../internal/submit-on-enter.js';
/**
* <wa-slider>
@@ -79,7 +80,7 @@ export default class WaSlider extends WebAwesomeFormAssociatedElement {
private readonly hasSlotController = new HasSlotController(this, 'hint', 'label');
private readonly localize = new LocalizeController(this);
private trackBoundingClientRect: DOMRect;
private valueWhenDraggingStarted: number | undefined;
private valueWhenDraggingStarted: number | undefined | null;
private activeThumb: 'min' | 'max' | null = null;
private lastTrackPosition: number | null = null; // Track last position for direction detection
@@ -111,10 +112,20 @@ export default class WaSlider extends WebAwesomeFormAssociatedElement {
/** The name of the slider. This will be submitted with the form as a name/value pair. */
@property({ reflect: true }) name: string;
private _value: number | null = null;
/** The minimum value of a range selection. Used only when range attribute is set. */
@property({ type: Number, attribute: 'min-value' }) minValue = 0;
/** The maximum value of a range selection. Used only when range attribute is set. */
@property({ type: Number, attribute: 'max-value' }) maxValue = 50;
/** The default value of the form control. Primarily used for resetting the form control. */
@property({ attribute: 'value', reflect: true, type: Number }) defaultValue: number =
this.getAttribute('value') == null ? this.minValue : Number(this.getAttribute("value"));
private _value: number = this.defaultValue;
/** The current value of the slider, submitted as a name/value pair with form data. */
get value() {
get value(): number {
if (this.valueHasChanged) {
return this._value;
}
@@ -124,7 +135,7 @@ export default class WaSlider extends WebAwesomeFormAssociatedElement {
@state()
set value(val: number | null) {
val = Number(val) ?? null;
val = Number(val) ?? this.minValue;
if (this._value === val) {
return;
@@ -134,15 +145,6 @@ export default class WaSlider extends WebAwesomeFormAssociatedElement {
this._value = val;
}
/** The minimum value of a range selection. Used only when range attribute is set. */
@property({ type: Number, attribute: 'min-value' }) minValue = 0;
/** The maximum value of a range selection. Used only when range attribute is set. */
@property({ type: Number, attribute: 'max-value' }) maxValue = 50;
/** The default value of the form control. Primarily used for resetting the form control. */
@property({ attribute: 'value', reflect: true, type: Number }) defaultValue: number | null =
Number(this.getAttribute('value')) || this.minValue;
/** Converts the slider to a range slider with two thumbs. */
@property({ type: Boolean, reflect: true }) range = false;
@@ -210,16 +212,6 @@ export default class WaSlider extends WebAwesomeFormAssociatedElement {
*/
@property({ attribute: false }) valueFormatter: (value: number) => string;
connectedCallback() {
super.connectedCallback();
this.addEventListener('invalid', this.handleHostInvalid);
}
disconnectedCallback() {
super.disconnectedCallback();
this.removeEventListener('invalid', this.handleHostInvalid);
}
firstUpdated() {
// Setup dragging based on range or single thumb mode
if (this.isRange) {
@@ -384,7 +376,9 @@ export default class WaSlider extends WebAwesomeFormAssociatedElement {
} else {
// Handle value for single thumb mode
if (changedProperties.has('value')) {
this.value = clamp(this.value, this.min, this.max);
if (this.value != null) {
this.value = clamp(this.value, this.min, this.max);
}
this.setValue(String(this.value));
}
}
@@ -434,9 +428,7 @@ export default class WaSlider extends WebAwesomeFormAssociatedElement {
} else {
this.value = parseFloat(this.getAttribute('value') ?? String(this.min));
}
this.isInvalid = false;
this.hasInteracted = false;
this.wasSubmitted = false;
super.formResetCallback();
}
@@ -509,16 +501,6 @@ export default class WaSlider extends WebAwesomeFormAssociatedElement {
this.dispatchEvent(new FocusEvent('focus', { bubbles: true, composed: true }));
}
private handleHostInvalid() {
//
// We need to simulate the :user-invalid state when the form is submitted. Alas, there's no way to listen to form
// submit because validation occurs before the `formdata` and `submit` events. The only way I've found to hook into
// it is by listening to the `invalid` event on the host element, which is dispatched by the browser when the form
// is submitted and the form-associated custom element is invalid.
//
this.wasSubmitted = true;
}
private handleKeyDown(event: KeyboardEvent) {
const isRtl = this.localize.dir() === 'rtl';
const target = event.target as HTMLElement;
@@ -591,15 +573,7 @@ export default class WaSlider extends WebAwesomeFormAssociatedElement {
// Handle form submission on Enter
case 'Enter':
if (this.internals.form) {
const submitter = [...this.internals.form.elements].find((el: HTMLInputElement | HTMLButtonElement) => {
// The first submit button associated with the form will be the submitter. At this time, only native buttons
// can be submitters (see https://github.com/WICG/webcomponents/issues/814)
return ['button', 'input'].includes(el.localName) && el.type === 'submit';
}) as HTMLElement;
this.internals.form.requestSubmit(submitter);
}
submitOnEnter(event, this)
return;
}

View File

@@ -0,0 +1,63 @@
import type WaButton from "../components/button/button.js";
import type { WebAwesomeFormAssociatedElement } from "./webawesome-form-associated-element.js";
export function submitOnEnter<T extends HTMLElement>(event: KeyboardEvent, el: T) {
const hasModifier = event.metaKey || event.ctrlKey || event.shiftKey || event.altKey;
// Pressing enter when focused on an input should submit the form like a native input, but we wait a tick before
// submitting to allow users to cancel the keydown event if they need to
if (event.key === 'Enter' && !hasModifier) {
// setTimeout in case the event is caught higher up in the tree and defaultPrevented
setTimeout(() => {
//
// When using an Input Method Editor (IME), pressing enter will cause the form to submit unexpectedly. One way
// to check for this is to look at event.isComposing, which will be true when the IME is open.
//
// See https://github.com/shoelace-style/shoelace/pull/988
//
if (!event.defaultPrevented && !event.isComposing) {
submitForm(el)
}
});
}
}
export function submitForm (el: HTMLElement | WebAwesomeFormAssociatedElement) {
let form: HTMLFormElement | null = null
if ("form" in el) {
form = el.form as HTMLFormElement | null
}
if (!form && "getForm" in el) {
form = el.getForm()
}
if (!form) {
return;
}
const formElements = [...form.elements];
// If we're the only formElement, we submit like a native input.
if (formElements.length === 1) {
form.requestSubmit(null);
return;
}
const button = formElements.find(
(el: HTMLButtonElement) => el.type === 'submit' && !el.matches(':disabled'),
) as undefined | HTMLButtonElement | WaButton;
// No button found, don't submit.
if (!button) {
return;
}
if (['input', 'button'].includes(button.localName)) {
form.requestSubmit(button);
} else {
// requestSubmit() wont work with `<wa-button>`, so trigger a manual click.
button.click();
}
}