UNPKG

@esri/calcite-components

Version:

Web Components for Esri's Calcite Design System.

143 lines (142 loc) • 14.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 { ref } from "lit/directives/ref.js"; import { LitElement, createEvent, safeClassMap, nothing } from "@arcgis/lumina"; import { s as slotChangeHasAssignedElement } from "../../chunks/dom.js"; import { u as useSetFocus } from "../../chunks/useSetFocus.js"; import { u as useInteractive } from "../../chunks/useInteractive.js"; import { H as Heading } from "../../chunks/Heading.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", 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 ::slotted(calcite-chip){--calcite-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:hover .icon,.container.interactive:focus .icon,.container.interactive.selected .icon{color:var(--calcite-tile-heading-text-color, var(--calcite-color-text-1))}.container.interactive:hover ::slotted(calcite-chip),.container.interactive:focus ::slotted(calcite-chip),.container.interactive.selected ::slotted(calcite-chip){--calcite-icon-color: var(--calcite-tile-text-color, var(--calcite-color-text-1))}.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{margin:0;padding:0;color:var(--calcite-tile-heading-text-color, var(--calcite-color-text-1));font-weight:var(--calcite-font-weight-medium);line-height:1.20313rem;overflow-wrap:break-word}.description{color:var(--calcite-tile-text-color, var(--calcite-color-text-2));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-container{justify-content:center}:host([alignment=center]) .text-content{text-align:center}:host([alignment=center]) slot[name=content-bottom]::slotted(*),:host([alignment=center]) slot[name=content-top]::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=highlight]) .container.selected{background-color:var(--calcite-color-surface-highlight)}: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.focusSetter = useSetFocus()(this); this.interactiveContainer = useInteractive(this); this.hasContentBottom = 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 }], 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 }], headingLevel: [11, {}, { type: Number, reflect: true }], href: [3, {}, { reflect: true }], icon: [3, { type: String }, { 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(options) { return this.focusSetter(() => this.interactive ? this.containerEl : void 0, options); } 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, hasContentTop, heading, headingLevel, 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 || 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 })}><div class=${safeClassMap(CSS.textContent)}>${heading && Heading({ class: CSS.heading, level: headingLevel, children: heading }) || ""}${description && html`<div class=${safeClassMap(CSS.description)}>${description}</div>` || ""}</div></div><slot name=${SLOTS.contentBottom} @slotchange=${this.handleSlotChange}></slot></div></div>`; } render() { const { disabled } = this; return this.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 };