UNPKG

@esri/calcite-components

Version:

Web Components for Esri's Calcite Design System.

283 lines (282 loc) • 20.4 kB
/*! All material copyright ESRI, All Rights Reserved, unless otherwise specified. See https://github.com/Esri/calcite-design-system/blob/dev/LICENSE.md for details. v3.2.1 */ import { C as CSS_UTILITY, c as customElement } from "../../chunks/runtime.js"; import { live } from "lit-html/directives/live.js"; import { html, nothing } from "lit"; import { createRef, ref } from "lit-html/directives/ref.js"; import { LitElement, createEvent, stringOrBoolean, safeClassMap } from "@arcgis/lumina"; import { useWatchAttributes } from "@arcgis/lumina/controllers"; import { v as setRequestedIcon, g as getElementDir } from "../../chunks/dom.js"; import { c as connectForm, i as internalHiddenInputInputEvent, d as disconnectForm, s as submitForm, H as HiddenFormInputSlot } from "../../chunks/form.js"; import { u as updateHostInteraction, I as InteractiveContainer } from "../../chunks/interactive.js"; import { c as connectLabel, d as disconnectLabel, g as getLabelText } from "../../chunks/label.js"; import { c as componentFocusable, g as getIconScale } from "../../chunks/component.js"; import { V as Validation } from "../../chunks/Validation.js"; import { s as syncHiddenFormInput } from "../../chunks/input.js"; import { u as useT9n } from "../../chunks/useT9n.js"; import { css } from "@lit/reactive-element/css-tag.js"; const CSS = { loader: "loader", clearButton: "clear-button", editingEnabled: "editing-enabled", inlineChild: "inline-child", inputIcon: "icon", prefix: "prefix", suffix: "suffix", wrapper: "element-wrapper", inputWrapper: "wrapper", actionWrapper: "action-wrapper" }; const IDS = { validationMessage: "inputTextValidationMessage" }; const SLOTS = { action: "action" }; const styles = css`:host([disabled]){cursor:default;-webkit-user-select:none;user-select:none;opacity:var(--calcite-opacity-disabled)}:host([disabled]) *,:host([disabled]) ::slotted(*){pointer-events:none}:host{display:block}:host([scale=s]) input{padding-inline-start:.5rem;padding-inline-end:var(--calcite-internal-input-text-input-padding-inline-end, .5rem)}:host([scale=s]) input,:host([scale=s]) .prefix,:host([scale=s]) .suffix{block-size:1.5rem;font-size:var(--calcite-font-size--2);line-height:1rem}:host([scale=s]) .prefix,:host([scale=s]) .suffix{padding-inline:.5rem}:host([scale=s]) .action-wrapper calcite-button,:host([scale=s]) .action-wrapper calcite-button button{block-size:1.5rem}:host([scale=s]) .clear-button{min-block-size:1.5rem;min-inline-size:1.5rem}:host([scale=m]) input{padding-inline-start:.75rem;padding-inline-end:var(--calcite-internal-input-text-input-padding-inline-end, .75rem)}:host([scale=m]) input,:host([scale=m]) .prefix,:host([scale=m]) .suffix{block-size:2rem;font-size:var(--calcite-font-size--1);line-height:1rem}:host([scale=m]) .prefix,:host([scale=m]) .suffix{padding-inline:.75rem}:host([scale=m]) .action-wrapper calcite-button,:host([scale=m]) .action-wrapper calcite-button button{block-size:2rem}:host([scale=m]) .clear-button{min-block-size:2rem;min-inline-size:2rem}:host([scale=l]) input{padding-inline-start:1rem;padding-inline-end:var(--calcite-internal-input-text-input-padding-inline-end, 1rem)}:host([scale=l]) input,:host([scale=l]) .prefix,:host([scale=l]) .suffix{block-size:2.75rem;font-size:var(--calcite-font-size-0);line-height:1.25rem}:host([scale=l]) .prefix,:host([scale=l]) .suffix{padding-inline:1rem}:host([scale=l]) .action-wrapper calcite-button,:host([scale=l]) .action-wrapper calcite-button button{block-size:2.75rem}:host([scale=l]) .clear-button{min-block-size:2.75rem;min-inline-size:2.75rem}:host([disabled]) ::slotted([calcite-hydrated][disabled]),:host([disabled]) [calcite-hydrated][disabled]{opacity:1}.interaction-container{display:contents}input{transition:var(--calcite-animation-timing),block-size 0,outline-offset 0s;-webkit-appearance:none;position:relative;margin:0;box-sizing:border-box;display:flex;max-block-size:100%;inline-size:100%;max-inline-size:100%;flex:1 1 0%;text-overflow:ellipsis;border-radius:0;background-color:var(--calcite-color-foreground-1);font-family:inherit;font-weight:var(--calcite-font-weight-normal);color:var(--calcite-color-text-1)}input:placeholder-shown{text-overflow:ellipsis}input{border-width:1px;border-style:solid;border-color:var(--calcite-color-border-input);color:var(--calcite-color-text-1)}input::placeholder,input:-ms-input-placeholder,input::-ms-input-placeholder{font-weight:var(--calcite-font-weight-normal);color:var(--calcite-color-text-3)}input:focus{border-color:var(--calcite-color-brand);color:var(--calcite-color-text-1)}input[readonly]{background-color:var(--calcite-color-background);font-weight:var(--calcite-font-weight-medium)}input[readonly]:focus{color:var(--calcite-color-text-1)}calcite-icon{color:var(--calcite-color-text-3)}input{outline-color:transparent}input:focus{outline:2px solid var(--calcite-color-focus, var(--calcite-ui-focus-color, var(--calcite-color-brand)));outline-offset:calc(-2px*(1 - (2*clamp(0,var(--calcite-offset-invert-focus),1))))}:host([status=invalid]) input{border-color:var(--calcite-color-status-danger)}:host([status=invalid]) input:focus{outline:2px solid var(--calcite-color-status-danger);outline-offset:calc(-2px*(1 - (2*clamp(0,var(--calcite-offset-invert-focus),1))))}:host([scale=s]) .icon{inset-inline-start:.5rem}:host([scale=m]) .icon{inset-inline-start:.75rem}:host([scale=l]) .icon{inset-inline-start:1rem}:host([icon][scale=s]) input{padding-inline-start:2rem}:host([icon][scale=m]) input{padding-inline-start:2.5rem}:host([icon][scale=l]) input{padding-inline-start:3.5rem}.element-wrapper{position:relative;order:3;display:inline-flex;flex:1 1 0%;align-items:center}.icon{pointer-events:none;position:absolute;z-index:var(--calcite-z-index);display:block;transition-property:background-color,block-size,border-color,box-shadow,color,inset-block-end,inset-block-start,inset-inline-end,inset-inline-start,inset-size,opacity,outline-color,transform;transition-duration:var(--calcite-animation-timing);transition-timing-function:ease-in-out}input[type=text]::-ms-clear,input[type=text]::-ms-reveal{display:none;block-size:0px;inline-size:0px}.clear-button{pointer-events:initial;order:4;margin:0;box-sizing:border-box;display:flex;min-block-size:100%;cursor:pointer;align-items:center;justify-content:center;align-self:stretch;border-width:1px;border-style:solid;border-color:var(--calcite-color-border-input);background-color:var(--calcite-color-foreground-1);outline-color:transparent;border-inline-start-width:0px}.clear-button:hover{background-color:var(--calcite-color-foreground-2);transition-property:background-color,block-size,border-color,box-shadow,color,inset-block-end,inset-block-start,inset-inline-end,inset-inline-start,inset-size,opacity,outline-color,transform;transition-duration:var(--calcite-animation-timing);transition-timing-function:ease-in-out}.clear-button:hover calcite-icon{color:var(--calcite-color-text-1);transition-property:background-color,block-size,border-color,box-shadow,color,inset-block-end,inset-block-start,inset-inline-end,inset-inline-start,inset-size,opacity,outline-color,transform;transition-duration:var(--calcite-animation-timing);transition-timing-function:ease-in-out}.clear-button:active{background-color:var(--calcite-color-foreground-3)}.clear-button:active calcite-icon{color:var(--calcite-color-text-1)}.clear-button:focus{outline:2px solid var(--calcite-color-focus, var(--calcite-ui-focus-color, var(--calcite-color-brand)));outline-offset:calc(-2px*(1 - (2*clamp(0,var(--calcite-offset-invert-focus),1))))}.clear-button:disabled{opacity:var(--calcite-opacity-disabled)}.loader{inset-block-start:1px;inset-inline:1px;pointer-events:none;position:absolute;display:block}.action-wrapper{order:7;display:flex}.prefix,.suffix{box-sizing:border-box;display:flex;block-size:auto;min-block-size:100%;-webkit-user-select:none;user-select:none;align-content:center;align-items:center;overflow-wrap:break-word;border-width:1px;border-style:solid;border-color:var(--calcite-color-border-input);background-color:var(--calcite-color-background);font-weight:var(--calcite-font-weight-medium);line-height:1;color:var(--calcite-color-text-2)}.prefix{order:2;border-inline-end-width:0px;inline-size:var(--calcite-input-prefix-size, auto)}.suffix{order:5;border-inline-start-width:0px;inline-size:var(--calcite-input-suffix-size, auto)}:host([alignment=start]) input{text-align:start}:host([alignment=end]) input{text-align:end}.wrapper{position:relative;display:flex;flex-direction:row;align-items:center}:host(.input--no-bottom-border) input{border-block-end-width:0px}:host(.input--no-top-border) input{border-block-start-width:0px}:host(.input--no-right-border) input{border-inline-end:0}:host(.input--no-left-border) input{border-inline-start:0}:host(.border-top-color-one) input{border-block-start-color:var(--calcite-color-border-1)}input.inline-child{background-color:transparent;transition-property:background-color,block-size,border-color,box-shadow,color,inset-block-end,inset-block-start,inset-inline-end,inset-inline-start,inset-size,opacity,outline-color,transform;transition-duration:var(--calcite-animation-timing);transition-timing-function:ease-in-out}input.inline-child .editing-enabled{background-color:inherit}input.inline-child:not(.editing-enabled){display:flex;cursor:pointer;text-overflow:ellipsis;border-color:transparent;padding-inline-start:0}.validation-container{display:flex;flex-direction:column;align-items:flex-start;align-self:stretch}:host([scale=m]) .validation-container,:host([scale=l]) .validation-container{padding-block-start:.5rem}:host([scale=s]) .validation-container{padding-block-start:.25rem}::slotted(input[slot=hidden-form-input]){margin:0!important;opacity:0!important;outline:none!important;padding:0!important;position:absolute!important;inset:0!important;transform:none!important;-webkit-appearance:none!important;z-index:-1!important}:host([hidden]){display:none}[hidden]{display:none}::placeholder{font-weight:var(--calcite-font-weight-normal);color:var(--calcite-input-placeholder-text-color, var(--calcite-color-text-3))}`; class InputText extends LitElement { constructor() { super(); this.actionWrapperEl = createRef(); this.attributeWatch = useWatchAttributes(["autofocus", "enterkeyhint", "inputmode", "spellcheck"], this.handleGlobalAttributesChanged); this.inputWrapperEl = createRef(); this.onHiddenFormInputInput = (event) => { if (event.target.name === this.name) { this.setValue({ value: event.target.value, origin: "direct" }); } this.setFocus(); event.stopPropagation(); }; this.previousValueOrigin = "initial"; this.userChangedValue = false; this._value = ""; this.messages = useT9n(); this.slottedActionElDisabledInternally = false; this.alignment = "start"; this.clearable = false; this.disabled = false; this.editingEnabled = false; this.iconFlipRtl = false; this.loading = false; this.readOnly = false; this.required = false; this.scale = "m"; this.status = "idle"; this.validity = { valid: false, badInput: false, customError: false, patternMismatch: false, rangeOverflow: false, rangeUnderflow: false, stepMismatch: false, tooLong: false, tooShort: false, typeMismatch: false, valueMissing: false }; this.calciteInputTextChange = createEvent(); this.calciteInputTextInput = createEvent(); this.calciteInternalInputTextBlur = createEvent(); this.calciteInternalInputTextFocus = createEvent(); this.listen("click", this.clickHandler); this.listen("keydown", this.keyDownHandler); } static { this.properties = { slottedActionElDisabledInternally: [16, {}, { state: true }], alignment: [3, {}, { reflect: true }], autocomplete: [0, {}, { attribute: false }], clearable: [7, {}, { reflect: true, type: Boolean }], disabled: [7, {}, { reflect: true, type: Boolean }], editingEnabled: [7, {}, { reflect: true, type: Boolean }], form: [3, {}, { reflect: true }], icon: [3, { converter: stringOrBoolean }, { reflect: true }], iconFlipRtl: [7, {}, { reflect: true, type: Boolean }], label: 1, loading: [7, {}, { reflect: true, type: Boolean }], maxLength: [11, {}, { reflect: true, type: Number }], messageOverrides: [0, {}, { attribute: false }], minLength: [11, {}, { reflect: true, type: Number }], name: [3, {}, { reflect: true }], pattern: 1, placeholder: 1, prefixText: 1, readOnly: [7, {}, { reflect: true, type: Boolean }], required: [7, {}, { reflect: true, type: Boolean }], scale: [3, {}, { reflect: true }], status: [3, {}, { reflect: true }], suffixText: 1, validationIcon: [3, { converter: stringOrBoolean }, { reflect: true }], validationMessage: 1, validity: [0, {}, { attribute: false }], value: 1 }; } static { this.styles = styles; } get value() { return this._value; } set value(value) { const oldValue = this._value; if (value !== oldValue) { this._value = value; this.valueWatcher(value, oldValue); } } async selectText() { this.childEl?.select(); } async setFocus() { await componentFocusable(this); this.childEl?.focus(); } connectedCallback() { super.connectedCallback(); this.inlineEditableEl = this.el.closest("calcite-inline-editable"); if (this.inlineEditableEl) { this.editingEnabled = this.inlineEditableEl.editingEnabled || false; } connectLabel(this); connectForm(this); this.el.addEventListener(internalHiddenInputInputEvent, this.onHiddenFormInputInput); } async load() { this.requestedIcon = setRequestedIcon({}, this.icon, "text"); this.setPreviousEmittedValue(this.value); this.setPreviousValue(this.value); } willUpdate(changes) { if (changes.has("icon")) { this.requestedIcon = setRequestedIcon({}, this.icon, "text"); } } updated() { updateHostInteraction(this); } disconnectedCallback() { super.disconnectedCallback(); disconnectLabel(this); disconnectForm(this); this.el.removeEventListener(internalHiddenInputInputEvent, this.onHiddenFormInputInput); } get isClearable() { return this.clearable && this.value.length > 0; } handleGlobalAttributesChanged() { this.requestUpdate(); } valueWatcher(newValue, previousValue) { if (!this.userChangedValue) { this.setValue({ origin: "direct", previousValue, value: !newValue ? "" : newValue }); } this.userChangedValue = false; } keyDownHandler(event) { if (this.readOnly || this.disabled || event.defaultPrevented) { return; } if (this.isClearable && event.key === "Escape") { this.clearInputTextValue(event); event.preventDefault(); } if (event.key === "Enter") { if (submitForm(this)) { event.preventDefault(); } } } onLabelClick() { this.setFocus(); } clearInputTextValue(nativeEvent) { this.setValue({ committing: true, nativeEvent, origin: "user", value: "" }); } emitChangeIfUserModified() { if (this.previousValueOrigin === "user" && this.value !== this.previousEmittedValue) { this.calciteInputTextChange.emit(); this.setPreviousEmittedValue(this.value); } } inputTextBlurHandler() { this.calciteInternalInputTextBlur.emit({ element: this.childEl, value: this.value }); this.emitChangeIfUserModified(); } clickHandler(event) { if (this.disabled) { return; } const composedPath = event.composedPath(); if (!composedPath.includes(this.inputWrapperEl.value) || composedPath.includes(this.actionWrapperEl.value)) { return; } this.setFocus(); } inputTextFocusHandler() { this.calciteInternalInputTextFocus.emit({ element: this.childEl, value: this.value }); } inputTextInputHandler(nativeEvent) { if (this.disabled || this.readOnly) { return; } this.setValue({ nativeEvent, origin: "user", value: nativeEvent.target.value }); } inputTextKeyDownHandler(event) { if (this.disabled || this.readOnly) { return; } if (event.key === "Enter") { this.emitChangeIfUserModified(); } } syncHiddenFormInput(input) { syncHiddenFormInput("text", this, input); } setChildElRef(el) { this.childEl = el; } setInputValue(newInputValue) { if (!this.childEl) { return; } this.childEl.value = newInputValue; } setPreviousEmittedValue(value) { this.previousEmittedValue = value; } setPreviousValue(value) { this.previousValue = value; } setValue({ committing = false, nativeEvent, origin, previousValue, value }) { this.setPreviousValue(previousValue ?? this.value); this.previousValueOrigin = origin; this.userChangedValue = origin === "user" && value !== this.value; this.value = value; if (origin === "direct") { this.setInputValue(value); this.setPreviousEmittedValue(value); } if (nativeEvent) { const calciteInputTextInputEvent = this.calciteInputTextInput.emit(); if (calciteInputTextInputEvent.defaultPrevented) { this.value = this.previousValue; } else if (committing) { this.emitChangeIfUserModified(); } } } render() { const dir = getElementDir(this.el); const loader = html`<div class=${safeClassMap(CSS.loader)}><calcite-progress .label=${this.messages.loading} type=indeterminate></calcite-progress></div>`; const inputClearButton = html`<button .ariaLabel=${this.messages.clear} class=${safeClassMap(CSS.clearButton)} .disabled=${this.disabled || this.readOnly} @click=${this.clearInputTextValue} tabindex=-1 type=button><calcite-icon icon=x .scale=${getIconScale(this.scale)}></calcite-icon></button>`; const iconEl = html`<calcite-icon class=${safeClassMap(CSS.inputIcon)} .flipRtl=${this.iconFlipRtl} .icon=${this.requestedIcon} .scale=${getIconScale(this.scale)}></calcite-icon>`; const prefixText = html`<div class=${safeClassMap(CSS.prefix)}>${this.prefixText}</div>`; const suffixText = html`<div class=${safeClassMap(CSS.suffix)}>${this.suffixText}</div>`; const childEl = html`<input aria-errormessage=${IDS.validationMessage} .ariaInvalid=${this.status === "invalid"} .ariaLabel=${getLabelText(this)} autocomplete=${this.autocomplete ?? nothing} .autofocus=${this.el.autofocus} class=${safeClassMap({ [CSS.editingEnabled]: this.editingEnabled, [CSS.inlineChild]: !!this.inlineEditableEl })} value=${this.defaultValue ?? nothing} .disabled=${this.disabled ? true : null} enterkeyhint=${this.el.enterKeyHint ?? nothing} inputmode=${this.el.inputMode ?? nothing} maxlength=${this.maxLength ?? nothing} minlength=${this.minLength ?? nothing} name=${this.name ?? nothing} @blur=${this.inputTextBlurHandler} @focus=${this.inputTextFocusHandler} @input=${this.inputTextInputHandler} @keydown=${this.inputTextKeyDownHandler} pattern=${this.pattern ?? nothing} placeholder=${(this.placeholder || "") ?? nothing} .readOnly=${this.readOnly} .required=${this.required ? true : null} spellcheck=${this.el.spellcheck ?? nothing} tabindex=${(this.disabled || this.inlineEditableEl && !this.editingEnabled ? -1 : null) ?? nothing} type=text .value=${live(this.value ?? "")} ${ref(this.setChildElRef)}>`; return InteractiveContainer({ disabled: this.disabled, children: html`<div class=${safeClassMap({ [CSS.inputWrapper]: true, [CSS_UTILITY.rtl]: dir === "rtl" })} ${ref(this.inputWrapperEl)}>${this.prefixText ? prefixText : null}<div class=${safeClassMap(CSS.wrapper)}>${childEl}${this.isClearable ? inputClearButton : null}${this.requestedIcon ? iconEl : null}${this.loading ? loader : null}</div><div class=${safeClassMap(CSS.actionWrapper)} ${ref(this.actionWrapperEl)}><slot name=${SLOTS.action}></slot></div>${this.suffixText ? suffixText : null}${HiddenFormInputSlot({ component: this })}</div>${this.validationMessage && this.status === "invalid" ? Validation({ icon: this.validationIcon, id: IDS.validationMessage, message: this.validationMessage, scale: this.scale, status: this.status }) : null}` }); } } customElement("calcite-input-text", InputText); export { InputText };