@esri/calcite-components
Version:
Web Components for Esri's Calcite Design System.
184 lines (183 loc) • 9.56 kB
JavaScript
/* COPYRIGHT Esri - https://js.arcgis.com/5.0/LICENSE.txt */
import { c as customElement } from "../../chunks/runtime.js";
import { css, html } from "lit";
import { createRef, ref } from "lit/directives/ref.js";
import { LitElement, createEvent, safeClassMap, nothing } from "@arcgis/lumina";
import { c as connectLabel, d as disconnectLabel, g as getLabelText } from "../../chunks/label.js";
import { b as slotChangeGetAssignedElements } from "../../chunks/dom.js";
import { u as useT9n } from "../../chunks/useT9n.js";
import { u as useSetFocus } from "../../chunks/useSetFocus.js";
import { u as useInteractive } from "../../chunks/useInteractive.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--hidden{pointer-events:none;opacity:0;inline-size:0}.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-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",
enableEditingButtonHidden: "enable-editing-button--hidden",
controlsWrapper: "controls-wrapper"
};
const ICONS = {
check: "check",
close: "x",
pencil: "pencil"
};
class InlineEditable extends LitElement {
constructor() {
super();
this.cancelEditingButtonRef = createRef();
this._editingEnabled = false;
this.enableEditingButtonRef = createRef();
this.messages = useT9n();
this.focusSetter = useSetFocus()(this);
this.interactiveContainer = useInteractive(this);
this.controls = false;
this.disabled = false;
this.loading = false;
this.scale = "m";
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 shouldShowControls() {
return this.editingEnabled && this.controls;
}
get editingEnabled() {
return this._editingEnabled;
}
set editingEnabled(editingEnabled) {
const oldEditingEnabled = this._editingEnabled;
if (editingEnabled !== oldEditingEnabled) {
this._editingEnabled = editingEnabled;
this.editingEnabledWatcher(editingEnabled, oldEditingEnabled);
}
}
async setFocus(options) {
return this.focusSetter(() => this.inputEl, options);
}
connectedCallback() {
super.connectedCallback();
connectLabel(this);
}
disconnectedCallback() {
super.disconnectedCallback();
disconnectLabel(this);
}
editingEnabledWatcher(newValue, oldValue) {
if (this.inputEl) {
this.inputEl.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.inputEl = inputElement;
if (!inputElement) {
return;
}
await inputElement.componentOnReady();
inputElement.editingEnabled = this.editingEnabled;
inputElement.label = inputElement.label || getLabelText(this);
}
onLabelClick() {
this.setFocus();
}
enableEditing() {
this.valuePriorToEditing = this.inputEl?.value;
this.editingEnabled = true;
this.inputEl?.setFocus();
this.calciteInternalInlineEditableEnableEditingChange.emit();
}
disableEditing() {
this.editingEnabled = false;
}
cancelEditing() {
if (this.inputEl) {
this.inputEl.value = this.valuePriorToEditing;
}
this.disableEditing();
this.enableEditingButtonRef.value?.setFocus();
if (!this.editingEnabled && !!this.shouldEmitCancel) {
this.calciteInlineEditableEditCancel.emit();
}
}
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.inputEl) {
event.preventDefault();
this.cancelEditingButtonRef.value.setFocus();
}
if (!!event.shiftKey && event.target === this.cancelEditingButtonRef.value) {
event.preventDefault();
this.inputEl?.setFocus();
}
}
}
async cancelEditingHandler(event) {
event.preventDefault();
this.cancelEditing();
}
enableEditingHandler(event) {
if (this.disabled || event.target !== this.enableEditingButtonRef.value && event.target !== this.inputEl) {
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.enableEditingButtonRef.value?.setFocus();
}
} catch {
} finally {
this.loading = false;
}
}
render() {
return this.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]: true,
[CSS.enableEditingButtonHidden]: this.editingEnabled
})} .iconStart=${ICONS.pencil} kind=neutral .label=${this.messages.enableEditing} @click=${this.enableEditingHandler} .scale=${this.scale} title=${this.messages.enableEditing ?? nothing} type=button ${ref(this.enableEditingButtonRef)}></calcite-button>${this.shouldShowControls && [
html`<div class=${safeClassMap(CSS.cancelEditingButtonWrapper)}><calcite-button appearance=transparent class=${safeClassMap(CSS.cancelEditingButton)} .iconStart=${ICONS.close} kind=neutral .label=${this.messages.cancelEditing} @click=${this.cancelEditingHandler} .scale=${this.scale} title=${this.messages.cancelEditing ?? nothing} type=button ${ref(this.cancelEditingButtonRef)}></calcite-button></div>`,
html`<calcite-button appearance=solid class=${safeClassMap(CSS.confirmChangesButton)} .iconStart=${ICONS.check} kind=brand .label=${this.messages.confirmChanges} .loading=${this.loading} @click=${this.confirmChangesHandler} .scale=${this.scale} title=${this.messages.confirmChanges ?? nothing} type=button></calcite-button>`
] || ""}</div></div>` });
}
}
customElement("calcite-inline-editable", InlineEditable);
export {
InlineEditable
};