UNPKG

@esri/calcite-components

Version:

Web Components for Esri's Calcite Design System.

184 lines (183 loc) • 9.56 kB
/* 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 };