496 lines
15 KiB
JavaScript
496 lines
15 KiB
JavaScript
import {
|
|
input_styles_default
|
|
} from "./chunk.53DWOBDF.js";
|
|
import {
|
|
l
|
|
} from "./chunk.MB643KRE.js";
|
|
import {
|
|
defaultValue
|
|
} from "./chunk.RQ7JZ4R7.js";
|
|
import {
|
|
FormControlController
|
|
} from "./chunk.NMS6LWK4.js";
|
|
import {
|
|
LocalizeController
|
|
} from "./chunk.NH3SRVOC.js";
|
|
import {
|
|
o
|
|
} from "./chunk.2URMUHDY.js";
|
|
import {
|
|
HasSlotController
|
|
} from "./chunk.NYIIDP5N.js";
|
|
import {
|
|
e
|
|
} from "./chunk.UZVKBFXH.js";
|
|
import {
|
|
SlIcon
|
|
} from "./chunk.UZYAV5H6.js";
|
|
import {
|
|
watch
|
|
} from "./chunk.FA5RT4K4.js";
|
|
import {
|
|
ShoelaceElement,
|
|
e as e2,
|
|
n,
|
|
r
|
|
} from "./chunk.SEXBCYCU.js";
|
|
import {
|
|
x
|
|
} from "./chunk.CXZZ2LVK.js";
|
|
import {
|
|
__decorateClass
|
|
} from "./chunk.KIILAQWQ.js";
|
|
|
|
// src/components/input/input.component.ts
|
|
var SlInput = class extends ShoelaceElement {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.formControlController = new FormControlController(this, {
|
|
assumeInteractionOn: ["sl-blur", "sl-input"]
|
|
});
|
|
this.hasSlotController = new HasSlotController(this, "help-text", "label");
|
|
this.localize = new LocalizeController(this);
|
|
this.hasFocus = false;
|
|
this.title = "";
|
|
// make reactive to pass through
|
|
this.__numberInput = Object.assign(document.createElement("input"), { type: "number" });
|
|
this.__dateInput = Object.assign(document.createElement("input"), { type: "date" });
|
|
this.type = "text";
|
|
this.name = "";
|
|
this.value = "";
|
|
this.defaultValue = "";
|
|
this.size = "medium";
|
|
this.filled = false;
|
|
this.pill = false;
|
|
this.label = "";
|
|
this.helpText = "";
|
|
this.clearable = false;
|
|
this.disabled = false;
|
|
this.placeholder = "";
|
|
this.readonly = false;
|
|
this.passwordToggle = false;
|
|
this.passwordVisible = false;
|
|
this.noSpinButtons = false;
|
|
this.form = "";
|
|
this.required = false;
|
|
this.spellcheck = true;
|
|
}
|
|
//
|
|
// NOTE: We use an in-memory input for these getters/setters instead of the one in the template because the properties
|
|
// can be set before the component is rendered.
|
|
//
|
|
/**
|
|
* Gets or sets the current value as a `Date` object. Returns `null` if the value can't be converted. This will use the native `<input type="{{type}}">` implementation and may result in an error.
|
|
*/
|
|
get valueAsDate() {
|
|
var _a;
|
|
this.__dateInput.type = this.type;
|
|
this.__dateInput.value = this.value;
|
|
return ((_a = this.input) == null ? void 0 : _a.valueAsDate) || this.__dateInput.valueAsDate;
|
|
}
|
|
set valueAsDate(newValue) {
|
|
this.__dateInput.type = this.type;
|
|
this.__dateInput.valueAsDate = newValue;
|
|
this.value = this.__dateInput.value;
|
|
}
|
|
/** Gets or sets the current value as a number. Returns `NaN` if the value can't be converted. */
|
|
get valueAsNumber() {
|
|
var _a;
|
|
this.__numberInput.value = this.value;
|
|
return ((_a = this.input) == null ? void 0 : _a.valueAsNumber) || this.__numberInput.valueAsNumber;
|
|
}
|
|
set valueAsNumber(newValue) {
|
|
this.__numberInput.valueAsNumber = newValue;
|
|
this.value = this.__numberInput.value;
|
|
}
|
|
/** Gets the validity state object */
|
|
get validity() {
|
|
return this.input.validity;
|
|
}
|
|
/** Gets the validation message */
|
|
get validationMessage() {
|
|
return this.input.validationMessage;
|
|
}
|
|
firstUpdated() {
|
|
this.formControlController.updateValidity();
|
|
}
|
|
handleBlur() {
|
|
this.hasFocus = false;
|
|
this.emit("sl-blur");
|
|
}
|
|
handleChange() {
|
|
this.value = this.input.value;
|
|
this.emit("sl-change");
|
|
}
|
|
handleClearClick(event) {
|
|
this.value = "";
|
|
this.emit("sl-clear");
|
|
this.emit("sl-input");
|
|
this.emit("sl-change");
|
|
this.input.focus();
|
|
event.stopPropagation();
|
|
}
|
|
handleFocus() {
|
|
this.hasFocus = true;
|
|
this.emit("sl-focus");
|
|
}
|
|
handleInput() {
|
|
this.value = this.input.value;
|
|
this.formControlController.updateValidity();
|
|
this.emit("sl-input");
|
|
}
|
|
handleInvalid(event) {
|
|
this.formControlController.setValidity(false);
|
|
this.formControlController.emitInvalidEvent(event);
|
|
}
|
|
handleKeyDown(event) {
|
|
const hasModifier = event.metaKey || event.ctrlKey || event.shiftKey || event.altKey;
|
|
if (event.key === "Enter" && !hasModifier) {
|
|
setTimeout(() => {
|
|
if (!event.defaultPrevented && !event.isComposing) {
|
|
this.formControlController.submit();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
handlePasswordToggle() {
|
|
this.passwordVisible = !this.passwordVisible;
|
|
}
|
|
handleDisabledChange() {
|
|
this.formControlController.setValidity(this.disabled);
|
|
}
|
|
handleStepChange() {
|
|
this.input.step = String(this.step);
|
|
this.formControlController.updateValidity();
|
|
}
|
|
async handleValueChange() {
|
|
await this.updateComplete;
|
|
this.formControlController.updateValidity();
|
|
}
|
|
/** Sets focus on the input. */
|
|
focus(options) {
|
|
this.input.focus(options);
|
|
}
|
|
/** Removes focus from the input. */
|
|
blur() {
|
|
this.input.blur();
|
|
}
|
|
/** Selects all the text in the input. */
|
|
select() {
|
|
this.input.select();
|
|
}
|
|
/** Sets the start and end positions of the text selection (0-based). */
|
|
setSelectionRange(selectionStart, selectionEnd, selectionDirection = "none") {
|
|
this.input.setSelectionRange(selectionStart, selectionEnd, selectionDirection);
|
|
}
|
|
/** Replaces a range of text with a new string. */
|
|
setRangeText(replacement, start, end, selectMode = "preserve") {
|
|
const selectionStart = start != null ? start : this.input.selectionStart;
|
|
const selectionEnd = end != null ? end : this.input.selectionEnd;
|
|
this.input.setRangeText(replacement, selectionStart, selectionEnd, selectMode);
|
|
if (this.value !== this.input.value) {
|
|
this.value = this.input.value;
|
|
}
|
|
}
|
|
/** Displays the browser picker for an input element (only works if the browser supports it for the input type). */
|
|
showPicker() {
|
|
if ("showPicker" in HTMLInputElement.prototype) {
|
|
this.input.showPicker();
|
|
}
|
|
}
|
|
/** Increments the value of a numeric input type by the value of the step attribute. */
|
|
stepUp() {
|
|
this.input.stepUp();
|
|
if (this.value !== this.input.value) {
|
|
this.value = this.input.value;
|
|
}
|
|
}
|
|
/** Decrements the value of a numeric input type by the value of the step attribute. */
|
|
stepDown() {
|
|
this.input.stepDown();
|
|
if (this.value !== this.input.value) {
|
|
this.value = this.input.value;
|
|
}
|
|
}
|
|
/** Checks for validity but does not show a validation message. Returns `true` when valid and `false` when invalid. */
|
|
checkValidity() {
|
|
return this.input.checkValidity();
|
|
}
|
|
/** Gets the associated form, if one exists. */
|
|
getForm() {
|
|
return this.formControlController.getForm();
|
|
}
|
|
/** Checks for validity and shows the browser's validation message if the control is invalid. */
|
|
reportValidity() {
|
|
return this.input.reportValidity();
|
|
}
|
|
/** Sets a custom validation message. Pass an empty string to restore validity. */
|
|
setCustomValidity(message) {
|
|
this.input.setCustomValidity(message);
|
|
this.formControlController.updateValidity();
|
|
}
|
|
render() {
|
|
const hasLabelSlot = this.hasSlotController.test("label");
|
|
const hasHelpTextSlot = this.hasSlotController.test("help-text");
|
|
const hasLabel = this.label ? true : !!hasLabelSlot;
|
|
const hasHelpText = this.helpText ? true : !!hasHelpTextSlot;
|
|
const hasClearIcon = this.clearable && !this.disabled && !this.readonly;
|
|
const isClearIconVisible = hasClearIcon && (typeof this.value === "number" || this.value.length > 0);
|
|
return x`
|
|
<div
|
|
part="form-control"
|
|
class=${e({
|
|
"form-control": true,
|
|
"form-control--small": this.size === "small",
|
|
"form-control--medium": this.size === "medium",
|
|
"form-control--large": this.size === "large",
|
|
"form-control--has-label": hasLabel,
|
|
"form-control--has-help-text": hasHelpText
|
|
})}
|
|
>
|
|
<label
|
|
part="form-control-label"
|
|
class="form-control__label"
|
|
for="input"
|
|
aria-hidden=${hasLabel ? "false" : "true"}
|
|
>
|
|
<slot name="label">${this.label}</slot>
|
|
</label>
|
|
|
|
<div part="form-control-input" class="form-control-input">
|
|
<div
|
|
part="base"
|
|
class=${e({
|
|
input: true,
|
|
// Sizes
|
|
"input--small": this.size === "small",
|
|
"input--medium": this.size === "medium",
|
|
"input--large": this.size === "large",
|
|
// States
|
|
"input--pill": this.pill,
|
|
"input--standard": !this.filled,
|
|
"input--filled": this.filled,
|
|
"input--disabled": this.disabled,
|
|
"input--focused": this.hasFocus,
|
|
"input--empty": !this.value,
|
|
"input--no-spin-buttons": this.noSpinButtons
|
|
})}
|
|
>
|
|
<span part="prefix" class="input__prefix">
|
|
<slot name="prefix"></slot>
|
|
</span>
|
|
|
|
<input
|
|
part="input"
|
|
id="input"
|
|
class="input__control"
|
|
type=${this.type === "password" && this.passwordVisible ? "text" : this.type}
|
|
title=${this.title}
|
|
name=${o(this.name)}
|
|
?disabled=${this.disabled}
|
|
?readonly=${this.readonly}
|
|
?required=${this.required}
|
|
placeholder=${o(this.placeholder)}
|
|
minlength=${o(this.minlength)}
|
|
maxlength=${o(this.maxlength)}
|
|
min=${o(this.min)}
|
|
max=${o(this.max)}
|
|
step=${o(this.step)}
|
|
.value=${l(this.value)}
|
|
autocapitalize=${o(this.autocapitalize)}
|
|
autocomplete=${o(this.autocomplete)}
|
|
autocorrect=${o(this.autocorrect)}
|
|
?autofocus=${this.autofocus}
|
|
spellcheck=${this.spellcheck}
|
|
pattern=${o(this.pattern)}
|
|
enterkeyhint=${o(this.enterkeyhint)}
|
|
inputmode=${o(this.inputmode)}
|
|
aria-describedby="help-text"
|
|
@change=${this.handleChange}
|
|
@input=${this.handleInput}
|
|
@invalid=${this.handleInvalid}
|
|
@keydown=${this.handleKeyDown}
|
|
@focus=${this.handleFocus}
|
|
@blur=${this.handleBlur}
|
|
/>
|
|
|
|
${hasClearIcon ? x`
|
|
<button
|
|
part="clear-button"
|
|
class=${e({
|
|
input__clear: true,
|
|
"input__clear--visible": isClearIconVisible
|
|
})}
|
|
type="button"
|
|
aria-label=${this.localize.term("clearEntry")}
|
|
@click=${this.handleClearClick}
|
|
tabindex="-1"
|
|
>
|
|
<slot name="clear-icon">
|
|
<sl-icon name="x-circle-fill" library="system"></sl-icon>
|
|
</slot>
|
|
</button>
|
|
` : ""}
|
|
${this.passwordToggle && !this.disabled ? x`
|
|
<button
|
|
part="password-toggle-button"
|
|
class="input__password-toggle"
|
|
type="button"
|
|
aria-label=${this.localize.term(this.passwordVisible ? "hidePassword" : "showPassword")}
|
|
@click=${this.handlePasswordToggle}
|
|
tabindex="-1"
|
|
>
|
|
${this.passwordVisible ? x`
|
|
<slot name="show-password-icon">
|
|
<sl-icon name="eye-slash" library="system"></sl-icon>
|
|
</slot>
|
|
` : x`
|
|
<slot name="hide-password-icon">
|
|
<sl-icon name="eye" library="system"></sl-icon>
|
|
</slot>
|
|
`}
|
|
</button>
|
|
` : ""}
|
|
|
|
<span part="suffix" class="input__suffix">
|
|
<slot name="suffix"></slot>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div
|
|
part="form-control-help-text"
|
|
id="help-text"
|
|
class="form-control__help-text"
|
|
aria-hidden=${hasHelpText ? "false" : "true"}
|
|
>
|
|
<slot name="help-text">${this.helpText}</slot>
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
};
|
|
SlInput.styles = input_styles_default;
|
|
SlInput.dependencies = { "sl-icon": SlIcon };
|
|
__decorateClass([
|
|
e2(".input__control")
|
|
], SlInput.prototype, "input", 2);
|
|
__decorateClass([
|
|
r()
|
|
], SlInput.prototype, "hasFocus", 2);
|
|
__decorateClass([
|
|
n()
|
|
], SlInput.prototype, "title", 2);
|
|
__decorateClass([
|
|
n({ reflect: true })
|
|
], SlInput.prototype, "type", 2);
|
|
__decorateClass([
|
|
n()
|
|
], SlInput.prototype, "name", 2);
|
|
__decorateClass([
|
|
n()
|
|
], SlInput.prototype, "value", 2);
|
|
__decorateClass([
|
|
defaultValue()
|
|
], SlInput.prototype, "defaultValue", 2);
|
|
__decorateClass([
|
|
n({ reflect: true })
|
|
], SlInput.prototype, "size", 2);
|
|
__decorateClass([
|
|
n({ type: Boolean, reflect: true })
|
|
], SlInput.prototype, "filled", 2);
|
|
__decorateClass([
|
|
n({ type: Boolean, reflect: true })
|
|
], SlInput.prototype, "pill", 2);
|
|
__decorateClass([
|
|
n()
|
|
], SlInput.prototype, "label", 2);
|
|
__decorateClass([
|
|
n({ attribute: "help-text" })
|
|
], SlInput.prototype, "helpText", 2);
|
|
__decorateClass([
|
|
n({ type: Boolean })
|
|
], SlInput.prototype, "clearable", 2);
|
|
__decorateClass([
|
|
n({ type: Boolean, reflect: true })
|
|
], SlInput.prototype, "disabled", 2);
|
|
__decorateClass([
|
|
n()
|
|
], SlInput.prototype, "placeholder", 2);
|
|
__decorateClass([
|
|
n({ type: Boolean, reflect: true })
|
|
], SlInput.prototype, "readonly", 2);
|
|
__decorateClass([
|
|
n({ attribute: "password-toggle", type: Boolean })
|
|
], SlInput.prototype, "passwordToggle", 2);
|
|
__decorateClass([
|
|
n({ attribute: "password-visible", type: Boolean })
|
|
], SlInput.prototype, "passwordVisible", 2);
|
|
__decorateClass([
|
|
n({ attribute: "no-spin-buttons", type: Boolean })
|
|
], SlInput.prototype, "noSpinButtons", 2);
|
|
__decorateClass([
|
|
n({ reflect: true })
|
|
], SlInput.prototype, "form", 2);
|
|
__decorateClass([
|
|
n({ type: Boolean, reflect: true })
|
|
], SlInput.prototype, "required", 2);
|
|
__decorateClass([
|
|
n()
|
|
], SlInput.prototype, "pattern", 2);
|
|
__decorateClass([
|
|
n({ type: Number })
|
|
], SlInput.prototype, "minlength", 2);
|
|
__decorateClass([
|
|
n({ type: Number })
|
|
], SlInput.prototype, "maxlength", 2);
|
|
__decorateClass([
|
|
n()
|
|
], SlInput.prototype, "min", 2);
|
|
__decorateClass([
|
|
n()
|
|
], SlInput.prototype, "max", 2);
|
|
__decorateClass([
|
|
n()
|
|
], SlInput.prototype, "step", 2);
|
|
__decorateClass([
|
|
n()
|
|
], SlInput.prototype, "autocapitalize", 2);
|
|
__decorateClass([
|
|
n()
|
|
], SlInput.prototype, "autocorrect", 2);
|
|
__decorateClass([
|
|
n()
|
|
], SlInput.prototype, "autocomplete", 2);
|
|
__decorateClass([
|
|
n({ type: Boolean })
|
|
], SlInput.prototype, "autofocus", 2);
|
|
__decorateClass([
|
|
n()
|
|
], SlInput.prototype, "enterkeyhint", 2);
|
|
__decorateClass([
|
|
n({
|
|
type: Boolean,
|
|
converter: {
|
|
// Allow "true|false" attribute values but keep the property boolean
|
|
fromAttribute: (value) => !value || value === "false" ? false : true,
|
|
toAttribute: (value) => value ? "true" : "false"
|
|
}
|
|
})
|
|
], SlInput.prototype, "spellcheck", 2);
|
|
__decorateClass([
|
|
n()
|
|
], SlInput.prototype, "inputmode", 2);
|
|
__decorateClass([
|
|
watch("disabled", { waitUntilFirstUpdate: true })
|
|
], SlInput.prototype, "handleDisabledChange", 1);
|
|
__decorateClass([
|
|
watch("step", { waitUntilFirstUpdate: true })
|
|
], SlInput.prototype, "handleStepChange", 1);
|
|
__decorateClass([
|
|
watch("value", { waitUntilFirstUpdate: true })
|
|
], SlInput.prototype, "handleValueChange", 1);
|
|
|
|
export {
|
|
SlInput
|
|
};
|