@esri/calcite-components
Version:
Web Components for Esri's Calcite Design System.
195 lines (194 loc) • 10.2 kB
JavaScript
/*! 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 customElement } from "../../chunks/runtime.js";
import { nothing, html } from "lit";
import { createRef, ref } from "lit-html/directives/ref.js";
import { LitElement, createEvent, safeClassMap, safeStyleMap } from "@arcgis/lumina";
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 } from "../../chunks/component.js";
import { s as slotChangeGetAssignedElements } from "../../chunks/dom.js";
import { u as useT9n } from "../../chunks/useT9n.js";
import { css } from "@lit/reactive-element/css-tag.js";
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]) .controls-wrapper{block-size:1.5rem}:host([scale=m]) .controls-wrapper{block-size:2rem}:host([scale=l]) .controls-wrapper{block-size:2.75rem}.wrapper{box-sizing:border-box;display:flex;justify-content:space-between;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;background-color:var(--calcite-inline-editable-background-color, var(--calcite-color-foreground-1))}.wrapper .input-wrapper{flex:1 1 0%}:host(:not([editing-enabled]):not([disabled])) .wrapper:hover{background-color:var(--calcite-inline-editable-background-color-hover, var(--calcite-color-foreground-2))}.controls-wrapper{display:flex}.cancel-editing-button[appearance=transparent][kind=neutral]{--calcite-internal-button-text-color: var(--calcite-color-text-3);--calcite-internal-button-border-block-start-color: var(--calcite-color-border-input);--calcite-internal-button-border-block-end-color: var(--calcite-color-border-input)}.cancel-editing-button[appearance=transparent][kind=neutral]:hover{--calcite-internal-button-text-color: var(--calcite-color-text-1)}.enable-editing-button[appearance=transparent][kind=neutral]{--calcite-internal-button-background-color: transparent}calcite-button{--calcite-button-background-color: var(--calcite-inline-editable-button-background-color);--calcite-button-corner-radius: var(--calcite-inline-editable-button-corner-radius);--calcite-button-loader-color: var(--calcite-inline-editable-button-loader-color);--calcite-button-shadow-color: var(--calcite-inline-editable-button-shadow-color);--calcite-button-text-color: var(--calcite-inline-editable-button-text-color)}:host([disabled]) ::slotted([calcite-hydrated][disabled]),:host([disabled]) [calcite-hydrated][disabled]{opacity:1}.interaction-container{display:contents}:host([hidden]){display:none}[hidden]{display:none}`;
const CSS = {
wrapper: "wrapper",
confirmChangesButton: "confirm-changes-button",
cancelEditingButton: "cancel-editing-button",
inputWrapper: "input-wrapper",
cancelEditingButtonWrapper: "cancel-editing-button-wrapper",
enableEditingButton: "enable-editing-button",
controlsWrapper: "controls-wrapper"
};
class InlineEditable extends LitElement {
constructor() {
super();
this.cancelEditingButton = createRef();
this.confirmEditingButton = createRef();
this._editingEnabled = false;
this.enableEditingButton = createRef();
this.messages = useT9n();
this.controls = false;
this.disabled = false;
this.loading = false;
this.calciteInlineEditableEditCancel = createEvent({ cancelable: false });
this.calciteInlineEditableEditConfirm = createEvent({ cancelable: false });
this.calciteInternalInlineEditableEnableEditingChange = createEvent({ cancelable: false });
this.listen("calciteInternalInputBlur", this.blurHandler);
}
static {
this.properties = { afterConfirm: [0, {}, { attribute: false }], controls: [7, {}, { reflect: true, type: Boolean }], disabled: [7, {}, { reflect: true, type: Boolean }], editingEnabled: [7, {}, { reflect: true, type: Boolean }], loading: [7, {}, { reflect: true, type: Boolean }], messageOverrides: [0, {}, { attribute: false }], scale: [3, {}, { reflect: true }] };
}
static {
this.shadowRootOptions = { mode: "open", delegatesFocus: true };
}
static {
this.styles = styles;
}
get editingEnabled() {
return this._editingEnabled;
}
set editingEnabled(editingEnabled) {
const oldEditingEnabled = this._editingEnabled;
if (editingEnabled !== oldEditingEnabled) {
this._editingEnabled = editingEnabled;
this.editingEnabledWatcher(editingEnabled, oldEditingEnabled);
}
}
async setFocus() {
await componentFocusable(this);
this.inputElement?.setFocus();
}
connectedCallback() {
super.connectedCallback();
connectLabel(this);
}
willUpdate(changes) {
if (changes.has("disabled") && (this.hasUpdated || this.disabled !== false)) {
this.disabledWatcher(this.disabled);
}
}
updated() {
updateHostInteraction(this);
}
disconnectedCallback() {
super.disconnectedCallback();
disconnectLabel(this);
}
get shouldShowControls() {
return this.editingEnabled && this.controls;
}
disabledWatcher(disabled) {
if (this.inputElement) {
this.inputElement.disabled = disabled;
}
}
editingEnabledWatcher(newValue, oldValue) {
if (this.inputElement) {
this.inputElement.editingEnabled = newValue;
}
if (!newValue && !!oldValue) {
this.shouldEmitCancel = true;
}
}
blurHandler() {
if (!this.controls) {
this.disableEditing();
}
}
async handleDefaultSlotChange(event) {
const inputElement = slotChangeGetAssignedElements(event).filter((el) => el.matches("calcite-input"))[0];
this.inputElement = inputElement;
if (!inputElement) {
return;
}
await inputElement.componentOnReady();
inputElement.editingEnabled = this.editingEnabled;
inputElement.disabled = this.disabled;
inputElement.label = inputElement.label || getLabelText(this);
this.scale = this.scale || this.inputElement?.scale || "m";
}
onLabelClick() {
this.setFocus();
}
enableEditing() {
this.valuePriorToEditing = this.inputElement?.value;
this.editingEnabled = true;
this.inputElement?.setFocus();
this.calciteInternalInlineEditableEnableEditingChange.emit();
}
disableEditing() {
this.editingEnabled = false;
}
cancelEditing() {
if (this.inputElement) {
this.inputElement.value = this.valuePriorToEditing;
}
this.disableEditing();
this.enableEditingButton.value?.setFocus();
if (!this.editingEnabled && !!this.shouldEmitCancel) {
this.calciteInlineEditableEditCancel.emit();
}
}
async escapeKeyHandler(event) {
if (event.defaultPrevented) {
return;
}
if (event.key === "Escape") {
event.preventDefault();
this.cancelEditing();
}
if (event.key === "Tab" && this.shouldShowControls) {
if (!event.shiftKey && event.target === this.inputElement) {
event.preventDefault();
this.cancelEditingButton.value.setFocus();
}
if (!!event.shiftKey && event.target === this.cancelEditingButton.value) {
event.preventDefault();
this.inputElement?.setFocus();
}
}
}
async cancelEditingHandler(event) {
event.preventDefault();
this.cancelEditing();
}
async enableEditingHandler(event) {
if (this.disabled || event.target !== this.enableEditingButton.value && event.target !== this.inputElement) {
return;
}
event.preventDefault();
if (!this.editingEnabled) {
this.enableEditing();
}
}
async confirmChangesHandler(event) {
event.preventDefault();
this.calciteInlineEditableEditConfirm.emit();
try {
if (this.afterConfirm) {
this.loading = true;
await this.afterConfirm();
this.disableEditing();
this.enableEditingButton.value.setFocus();
}
} catch {
} finally {
this.loading = false;
}
}
render() {
return InteractiveContainer({ disabled: this.disabled, children: html`<div class=${safeClassMap(CSS.wrapper)} @click=${this.enableEditingHandler} @keydown=${this.escapeKeyHandler}><div class=${safeClassMap(CSS.inputWrapper)}><slot @slotchange=${this.handleDefaultSlotChange}></slot></div><div class=${safeClassMap(CSS.controlsWrapper)}><calcite-button appearance=transparent class=${safeClassMap(CSS.enableEditingButton)} .disabled=${this.disabled} icon-start=pencil kind=neutral .label=${this.messages.enableEditing} @click=${this.enableEditingHandler} .scale=${this.scale} style=${safeStyleMap({
opacity: this.editingEnabled ? "0" : "1",
width: this.editingEnabled ? "0" : "inherit"
})} title=${this.messages.enableEditing ?? nothing} type=button ${ref(this.enableEditingButton)}></calcite-button>${this.shouldShowControls && [
html`<div class=${safeClassMap(CSS.cancelEditingButtonWrapper)}><calcite-button appearance=transparent class=${safeClassMap(CSS.cancelEditingButton)} .disabled=${this.disabled} icon-start=x kind=neutral .label=${this.messages.cancelEditing} @click=${this.cancelEditingHandler} .scale=${this.scale} title=${this.messages.cancelEditing ?? nothing} type=button ${ref(this.cancelEditingButton)}></calcite-button></div>`,
html`<calcite-button appearance=solid class=${safeClassMap(CSS.confirmChangesButton)} .disabled=${this.disabled} icon-start=check kind=brand .label=${this.messages.confirmChanges} .loading=${this.loading} @click=${this.confirmChangesHandler} .scale=${this.scale} title=${this.messages.confirmChanges ?? nothing} type=button ${ref(this.confirmEditingButton)}></calcite-button>`
] || ""}</div></div>` });
}
}
customElement("calcite-inline-editable", InlineEditable);
export {
InlineEditable
};