UNPKG

@esri/calcite-components

Version:

Web Components for Esri's Calcite Design System.

121 lines (120 loc) • 15.2 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 { keyed } from "lit/directives/keyed.js"; import { createRef, ref } from "lit/directives/ref.js"; import { LitElement, safeClassMap, nothing } from "@arcgis/lumina"; import { g as guid } from "../../chunks/guid.js"; import { c as createObserver } from "../../chunks/observers.js"; import { g as getIconScale } from "../../chunks/component.js"; import { u as useT9n } from "../../chunks/useT9n.js"; import { u as useSetFocus } from "../../chunks/useSetFocus.js"; import { f as findAssociatedForm, s as submitForm, r as resetForm } from "../../chunks/form.js"; import { u as useInteractive } from "../../chunks/useInteractive.js"; import { I as IDS, C as CSS } from "../../chunks/resources.js"; const styles = css`:host{box-sizing:border-box;background-color:var(--calcite-color-foreground-1);color:var(--calcite-color-text-2);font-size:var(--calcite-font-size--1)}:host *{box-sizing:border-box}: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([scale=s]){--calcite-internal-action-font-size: var(--calcite-font-size--2);--calcite-internal-action-height: var(--calcite-size-sm);--calcite-internal-action-line-height: 1rem;--calcite-internal-action-spacing: var(--calcite-spacing-xxs)}:host([scale=m]){--calcite-internal-action-font-size: var(--calcite-font-size--1);--calcite-internal-action-height: var(--calcite-size-md);--calcite-internal-action-line-height: 1rem;--calcite-internal-action-spacing: var(--calcite-spacing-sm)}:host([scale=l]){--calcite-internal-action-font-size: var(--calcite-font-size-0);--calcite-internal-action-height: var(--calcite-size-lg);--calcite-internal-action-line-height: 1.25rem;--calcite-internal-action-spacing: var(--calcite-spacing-sm-plus)}:host{display:flex;cursor:pointer;background-color:transparent;--calcite-internal-action-text-color: var(--calcite-color-text-3);border-radius:var(--calcite-action-corner-radius, var(--calcite-action-corner-radius-start-start, var(--calcite-corner-radius-xs)) var(--calcite-action-corner-radius-start-end, var(--calcite-corner-radius-xs)) var(--calcite-action-corner-radius-end-end, var(--calcite-corner-radius-xs)) var(--calcite-action-corner-radius-end-start, var(--calcite-corner-radius-xs)))}.interaction-container{border-radius:inherit}:host([width=full]){flex:1 0 auto}:host([width=full]) .button{justify-content:center}:host([width=full]) .button .text-container--visible{flex:none}:host([drag-handle]){cursor:move;--calcite-internal-action-text-color: var(--calcite-color-border-input);--calcite-internal-action-padding-inline: var(--calcite-spacing-xxs)}.button{position:relative;margin:0;display:flex;inline-size:auto;align-items:center;justify-content:flex-start;border-style:none;outline-color:transparent;background-color:var(--calcite-action-background-color, var(--calcite-color-foreground-1));border-radius:inherit;color:var(--calcite-action-text-color, var(--calcite-internal-action-text-color));cursor:inherit;flex:1 0 auto;font-family:inherit;font-size:var(--calcite-internal-action-font-size);font-weight:var(--calcite-font-weight-normal);line-height:var(--calcite-internal-action-line-height);min-block-size:var(--calcite-internal-action-height);padding-block:var(--calcite-internal-action-padding-block, var(--calcite-internal-action-spacing));padding-inline:var(--calcite-internal-action-padding-inline, var(--calcite-internal-action-spacing));text-align:start}.button:hover{background-color:var(--calcite-action-background-color-hover, var(--calcite-color-foreground-2));color:var(--calcite-action-text-color-press, var(--calcite-action-text-color-pressed, var(--calcite-color-text-1)))}.button:focus{outline:var(--calcite-border-width-md) solid var(--calcite-color-focus, var(--calcite-ui-focus-color, var(--calcite-color-brand)));outline-offset:calc(calc(-1 * var(--calcite-spacing-base)) * calc(1 - (2*clamp(0,var(--calcite-offset-invert-focus),1))))}.button:active{background-color:var(--calcite-action-background-color-press, var(--calcite-action-background-color-pressed, var(--calcite-color-foreground-3)))}.button--text-visible{gap:var(--calcite-internal-action-spacing);inline-size:100%}.icon-container{pointer-events:none;margin:0;display:flex;align-items:center;justify-content:center}.text-container{margin:0;inline-size:0px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;opacity:0;transition-property:opacity;transition-duration:var(--calcite-animation-timing);transition-timing-function:cubic-bezier(.4,0,.2,1);transition-property:inline-size}.text-container--visible{inline-size:auto;flex:1 1 auto;opacity:1}:host([active]) .button{background-color:var(--calcite-action-background-color, var(--calcite-color-foreground-3));color:var(--calcite-action-text-color-press, var(--calcite-action-text-color-pressed, var(--calcite-color-text-1)))}:host([active]) .button:hover{background-color:var(--calcite-action-background-color-hover, var(--calcite-color-foreground-3))}:host([active]) .button:active{background-color:var(--calcite-action-background-color-press, var(--calcite-action-background-color-pressed, var(--calcite-color-foreground-3)))}:host([loading]) .button:hover,:host([loading]) .button:focus{background-color:var(--calcite-action-background-color, var(--calcite-color-foreground-1))}:host([loading]) calcite-loader[inline]{margin-inline-end:0px}:host([appearance=transparent]):host([active]) .button{background-color:var(--calcite-action-background-color-press, var(--calcite-action-background-color-pressed, var(--calcite-color-transparent-press)))}:host([appearance=transparent]) .button{transition-property:box-shadow;transition-duration:var(--calcite-animation-timing);transition-timing-function:cubic-bezier(.4,0,.2,1);background-color:var(--calcite-action-background-color, var(--calcite-color-transparent))}:host([appearance=transparent]) .button:hover{background-color:var(--calcite-action-background-color-hover, var(--calcite-color-transparent-hover))}:host([appearance=transparent]) .button:active{background-color:var(--calcite-action-background-color-press, var(--calcite-action-background-color-pressed, var(--calcite-color-transparent-press)))}:host([selection-appearance=highlight]):host([active]) .button{background-color:var(--calcite-color-surface-highlight);color:var(--calcite-color-text-highlight)}:host([active-descendant]) .button{outline:var(--calcite-border-width-md) solid var(--calcite-color-focus, var(--calcite-ui-focus-color, var(--calcite-color-brand)));outline-offset:calc(calc(-1 * var(--calcite-spacing-base)) * calc(1 - (2*clamp(0,var(--calcite-offset-invert-focus),1))))}:host([alignment=center]) .button{justify-content:center}:host([alignment=end]) .button{justify-content:flex-end}:host([alignment=center]) .button .text-container--visible,:host([alignment=end]) .button .text-container--visible{flex:0 1 auto}:host([scale=s][compact]) .button,:host([scale=m][compact]) .button,:host([scale=l][compact]) .button{padding-inline:0px}.slot-container{display:flex}.slot-container--hidden{display:none}.indicator-with-icon{position:relative}.indicator-with-icon:after{content:"";position:absolute;block-size:.5rem;inline-size:.5rem;border-radius:9999px;inset-block-end:-.275rem;inset-inline-end:-.275rem;background-color:var(--calcite-action-indicator-color, var(--calcite-color-brand))}.indicator-without-icon{margin-inline:.25rem;inline-size:1rem;position:relative}.indicator-without-icon:after{content:"";position:absolute;block-size:.5rem;inline-size:.5rem;border-radius:9999px;inset-block-end:-.275rem;inset-inline-end:-.275rem;background-color:var(--calcite-action-indicator-color, var(--calcite-color-brand))}:host([scale=s]) .indicator-with-icon{position:relative}:host([scale=s]) .indicator-with-icon:after{content:"";position:absolute;block-size:.5rem;inline-size:.5rem;border-radius:9999px;inset-block-end:-.125rem;inset-inline-end:-.125rem;background-color:var(--calcite-action-indicator-color, var(--calcite-color-brand));block-size:.375rem;inline-size:.375rem}:host([scale=s]) .indicator-without-icon{position:relative}:host([scale=s]) .indicator-without-icon:after{content:"";position:absolute;block-size:.5rem;inline-size:.5rem;border-radius:9999px;inset-block-end:-.175rem;inset-inline-end:-.175rem;background-color:var(--calcite-action-indicator-color, var(--calcite-color-brand));block-size:.375rem;inline-size:.375rem}.indicator-text{position:absolute;inline-size:1px;block-size:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}:host([hidden]){display:none}[hidden]{display:none}:host([disabled]) ::slotted([calcite-hydrated][disabled]),:host([disabled]) [calcite-hydrated][disabled]{opacity:1}.interaction-container{display:contents}`; class Action extends LitElement { constructor() { super(...arguments); this.guid = guid(); this.buttonRef = createRef(); this.buttonId = IDS.button(this.guid); this.mutationObserver = createObserver("mutation", () => this.requestUpdate()); this.messages = useT9n({ blocking: true }); this.focusSetter = useSetFocus()(this); this.indicatorRef = createRef(); this.interactiveContainer = useInteractive(this); this.active = false; this.activeDescendant = false; this.appearance = "transparent"; this.compact = false; this.disabled = false; this.dragHandle = false; this.iconFlipRtl = false; this.indicator = false; this.loading = false; this.scale = "m"; this.width = "auto"; this.textEnabled = false; this.type = "button"; } static { this.properties = { aria: [0, {}, { attribute: false }], active: [7, {}, { reflect: true, type: Boolean }], activeDescendant: [7, {}, { reflect: true, type: Boolean }], alignment: [3, {}, { reflect: true }], appearance: [3, {}, { reflect: true }], compact: [7, {}, { reflect: true, type: Boolean }], disabled: [7, {}, { reflect: true, type: Boolean }], dragHandle: [7, {}, { reflect: true, type: Boolean }], form: [3, {}, { reflect: true }], icon: [3, { type: String }, { reflect: true }], iconFlipRtl: [7, {}, { reflect: true, type: Boolean }], indicator: [7, {}, { reflect: true, type: Boolean }], label: 1, loading: [7, {}, { reflect: true, type: Boolean }], messageOverrides: [0, {}, { attribute: false }], scale: [3, {}, { reflect: true }], width: [3, {}, { reflect: true }], text: 1, textEnabled: [7, {}, { reflect: true, type: Boolean }], type: [3, {}, { reflect: true }], selectionAppearance: [3, {}, { reflect: true }] }; } static { this.styles = styles; } async setFocus(options) { return this.focusSetter(() => this.buttonRef.value, options); } connectedCallback() { super.connectedCallback(); this.formEl = findAssociatedForm(this); this.mutationObserver?.observe(this.el, { childList: true, subtree: true }); } disconnectedCallback() { super.disconnectedCallback(); this.formEl = null; this.mutationObserver?.disconnect(); } handleClick() { const { type } = this; if (type === "submit") { submitForm(this); } else if (type === "reset") { resetForm(this); } } renderTextContainer() { const { text, textEnabled } = this; const textContainerClasses = { [CSS.textContainer]: true, [CSS.textContainerVisible]: textEnabled }; return text ? keyed("text-container", html`<div class=${safeClassMap(textContainerClasses)}>${text}</div>`) : null; } renderIndicatorText() { const { indicator, messages, buttonId } = this; return html`<div aria-labelledby=${buttonId ?? nothing} aria-live=polite class=${safeClassMap(CSS.indicatorText)} role=region ${ref(this.indicatorRef)}>${indicator ? messages.indicator : null}</div>`; } renderIconContainer() { const { loading, icon, scale, el, iconFlipRtl, indicator } = this; const loaderScale = scale === "l" ? "l" : "m"; const calciteLoaderNode = loading ? html`<calcite-loader inline .label=${this.messages.loading} .scale=${loaderScale}></calcite-loader>` : null; const calciteIconNode = icon ? html`<calcite-icon class=${safeClassMap({ [CSS.indicatorWithIcon]: indicator })} .flipRtl=${iconFlipRtl} .icon=${icon} .scale=${getIconScale(this.scale)}></calcite-icon>` : null; const iconNode = calciteLoaderNode || calciteIconNode; const hasIconToDisplay = iconNode || el.children?.length; const slotContainerNode = html`<div class=${safeClassMap({ [CSS.slotContainer]: true, [CSS.slotContainerHidden]: loading })}><slot></slot></div>`; return hasIconToDisplay ? keyed("icon-container", html`<div aria-hidden=true class=${safeClassMap(CSS.iconContainer)}>${iconNode}${slotContainerNode}</div>`) : null; } renderButton() { const { compact, disabled, icon, loading, textEnabled, label, text, indicator, indicatorRef, buttonId, messages } = this; const labelFallback = label || text || ""; const ariaLabel = indicator ? messages.indicatorLabel.replace("{label}", labelFallback) : labelFallback; const buttonClasses = { [CSS.button]: true, [CSS.buttonTextVisible]: textEnabled, [CSS.buttonCompact]: compact }; const buttonContent = html`${this.renderIconContainer()}${this.renderTextContainer()}${!icon && indicator && keyed("indicator-no-icon", html`<div class=${safeClassMap(CSS.indicatorWithoutIcon)}></div>`) || ""}`; const internalControlsElements = indicator && indicatorRef.value ? [indicatorRef.value] : []; const ariaControlsElements = [ ...this.aria?.controlsElements ?? [], ...internalControlsElements ]; if (this.dragHandle) { return html`<span .ariaBusy=${loading} .ariaControlsElements=${ariaControlsElements} .ariaDescribedByElements=${this.aria?.describedByElements} .ariaExpanded=${this.aria?.expanded} .ariaHasPopup=${this.aria?.hasPopup} .ariaLabel=${ariaLabel} .ariaLabelledByElements=${this.aria?.labelledByElements} .ariaOwnsElements=${this.aria?.ownsElements} .ariaPressed=${this.aria?.pressed} class=${safeClassMap(buttonClasses)} id=${buttonId ?? nothing} role=button tabindex=${(this.disabled ? null : 0) ?? nothing} ${ref(this.buttonRef)}>${buttonContent}</span>`; } return html`<button .ariaBusy=${loading} .ariaChecked=${this.aria?.checked} .ariaControlsElements=${ariaControlsElements} .ariaDescribedByElements=${this.aria?.describedByElements} .ariaExpanded=${this.aria?.expanded} .ariaHasPopup=${this.aria?.hasPopup} .ariaLabel=${ariaLabel} .ariaLabelledByElements=${this.aria?.labelledByElements} .ariaOwnsElements=${this.aria?.ownsElements} .ariaPressed=${this.aria?.pressed} class=${safeClassMap(buttonClasses)} .disabled=${disabled} id=${buttonId ?? nothing} @click=${this.handleClick} .role=${this.aria?.role} ${ref(this.buttonRef)}>${buttonContent}</button>`; } render() { return this.interactiveContainer({ disabled: this.disabled, children: html`${this.renderButton()}${this.renderIndicatorText()}` }); } } customElement("calcite-action", Action); export { Action };