UNPKG

@esri/calcite-components

Version:

Web Components for Esri's Calcite Design System.

195 lines (194 loc) • 10.2 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 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 };