@esri/calcite-components
Version:
Web Components for Esri's Calcite Design System.
153 lines (152 loc) • 14.2 kB
JavaScript
/*! 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 CSS_UTILITY, c as customElement } from "../../chunks/runtime.js";
import { html } from "lit-html";
import { keyed } from "lit-html/directives/keyed.js";
import { ref } from "lit-html/directives/ref.js";
import { LitElement, createEvent, safeClassMap } from "@arcgis/lumina";
import { l as closestElementCrossShadowBoundary, a as slotChangeHasAssignedElement, g as getElementDir } from "../../chunks/dom.js";
import { c as componentFocusable, g as getIconScale } from "../../chunks/component.js";
import { css } from "@lit/reactive-element/css-tag.js";
const SLOTS = {
actionsStart: "actions-start",
actionsEnd: "actions-end"
};
const CSS = {
actionsEnd: "actions-end",
actionsStart: "actions-start",
content: "content",
description: "description",
expandIcon: "expand-icon",
header: "header",
headerContainer: "header-container",
headerContent: "header-content",
headerText: "header-text",
heading: "heading",
icon: "icon",
iconEnd: "icon--end",
iconStart: "icon--start"
};
const IDS = {
section: "section",
sectionToggle: "section-toggle"
};
const styles = css`.icon-position--end,.icon-position--start{--calcite-internal-accordion-item-icon-rotation: -90deg ;--calcite-internal-accordion-item-active-icon-rotation: 0deg;--calcite-internal-accordion-item-icon-rotation-rtl: 90deg;--calcite-internal-accordion-item-active-icon-rotation-rtl: 0deg}:host{position:relative;display:flex;flex-direction:column;text-decoration-line:none;color:var(--calcite-accordion-text-color, var(--calcite-accordion-item-text-color, var(--calcite-color-text-3)));background-color:var(--calcite-accordion-background-color, var(--calcite-accordion-item-background-color));border-width:0}:host .header{background-color:var(--calcite-accordion-item-header-background-color)}:host .header:hover{background-color:var(--calcite-internal-accordion-item-header-background-color-hover)}:host .header:active{background-color:var(--calcite-internal-accordion-item-header-background-color-press)}.header--solid{--calcite-internal-accordion-item-header-background-color-hover: var( --calcite-accordion-item-header-background-color-hover, var(--calcite-color-foreground-2) );--calcite-internal-accordion-item-header-background-color-press: var( --calcite-accordion-item-header-background-color-press, var(--calcite-color-foreground-3) )}.header--transparent{--calcite-internal-accordion-item-header-background-color-hover: var( --calcite-accordion-item-header-background-color-hover, var(--calcite-color-transparent-hover) );--calcite-internal-accordion-item-header-background-color-press: var( --calcite-accordion-item-header-background-color-press, var(--calcite-color-transparent-press) )}.icon-position--start{--calcite-internal-accordion-item-flex-direction: row-reverse;--calcite-internal-accordion-item-icon-spacing-start: 0;--calcite-internal-accordion-item-icon-spacing-end: var(--calcite-internal-accordion-icon-margin)}.icon-position--end{--calcite-internal-accordion-item-flex-direction: row;--calcite-internal-accordion-item-icon-spacing-start: var(--calcite-internal-accordion-icon-margin);--calcite-internal-accordion-item-icon-spacing-end: 0}.icon-position--end:not(.icon-type--plus-minus){--calcite-internal-accordion-item-icon-rotation: 0deg;--calcite-internal-accordion-item-active-icon-rotation: 180deg;--calcite-internal-accordion-item-icon-rotation-rtl: 0deg;--calcite-internal-accordion-item-active-icon-rotation-rtl: -180deg }.content,.header{border-block-end-width:var(--calcite-border-width-sm);border-block-end-style:solid;border-color:var(--calcite-accordion-border-color, var(--calcite-accordion-item-border-color, var(--calcite-color-border-2)))}.header-content{padding:var(--calcite-internal-accordion-item-padding, var(--calcite-internal-accordion-item-spacing-unit, .5rem .75rem))}.content{padding:var(--calcite-accordion-item-content-space, var(--calcite-internal-accordion-item-padding, var(--calcite-internal-accordion-item-spacing-unit, .5rem .75rem)))}.header{display:flex;align-items:stretch}.header-content,.header-container,.header .actions-start,.header .actions-end{display:flex;align-items:center;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1);word-wrap:break-word;word-break:break-word}.header-content{flex-grow:1;cursor:pointer;outline-color:transparent;flex-direction:var(--calcite-internal-accordion-item-flex-direction);color:var(--calcite-accordion-item-heading-text-color, var(--calcite-accordion-text-color, inherit))}.header-content: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))))}.header-content:focus,.header-content:hover,.header-content:active{color:var(--calcite-accordion-item-heading-text-color, var(--calcite-accordion-text-color-hover))}.header-content:focus .heading,.header-content:hover .heading,.header-content:active .heading{color:var(--calcite-accordion-item-heading-text-color, var(--calcite-accordion-text-color-press))}.header-container{inline-size:100%}.header-text{margin-block:0px;flex-grow:1;flex-direction:column;padding-block:0px;text-align:initial;margin-inline-end:auto}.heading,.description{display:flex;inline-size:100%}.heading{font-weight:var(--calcite-font-weight-medium)}.actions-start ::slotted(calcite-action),.actions-end ::slotted(calcite-action){align-self:stretch}.icon{display:flex;align-items:center;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1);margin-inline-end:var(--calcite-internal-accordion-item-icon-spacing-start);margin-inline-start:var(--calcite-internal-accordion-item-icon-spacing-end)}.icon--start{color:var(--calcite-accordion-item-icon-color-start, var(--calcite-accordion-item-start-icon-color, var(--calcite-accordion-item-icon-color, currentColor)));margin-inline-end:var(--calcite-internal-accordion-icon-margin)}.icon--end{color:var(--calcite-accordion-item-icon-color-end, var(--calcite-accordion-item-end-icon-color, var(--calcite-accordion-item-icon-color, currentColor)));margin-inline-end:var(--calcite-internal-accordion-icon-margin);margin-inline-start:var(--calcite-internal-accordion-icon-margin)}.expand-icon{color:var(--calcite-accordion-item-expand-icon-color, var(--calcite-accordion-text-color, var(--calcite-accordion-item-text-color, var(--calcite-color-text-3))));margin-inline-start:var(--calcite-internal-accordion-item-icon-spacing-start);margin-inline-end:var(--calcite-internal-accordion-item-icon-spacing-end);transform:rotate(var(--calcite-internal-accordion-item-icon-rotation))}.calcite--rtl .expand-icon{transform:rotate(var(--calcite-internal-accordion-item-icon-rotation-rtl))}.description{margin-block-start:.25rem}.content{display:none;text-align:initial}:host(:not([expanded])) .heading{color:var(--calcite-accordion-item-heading-text-color, var(--calcite-accordion-text-color-hover, var(--calcite-accordion-item-text-color-hover, var(--calcite-color-text-2))))}:host([expanded]){color:var(--calcite-accordion-text-color-press, var(--calcite-accordion-text-color, var(--calcite-accordion-item-text-color, var(--calcite-color-text-1))))}:host([expanded]) .header{border-block-end-color:transparent}:host([expanded]) .expand-icon{color:var(--calcite-accordion-item-expand-icon-color, var(--calcite-accordion-text-color-hover, var(--calcite-accordion-text-color, var(--calcite-accordion-item-text-color, var(--calcite-accordion-item-text-color-hover, var(--calcite-color-text-2))))));transform:rotate(var(--calcite-internal-accordion-item-active-icon-rotation))}:host([expanded]) .calcite--rtl .expand-icon{transform:rotate(var(--calcite-internal-accordion-item-active-icon-rotation-rtl))}:host([expanded]) .description{color:var(--calcite-accordion-text-color-hover, var(--calcite-accordion-text-color, var(--calcite-accordion-item-text-color, var(--calcite-accordion-item-text-color-hover, var(--calcite-color-text-2)))))}:host([expanded]) .content{display:block}@media (forced-colors: active){:host([expanded]) .header{border-block-end:none}:host([expanded]) .heading{font-weight:bolder}.header-content:hover .heading,.header-content:focus .heading{text-decoration:underline}}:host([hidden]){display:none}[hidden]{display:none}`;
class AccordionItem extends LitElement {
constructor() {
super();
this.hasActionsEnd = false;
this.hasActionsStart = false;
this.expanded = false;
this.calciteInternalAccordionItemClose = createEvent({ cancelable: false });
this.calciteInternalAccordionItemSelect = createEvent({ cancelable: false });
this.listen("keydown", this.keyDownHandler);
this.listenOn(document.body, "calciteInternalAccordionChange", this.updateActiveItemOnChange);
this.listenOn(document, "calciteInternalAccordionItemsSync", this.accordionItemSyncHandler);
}
static {
this.properties = { hasActionsEnd: [16, {}, { state: true }], hasActionsStart: [16, {}, { state: true }], accordionParent: [0, {}, { attribute: false }], description: 1, expanded: [7, {}, { reflect: true, type: Boolean }], heading: 1, iconEnd: [3, {}, { reflect: true }], iconFlipRtl: [3, {}, { reflect: true }], appearance: 1, iconPosition: 1, iconStart: [3, {}, { reflect: true }], iconType: 1, scale: 1 };
}
static {
this.styles = styles;
}
async setFocus() {
await componentFocusable(this);
this.headerEl.focus();
}
keyDownHandler(event) {
if (event.target === this.el) {
switch (event.key) {
case " ":
case "Enter":
this.emitRequestedItem();
event.preventDefault();
break;
}
}
}
updateActiveItemOnChange(event) {
const [accordion] = event.composedPath();
const parent = closestElementCrossShadowBoundary(this.el, "calcite-accordion");
if (accordion !== parent) {
return;
}
this.determineActiveItem(parent.selectionMode, event.detail.requestedAccordionItem);
event.stopPropagation();
}
accordionItemSyncHandler(event) {
const [accordion] = event.composedPath();
const accordionItem = this.el;
const willBeSyncedByDirectParent = accordionItem.parentElement === accordion;
if (willBeSyncedByDirectParent) {
return;
}
const closestAccordionParent = closestElementCrossShadowBoundary(accordionItem, "calcite-accordion");
if (accordion !== closestAccordionParent) {
return;
}
this.appearance = closestAccordionParent.appearance;
this.iconPosition = closestAccordionParent.iconPosition;
this.iconType = closestAccordionParent.iconType;
this.scale = closestAccordionParent.scale;
event.stopPropagation();
}
handleActionsStartSlotChange(event) {
this.hasActionsStart = slotChangeHasAssignedElement(event);
}
handleActionsEndSlotChange(event) {
this.hasActionsEnd = slotChangeHasAssignedElement(event);
}
storeHeaderEl(el) {
this.headerEl = el;
}
itemHeaderClickHandler() {
this.emitRequestedItem();
}
determineActiveItem(selectionMode, requestedItem) {
switch (selectionMode) {
case "multiple":
if (this.el === requestedItem) {
this.expanded = !this.expanded;
}
break;
case "single":
this.expanded = this.el === requestedItem ? !this.expanded : false;
break;
case "single-persist":
this.expanded = this.el === requestedItem;
break;
}
}
emitRequestedItem() {
this.calciteInternalAccordionItemSelect.emit({
requestedAccordionItem: this.el
});
}
renderActionsStart() {
return html`<div class=${safeClassMap(CSS.actionsStart)} .hidden=${!this.hasActionsStart}><slot name=${SLOTS.actionsStart} @slotchange=${this.handleActionsStartSlotChange}></slot></div>`;
}
renderActionsEnd() {
return html`<div class=${safeClassMap(CSS.actionsEnd)} .hidden=${!this.hasActionsEnd}><slot name=${SLOTS.actionsEnd} @slotchange=${this.handleActionsEndSlotChange}></slot></div>`;
}
render() {
const { iconFlipRtl } = this;
const dir = getElementDir(this.el);
const iconStartEl = this.iconStart ? keyed("icon-start", html`<calcite-icon class=${safeClassMap({ [CSS.icon]: true, [CSS.iconStart]: true })} .flipRtl=${iconFlipRtl === "both" || iconFlipRtl === "start"} .icon=${this.iconStart} .scale=${getIconScale(this.scale)}></calcite-icon>`) : null;
const iconEndEl = this.iconEnd ? keyed("icon-end", html`<calcite-icon class=${safeClassMap({ [CSS.iconEnd]: true, [CSS.icon]: true })} .flipRtl=${iconFlipRtl === "both" || iconFlipRtl === "end"} .icon=${this.iconEnd} .scale=${getIconScale(this.scale)}></calcite-icon>`) : null;
const { description } = this;
return html`<div class=${safeClassMap({
[`icon-position--${this.iconPosition}`]: true,
[`icon-type--${this.iconType}`]: true
})}><div class=${safeClassMap({
[CSS.header]: true,
[CSS_UTILITY.rtl]: dir === "rtl",
[`header--${this.appearance}`]: true
})}>${this.renderActionsStart()}<div aria-controls=${IDS.section} .ariaExpanded=${this.expanded} class=${safeClassMap(CSS.headerContent)} id=${IDS.sectionToggle} @click=${this.itemHeaderClickHandler} role=button tabindex=0 ${ref(this.storeHeaderEl)}><div class=${safeClassMap(CSS.headerContainer)}>${iconStartEl}<div class=${safeClassMap(CSS.headerText)}><span class=${safeClassMap(CSS.heading)}>${this.heading}</span>${description ? html`<span class=${safeClassMap(CSS.description)}>${description}</span>` : null}</div>${iconEndEl}</div><calcite-icon class=${safeClassMap(CSS.expandIcon)} .icon=${this.iconType === "chevron" ? "chevronDown" : this.iconType === "caret" ? "caretDown" : this.expanded ? "minus" : "plus"} .scale=${getIconScale(this.scale)}></calcite-icon></div>${this.renderActionsEnd()}</div><section aria-labelledby=${IDS.sectionToggle} class=${safeClassMap(CSS.content)} id=${IDS.section}><slot></slot></section></div>`;
}
}
customElement("calcite-accordion-item", AccordionItem);
export {
AccordionItem
};