UNPKG

@esri/calcite-components

Version:

Web Components for Esri's Calcite Design System.

153 lines (152 loc) • 13.8 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 { html } from "lit-html"; import { ref } from "lit-html/directives/ref.js"; import { LitElement, createEvent, safeClassMap, nothing } from "@arcgis/lumina"; import { u as updateHostInteraction, I as InteractiveContainer } from "../../chunks/interactive.js"; import { a as slotChangeHasAssignedElement } from "../../chunks/dom.js"; import { c as componentFocusable } from "../../chunks/component.js"; import { css } from "@lit/reactive-element/css-tag.js"; const CSS = { container: "container", contentContainer: "content-container", contentContainerHasContent: "content-container--has-content", contentContainerHasOnlyContentTopAndBottom: "content-container--has-only-content-top-and-bottom", textContentContainer: "text-content-container", description: "description", heading: "heading", icon: "icon", interactive: "interactive", largeVisualDeprecated: "large-visual-deprecated", row: "row", selected: "selected", selectionIcon: "selection-icon", textContent: "text-content" }; const ICONS = { selectedMultiple: "check-square-f", selectedSingle: "circle-f", unselectedMultiple: "square", unselectedSingle: "circle" }; const SLOTS = { contentBottom: "content-bottom", contentEnd: "content-end", contentStart: "content-start", contentTop: "content-top" }; 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{box-shadow:var(--calcite-tile-shadow, var(--calcite-shadow-none));box-sizing:border-box;display:inline-block}calcite-link{--calcite-link-text-color: var(--calcite-tile-link-text-color)}.container{background-color:var(--calcite-tile-background-color, var(--calcite-color-foreground-1));block-size:var(--calcite-container-size-content-fluid);border-radius:var(--calcite-tile-corner-radius, var(--calcite-corner-radius));box-sizing:border-box;color:var(--calcite-tile-text-color, var(--calcite-color-text-3));inline-size:var(--calcite-container-size-content-fluid);outline:var(--calcite-border-width-sm, 1px) solid var(--calcite-tile-border-color, var(--calcite-color-border-2));padding:var(--calcite-internal-tile-spacing);position:relative;-webkit-user-select:none;user-select:none}.container .selection-icon{color:var(--calcite-tile-text-color, var(--calcite-color-text-3))}.container.interactive{cursor:pointer}.container.interactive:hover,.container.interactive:focus,.container.interactive.selected{outline-color:var(--calcite-tile-accent-color-press, var(--calcite-color-brand));z-index:var(--calcite-z-index)}.container.interactive:hover .selection-icon,.container.interactive:focus .selection-icon,.container.interactive.selected .selection-icon{color:var(--calcite-tile-accent-color-press, var(--calcite-color-brand))}.container.interactive:focus{box-shadow:inset 0 0 0 1px var(--calcite-tile-accent-color-press, var(--calcite-color-brand));z-index:calc(var(--calcite-z-index) + 1)}.content-container,.row{align-items:flex-start;display:flex}.content-container{flex-direction:column;word-wrap:break-word;word-break:break-word;inline-size:var(--calcite-container-size-content-fluid)}.text-content-container{inline-size:100%;outline-color:transparent;padding:0}.text-content{display:flex;flex-direction:column}.heading{color:var(--calcite-tile-heading-text-color, var(--calcite-color-text-2));font-weight:var(--calcite-font-weight-medium);line-height:1.20313rem;overflow-wrap:break-word}.description{font-weight:var(--calcite-font-weight-regular);overflow-wrap:break-word}.large-visual-deprecated{align-items:center;justify-content:center;min-block-size:12rem;text-align:center}.large-visual-deprecated .icon{align-self:center;block-size:64px;inline-size:64px}.large-visual-deprecated .selection-icon{position:absolute;inset-inline-start:var(--calcite-internal-tile-spacing);inset-block-start:var(--calcite-internal-tile-spacing);z-index:var(--calcite-z-index)}.large-visual-deprecated .text-content-container{justify-content:center}:host([alignment=center]) .icon{align-self:center}:host([alignment=center]) .text-content{text-align:center}:host([alignment=center]) slot[name=content-start]::slotted(*),:host([alignment=center]) slot[name=content-end]::slotted(*){align-self:center}:host([scale=s]){--calcite-internal-tile-spacing: var(--calcite-spacing-sm);max-inline-size:400px;min-inline-size:100px}:host([scale=s]) .heading{font-size:var(--calcite-font-size--2);line-height:1.03125rem}:host([scale=s]) .description{font-size:var(--calcite-font-size--3);line-height:.85938rem}:host([scale=m]){--calcite-internal-tile-spacing: var(--calcite-spacing-md);max-inline-size:460px;min-inline-size:140px}:host([scale=m]) .heading{font-size:var(--calcite-font-size--1);line-height:1.20313rem}:host([scale=m]) .description{font-size:var(--calcite-font-size--2);line-height:1.03125rem}:host([scale=l]){--calcite-internal-tile-spacing: var(--calcite-spacing-lg);max-inline-size:520px;min-inline-size:160px}:host([scale=l]) .heading{font-size:var(--calcite-font-size-0);line-height:1.375rem}:host([scale=l]) .description{font-size:var(--calcite-font-size--1);line-height:1.20313rem}.content-container--has-content,.row{gap:var(--calcite-internal-tile-spacing)}.content-container--has-only-content-top-and-bottom slot[name=content-top]::slotted(*){margin-block-end:var(--calcite-internal-tile-spacing)}:host([selection-appearance=border][layout=horizontal]) .container.selected:focus:before,:host([selection-appearance=border][layout=vertical]) .container.selected:focus:before{block-size:100%;box-shadow:inset 0 0 0 1px var(--calcite-tile-accent-color-press, var(--calcite-color-brand));content:"";display:block;inline-size:100%;inset-block-start:0;inset-inline-start:0;position:absolute}:host([selection-appearance=border][layout=horizontal]) .container.selected{box-shadow:inset 0 -4px 0 0 var(--calcite-tile-accent-color-press, var(--calcite-color-brand))}:host([selection-appearance=border][layout=vertical]) .container.selected{box-shadow:inset 4px 0 0 0 var(--calcite-tile-accent-color-press, var(--calcite-color-brand))}:host(:hover:not([disabled])) .heading,:host([active]:not([disabled])) .heading{color:var(--calcite-tile-heading-text-color, var(--calcite-color-text-1))}:host(:hover:not([disabled])) .description,:host([active]:not([disabled])) .description{color:var(--calcite-tile-text-color, var(--calcite-color-text-2))}:host([href]:focus:not([disabled])) .container,:host([href]:hover:not([disabled])) .container{outline-color:var(--calcite-tile-link-color, var(--calcite-color-text-link));z-index:var(--calcite-z-index)}:host([href]:focus:not([disabled])) .icon,:host([href]:hover:not([disabled])) .icon{color:var(--calcite-tile-link-color, var(--calcite-color-text-link))}:host([href]:focus:not([disabled])) .heading,:host([href]:hover:not([disabled])) .heading{color:var(--calcite-tile-link-color, var(--calcite-color-text-link))}:host([href]:active:not([disabled])) .container{box-shadow:inset 0 0 0 1px var(--calcite-tile-link-color, var(--calcite-color-text-link));outline-color:var(--calcite-tile-link-color, var(--calcite-color-text-link))}:host([embed]) .container{padding:0}:host([selection-mode=none]) .container:hover,:host([selection-mode=none]) .container.selected{outline-color:var(--calcite-tile-border-color, var(--calcite-color-border-2))}:host([selection-mode=none]) .container:focus{outline-color:var(--calcite-tile-accent-color-press, var(--calcite-color-brand))}:host([disabled]) ::slotted([calcite-hydrated][disabled]),:host([disabled]) [calcite-hydrated][disabled]{opacity:1}.interaction-container{display:contents}:host([hidden]){display:none}[hidden]{display:none}::slotted(*){max-inline-size:100%}`; class Tile extends LitElement { constructor() { super(); this.hasContentBottom = false; this.hasContentEnd = false; this.hasContentStart = false; this.hasContentTop = false; this.active = false; this.alignment = "start"; this.disabled = false; this.embed = false; this.iconFlipRtl = false; this.interactive = false; this.layout = "horizontal"; this.scale = "m"; this.selected = false; this.selectionAppearance = "icon"; this.selectionMode = "none"; this.calciteInternalTileKeyEvent = createEvent({ cancelable: false }); this.calciteTileSelect = createEvent(); this.listen("keydown", this.keyDownHandler); } static { this.properties = { hasContentBottom: [16, {}, { state: true }], hasContentEnd: [16, {}, { state: true }], hasContentStart: [16, {}, { state: true }], hasContentTop: [16, {}, { state: true }], active: [7, {}, { reflect: true, type: Boolean }], alignment: [3, {}, { reflect: true }], description: [3, {}, { reflect: true }], disabled: [7, {}, { reflect: true, type: Boolean }], embed: [7, {}, { reflect: true, type: Boolean }], heading: [3, {}, { reflect: true }], href: [3, {}, { reflect: true }], icon: [3, {}, { reflect: true }], iconFlipRtl: [7, {}, { reflect: true, type: Boolean }], interactive: [5, {}, { type: Boolean }], label: 1, layout: [3, {}, { reflect: true }], scale: [3, {}, { reflect: true }], selected: [7, {}, { reflect: true, type: Boolean }], selectionAppearance: [3, {}, { reflect: true }], selectionMode: [3, {}, { reflect: true }] }; } static { this.styles = styles; } async setFocus() { await componentFocusable(this); if (!this.disabled && this.interactive) { this.containerEl?.focus(); } } updated() { updateHostInteraction(this); } clickHandler() { if (this.interactive) { this.setFocus(); this.handleSelectEvent(); } } handleSelectEvent() { if (this.disabled || !this.interactive || this.selectionMode === "single-persist" && this.selected === true) { return; } this.calciteTileSelect.emit(); } handleSlotChange(event) { const slotName = event.target.dataset.name; this[`has${slotName}`] = slotChangeHasAssignedElement(event); } setContainerEl(el) { this.containerEl = el; } keyDownHandler(event) { if (event.target === this.el) { switch (event.key) { case " ": case "Enter": this.handleSelectEvent(); event.preventDefault(); break; case "ArrowDown": case "ArrowLeft": case "ArrowRight": case "ArrowUp": case "Home": case "End": this.calciteInternalTileKeyEvent.emit(event); event.preventDefault(); break; } } } renderSelectionIcon() { const { selected, selectionAppearance, selectionMode } = this; if (selectionAppearance === "icon" && selectionMode !== "none") { return html`<calcite-icon class=${safeClassMap(CSS.selectionIcon)} .icon=${selected ? selectionMode === "multiple" ? ICONS.selectedMultiple : ICONS.selectedSingle : selectionMode === "multiple" ? ICONS.unselectedMultiple : ICONS.unselectedSingle} scale=s></calcite-icon>`; } return; } renderTile() { const { description, disabled, hasContentBottom, hasContentEnd, hasContentStart, hasContentTop, heading, icon, iconFlipRtl, interactive, selectionMode } = this; const isLargeVisual = heading && icon && !description; const disableInteraction = Boolean(this.href) || !interactive; const role = selectionMode === "multiple" && interactive ? "checkbox" : selectionMode !== "none" && interactive ? "radio" : interactive ? "button" : void 0; const hasContent = !!(description || hasContentEnd || hasContentStart || heading || icon); const hasOnlyContentTopAndBottom = !hasContent && hasContentTop && hasContentBottom; return html`<div .ariaChecked=${selectionMode !== "none" && interactive ? this.selected : void 0} .ariaDisabled=${disableInteraction ? disabled : void 0} .ariaLabel=${role && this.label} class=${safeClassMap({ [CSS.container]: true, [CSS.interactive]: interactive, // [Deprecated] Use the content-top slot for rendering icon with alignment="center" instead [CSS.largeVisualDeprecated]: isLargeVisual, [CSS.row]: true, [CSS.selected]: this.selected })} @click=${this.clickHandler} .role=${role} tabindex=${(disableInteraction ? void 0 : 0) ?? nothing} ${ref(this.setContainerEl)}>${this.renderSelectionIcon()}<div class=${safeClassMap({ [CSS.contentContainer]: true, [CSS.contentContainerHasContent]: hasContent, [CSS.contentContainerHasOnlyContentTopAndBottom]: hasOnlyContentTopAndBottom })}><slot name=${SLOTS.contentTop} @slotchange=${this.handleSlotChange}></slot>${icon && html`<calcite-icon class=${safeClassMap(CSS.icon)} .flipRtl=${iconFlipRtl} .icon=${icon} scale=l></calcite-icon>` || ""}<div class=${safeClassMap({ [CSS.textContentContainer]: true, [CSS.row]: true })}><slot name=${SLOTS.contentStart} @slotchange=${this.handleSlotChange}></slot><div class=${safeClassMap(CSS.textContent)}>${heading && html`<div class=${safeClassMap(CSS.heading)}>${heading}</div>` || ""}${description && html`<div class=${safeClassMap(CSS.description)}>${description}</div>` || ""}</div><slot name=${SLOTS.contentEnd} @slotchange=${this.handleSlotChange}></slot></div><slot name=${SLOTS.contentBottom} @slotchange=${this.handleSlotChange}></slot></div></div>`; } render() { const { disabled } = this; return InteractiveContainer({ disabled, children: this.href ? html`<calcite-link .disabled=${disabled} .href=${this.href}>${this.renderTile()}</calcite-link>` : this.renderTile() }); } } customElement("calcite-tile", Tile); export { Tile };