UNPKG

@esri/calcite-components

Version:

Web Components for Esri's Calcite Design System.

172 lines (171 loc) • 15.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 { html } from "lit-html"; import { createRef, ref } from "lit-html/directives/ref.js"; import { LitElement, createEvent, safeClassMap } from "@arcgis/lumina"; import { a as slotChangeHasAssignedElement } from "../../chunks/dom.js"; import { c as componentFocusable } from "../../chunks/component.js"; import { u as updateHostInteraction, I as InteractiveContainer } from "../../chunks/interactive.js"; import { i as isActivationKey } from "../../chunks/key.js"; import { u as useT9n } from "../../chunks/useT9n.js"; import { css } from "@lit/reactive-element/css-tag.js"; const CSS = { container: "container", contentWrapper: "content-wrapper", header: "header", footer: "footer", checkboxWrapper: "checkbox-wrapper", checkboxWrapperDeprecated: "checkbox-wrapper-deprecated", thumbnailWrapper: "thumbnail-wrapper", headerTextContainer: "header-text-container", cardContent: "card-content", hasSlottedContent: "has-slotted-content" }; const SLOTS = { thumbnail: "thumbnail", heading: "heading", description: "description", footerStart: "footer-start", footerEnd: "footer-end", title: "title", subtitle: "subtitle" }; const ICONS = { selected: "check-square-f", unselected: "square", selectedSingle: "circle-f", unselectedSingle: "circle" }; 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;max-inline-size:100%}.content-wrapper{position:relative;display:flex;block-size:100%;flex-direction:column;justify-content:space-between;overflow:hidden;border:var(--calcite-border-width-sm) solid var(--calcite-card-border-color, var(--calcite-color-border-3));border-radius:var(--calcite-card-corner-radius, var(--calcite-corner-radius-sharp));background-color:var(--calcite-card-background-color, var(--calcite-color-foreground-1));box-shadow:var(--calcite-card-shadow, var(--calcite-shadow-none));pointer-events:none}::slotted(*){pointer-events:auto}:host(:not([selectable])) .content-wrapper:not(.non-interactive){outline-color:transparent}:host(:not([selectable])) .content-wrapper:not(.non-interactive):focus{outline:2px solid var(--calcite-color-focus, var(--calcite-ui-focus-color, var(--calcite-color-brand)));outline-offset:calc(2px*(1 - (2*clamp(0,var(--calcite-offset-invert-focus),1))))}.container{position:relative;display:flex;flex:1 1 auto;flex-direction:column}:host([loading]) .content-wrapper *:not(calcite-loader):not(.calcite-card-loader-container){pointer-events:none;opacity:0}:host([loading]) .calcite-card-loader-container{position:absolute;inset:0;display:flex;align-items:center}.header{display:flex;flex-direction:row;align-items:flex-start}.footer{margin-block-start:auto;display:flex;flex-direction:row;align-content:space-between;justify-content:space-between;padding-inline:var(--calcite-spacing-md);padding-block-start:var(--calcite-spacing-xxs);padding-block-end:var(--calcite-spacing-md)}.header-text-container{display:flex;inline-size:100%;flex-direction:column;justify-content:center;padding-inline:.75rem;padding-block:.5rem}.header-text-container:not(:only-child){padding-inline-end:.125rem}.footer{margin-block-start:auto;flex-direction:row;align-content:space-between;justify-content:space-between;padding-inline:.75rem;padding-block:.25rem .75rem}.card-content{block-size:auto;font-size:var(--calcite-font-size--2);line-height:1.375}.has-slotted-content{padding:.75rem}:host([selected]) .content-wrapper{box-shadow:inset 0 -4px 0 0 var(--calcite-card-accent-color-selected, var(--calcite-color-brand))}:host([selectable]) .header{padding-inline-end:var(--calcite-spacing-xxxl)}slot[name=title]::slotted(*),*::slotted([slot=title]){margin:0;font-size:var(--calcite-font-size--1);line-height:1.375;font-weight:var(--calcite-font-weight-medium);color:var(--calcite-color-text-1)}slot[name=subtitle]::slotted(*),*::slotted([slot=subtitle]){margin:0;margin-block-start:.125rem;font-size:var(--calcite-font-size--2);line-height:1.375;font-weight:var(--calcite-font-weight-normal);color:var(--calcite-color-text-2)}slot[name=heading]::slotted(*),*::slotted([slot=heading]){margin:0;font-size:var(--calcite-font-size--1);line-height:1.375;font-weight:var(--calcite-font-weight-medium);color:var(--calcite-color-text-1)}slot[name=description]::slotted(*),*::slotted([slot=description]){margin:0;margin-block-start:.125rem;font-size:var(--calcite-font-size--2);line-height:1.375;font-weight:var(--calcite-font-weight-normal);color:var(--calcite-color-text-2)}slot[name=thumbnail]::slotted(img),img::slotted([slot=thumbnail]){min-inline-size:100%;max-inline-size:100%}slot[name=footer-start]::slotted(*),*::slotted([slot=footer-start]){align-self:center;font-size:var(--calcite-font-size--2);line-height:1.375;margin-inline-end:auto}slot[name=footer-end]::slotted(*),*::slotted([slot=footer-end]){align-self:center;font-size:var(--calcite-font-size--2);line-height:1.375}.checkbox-wrapper-deprecated{pointer-events:auto;position:absolute;inset-block-start:var(--calcite-spacing-sm);inset-inline-end:var(--calcite-spacing-sm);margin:0;padding:0;color:var(--calcite-card-selection-color, var(--calcite-color-text-3))}.checkbox-wrapper-deprecated:hover{background-color:var(--calcite-card-selection-background-color-hover, var(--calcite-color-foreground-2));color:var(--calcite-card-selection-color-hover, var(--calcite-card-selection-icon-color-hover, var(--calcite-color-text-2)))}.checkbox-wrapper-deprecated:active{background-color:var(--calcite-card-selection-background-color-press, var(--calcite-color-transparent-press))}.checkbox-wrapper{pointer-events:auto;margin:.5rem;cursor:pointer;padding:.5rem;outline-color:transparent;display:flex;align-items:center;justify-items:center;color:var(--calcite-card-selection-color, var(--calcite-color-text-3))}.checkbox-wrapper:hover{background-color:var(--calcite-card-selection-background-color-hover, var(--calcite-color-foreground-2));color:var(--calcite-card-selection-color-hover, var(--calcite-card-selection-icon-color-hover, var(--calcite-color-text-2)))}.checkbox-wrapper:active{background-color:var(--calcite-card-selection-background-color-press, var(--calcite-color-transparent-press))}.checkbox-wrapper calcite-icon{pointer-events:none}:host([selected]) .checkbox-wrapper-deprecated,:host([selected]) .checkbox-wrapper{color:var(--calcite-card-accent-color-selected, var(--calcite-card-selection-icon-color-selected, var(--calcite-color-brand)))}:host(:not([selectable])) .content-wrapper:not(.non-interactive):focus .checkbox-wrapper-deprecated,:host(:not([selectable])) .content-wrapper:not(.non-interactive):focus .checkbox-wrapper{background-color:var(--calcite-card-selection-background-color-hover, var(--calcite-color-foreground-2));color:var(--calcite-card-selection-color-hover, var(--calcite-card-selection-icon-color-hover, var(--calcite-color-text-2)))}:host([selected]:not([selectable])) .content-wrapper:not(.non-interactive):focus .checkbox-wrapper-deprecated,:host([selected]:not([selectable])) .content-wrapper:not(.non-interactive):focus .checkbox-wrapper{background-color:var(--calcite-card-selection-background-color-press, var(--calcite-color-transparent-press));color:var(--calcite-card-accent-color-selected, var(--calcite-card-selection-icon-color-selected, var(--calcite-color-brand)))}.thumbnail-wrapper{display:flex}.content-wrapper.inline{flex-direction:row}.content-wrapper.inline>.container{inline-size:60%}.content-wrapper.inline>.thumbnail-wrapper{inline-size:40%;align-items:flex-start}.content-wrapper.inline slot[name=thumbnail]::slotted(img),.content-wrapper.inline img::slotted([slot=thumbnail]){inline-size:100%}slot[name=footer-start]::slotted(*),slot[name=footer-end]::slotted(*){display:flex;gap:.25rem}: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 Card extends LitElement { constructor() { super(...arguments); this.containerEl = createRef(); this.messages = useT9n(); this.hasContent = false; this.hasDescription = false; this.hasFooterEnd = false; this.hasFooterStart = false; this.hasHeading = false; this.hasSubtitle = false; this.hasThumbnail = false; this.hasTitle = false; this.disabled = false; this.loading = false; this.selectable = false; this.selected = false; this.selectionMode = "none"; this.thumbnailPosition = "block-start"; this.calciteCardSelect = createEvent({ cancelable: false }); this.calciteInternalCardKeyEvent = createEvent({ cancelable: false }); } static { this.properties = { hasContent: [16, {}, { state: true }], hasDescription: [16, {}, { state: true }], hasFooterEnd: [16, {}, { state: true }], hasFooterStart: [16, {}, { state: true }], hasHeading: [16, {}, { state: true }], hasSubtitle: [16, {}, { state: true }], hasThumbnail: [16, {}, { state: true }], hasTitle: [16, {}, { state: true }], disabled: [7, {}, { reflect: true, type: Boolean }], label: 1, loading: [7, {}, { reflect: true, type: Boolean }], messageOverrides: [0, {}, { attribute: false }], selectable: [7, {}, { reflect: true, type: Boolean }], selected: [7, {}, { reflect: true, type: Boolean }], selectionMode: 1, thumbnailPosition: [3, {}, { reflect: true }] }; } static { this.styles = styles; } async setFocus() { await componentFocusable(this); if (!this.disabled) { this.containerEl.value?.focus(); } } updated() { updateHostInteraction(this); } handleThumbnailSlotChange(event) { this.hasThumbnail = slotChangeHasAssignedElement(event); } handleHeadingSlotChange(event) { this.hasHeading = slotChangeHasAssignedElement(event); } handleDescriptionSlotChange(event) { this.hasDescription = slotChangeHasAssignedElement(event); } handleTitleSlotChange(event) { this.hasTitle = slotChangeHasAssignedElement(event); } handleSubtitleSlotChange(event) { this.hasSubtitle = slotChangeHasAssignedElement(event); } handleFooterStartSlotChange(event) { this.hasFooterStart = slotChangeHasAssignedElement(event); } handleFooterEndSlotChange(event) { this.hasFooterEnd = slotChangeHasAssignedElement(event); } handleDefaultSlotChange(event) { this.hasContent = slotChangeHasAssignedElement(event); } keyDownHandler(event) { if (event.target === this.containerEl.value && !this.selectable && !this.disabled) { if (isActivationKey(event.key) && this.selectionMode !== "none") { this.calciteCardSelect.emit(); event.preventDefault(); } else { switch (event.key) { case "ArrowRight": case "ArrowLeft": case "Home": case "End": this.calciteInternalCardKeyEvent.emit(event); event.preventDefault(); break; } } } } cardBodyClickHandler(event) { const isFromScreenReader = event.target === this.containerEl.value; if (isFromScreenReader && !this.selectable && !this.disabled && this.selectionMode !== "none") { this.calciteCardSelect.emit(); } } selectCardDeprecated(event) { this.selected = event.currentTarget.checked; this.calciteCardSelect.emit(); } cardSelectClick(event) { if (!this.disabled) { event.preventDefault(); this.calciteCardSelect.emit(); this.setFocus(); } } renderCheckboxDeprecated() { return html`<calcite-label class=${safeClassMap(CSS.checkboxWrapperDeprecated)}><calcite-checkbox .checked=${this.selected} .label=${this.messages.select} @calciteCheckboxChange=${this.selectCardDeprecated}></calcite-checkbox></calcite-label>`; } renderThumbnail() { return html`<section class=${safeClassMap(CSS.thumbnailWrapper)} .hidden=${!this.hasThumbnail}><slot name=${SLOTS.thumbnail} @slotchange=${this.handleThumbnailSlotChange}></slot></section>`; } renderSelectionIcon() { const icon = this.selectionMode === "multiple" && this.selected ? ICONS.selected : this.selectionMode === "multiple" ? ICONS.unselected : this.selected ? ICONS.selectedSingle : ICONS.unselectedSingle; return html`<div class=${safeClassMap(CSS.checkboxWrapper)} @pointerdown=${this.cardSelectClick} tabindex=-1><calcite-icon .icon=${icon} scale=s></calcite-icon></div>`; } renderHeader() { const hasHeader = this.hasHeading || this.hasDescription; const hasDeprecatedHeader = this.hasSubtitle || this.hasTitle; const showHeader = hasHeader || hasDeprecatedHeader; return html`<header class=${safeClassMap(CSS.header)} .hidden=${!showHeader}>${this.selectable ? this.renderCheckboxDeprecated() : null}<div class=${safeClassMap(CSS.headerTextContainer)}><slot name=${SLOTS.heading} @slotchange=${this.handleHeadingSlotChange}></slot><slot name=${SLOTS.description} @slotchange=${this.handleDescriptionSlotChange}></slot><slot name=${SLOTS.title} @slotchange=${this.handleTitleSlotChange}></slot><slot name=${SLOTS.subtitle} @slotchange=${this.handleSubtitleSlotChange}></slot></div>${this.selectionMode !== "none" && this.renderSelectionIcon() || ""}</header>`; } renderFooter() { const hasFooter = this.hasFooterStart || this.hasFooterEnd; return html`<footer class=${safeClassMap(CSS.footer)} .hidden=${!hasFooter}><slot name=${SLOTS.footerStart} @slotchange=${this.handleFooterStartSlotChange}></slot><slot name=${SLOTS.footerEnd} @slotchange=${this.handleFooterEndSlotChange}></slot></footer>`; } render() { const thumbnailInline = this.thumbnailPosition.startsWith("inline"); const thumbnailStart = this.thumbnailPosition.endsWith("start"); const role = this.selectionMode === "multiple" ? "checkbox" : this.selectionMode !== "none" ? "radio" : void 0; return InteractiveContainer({ disabled: this.disabled, children: html`<div .ariaChecked=${this.selectionMode !== "none" ? this.selected : void 0} .ariaLabel=${this.label} class=${safeClassMap({ [CSS.contentWrapper]: true, inline: thumbnailInline })} @click=${this.cardBodyClickHandler} @keydown=${this.keyDownHandler} .role=${role} .tabIndex=${!this.selectable || this.disabled ? 0 : -1} ${ref(this.containerEl)}>${this.loading ? html`<div aria-live=polite class="calcite-card-loader-container"><calcite-loader .label=${this.messages.loading}></calcite-loader></div>` : null}${thumbnailStart && this.renderThumbnail() || ""}<section .ariaBusy=${this.loading} class=${safeClassMap({ [CSS.container]: true })}>${this.renderHeader()}<div class=${safeClassMap({ [CSS.cardContent]: true, [CSS.hasSlottedContent]: this.hasContent })}><slot @slotchange=${this.handleDefaultSlotChange}></slot></div>${this.renderFooter()}</section>${!thumbnailStart && this.renderThumbnail() || ""}</div>` }); } } customElement("calcite-card", Card); export { Card };