@esri/calcite-components
Version:
Web Components for Esri's Calcite Design System.
195 lines (194 loc) • 18 kB
JavaScript
/* COPYRIGHT Esri - https://js.arcgis.com/5.0/LICENSE.txt */
import { C as CSS_UTILITY, c as customElement } from "../../chunks/runtime.js";
import { keyed } from "lit/directives/keyed.js";
import { css, html, nothing } from "lit";
import { LitElement, createEvent, safeClassMap } from "@arcgis/lumina";
import { createRef, ref } from "lit/directives/ref.js";
import { c as closestElementCrossShadowBoundary, s as slotChangeHasAssignedElement, g as getElementDir } from "../../chunks/dom.js";
import { g as getIconScale } from "../../chunks/component.js";
import { u as useSetFocus } from "../../chunks/useSetFocus.js";
import { u as useT9n } from "../../chunks/useT9n.js";
import { H as Heading } from "../../chunks/Heading.js";
const SLOTS = {
actionsStart: "actions-start",
actionsEnd: "actions-end",
contentEnd: "content-end",
contentStart: "content-start"
};
const CSS = {
actionsEnd: "actions-end",
actionsStart: "actions-start",
content: "content",
description: "description",
expandIcon: "expand-icon",
hasActions: "has-actions",
header: "header",
headerContainer: "header-container",
headerContent: "header-content",
headerText: "header-text",
headerAppearance: (appearance) => `header--${appearance}`,
heading: "heading",
icon: "icon",
iconEnd: "icon--end",
iconStart: "icon--start",
iconPosition: (iconPosition) => `icon-position--${iconPosition}`,
iconType: (iconType) => `icon-type--${iconType}`,
item: "item",
slotContentEnd: "slot-content-end",
slotContentStart: "slot-content-start"
};
const IDS = {
section: "section",
sectionToggle: "section-toggle"
};
const ICONS = {
chevronDown: "chevronDown",
caretDown: "caretDown",
plus: "plus",
minus: "minus"
};
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([scale=s]){--calcite-internal-accordion-item-action-slot-spacing: var(--calcite-spacing-xxs);--calcite-internal-accordion-item-description-font-size: var(--calcite-font-size--3)}:host([scale=m]){--calcite-internal-accordion-item-action-slot-spacing: var(--calcite-spacing-xxs);--calcite-internal-accordion-item-description-font-size: var(--calcite-font-size--2)}:host([scale=l]){--calcite-internal-accordion-item-action-slot-spacing: var(--calcite-spacing-xs);--calcite-internal-accordion-item-description-font-size: var(--calcite-font-size--1)}: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));background:none;border:none;appearance:none;-webkit-appearance:none;box-shadow:none;outline:none;font-family:inherit}.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-timing-function:cubic-bezier(.4,0,.2,1);word-wrap:break-word;word-break:break-word}.header .has-actions{gap:var(--calcite-internal-accordion-item-action-slot-spacing);padding-block:var(--calcite-internal-accordion-item-action-slot-spacing)}.header .actions-start.has-actions{padding-inline:var(--calcite-internal-accordion-item-action-slot-spacing) 0}.header .actions-end.has-actions{padding-inline:0 var(--calcite-internal-accordion-item-action-slot-spacing)}.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: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))))}.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%}.slot-content-end{margin-inline-start:var(--calcite-internal-accordion-icon-margin)}.slot-content-start{margin-inline-end:var(--calcite-internal-accordion-icon-margin)}.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%;line-height:var(--calcite-font-line-height-relative-snug)}.heading{margin:0;padding:0;font-weight:var(--calcite-font-weight-medium)}:host([scale=s]) .heading{font-size:var(--calcite-font-size--2)}:host([scale=m]) .heading{font-size:var(--calcite-font-size--1)}:host([scale=l]) .heading{font-size:var(--calcite-font-size-0)}.icon{display:flex;align-items:center;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, var(--calcite-ui-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, var(--calcite-ui-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{font-size:var(--calcite-internal-accordion-item-description-font-size)}.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-1))));font-weight:var(--calcite-font-weight-normal)}: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.headerRef = createRef();
this.focusSetter = useSetFocus()(this);
this.messages = useT9n();
this.hasActionsEnd = false;
this.hasActionsStart = false;
this.hasContentEnd = false;
this.hasContentStart = false;
this.expanded = false;
this.calciteAccordionItemCollapse = createEvent({ cancelable: false });
this.calciteAccordionItemExpand = createEvent({ cancelable: 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 }], hasContentEnd: [16, {}, { state: true }], hasContentStart: [16, {}, { state: true }], accordionParent: [0, {}, { attribute: false }], description: 1, expanded: [7, {}, { reflect: true, type: Boolean }], heading: 1, iconEnd: [3, { type: String }, { reflect: true }], iconFlipRtl: [3, {}, { reflect: true }], appearance: 1, headingLevel: [11, {}, { type: Number, reflect: true }], iconPosition: 1, iconStart: [3, { type: String }, { reflect: true }], iconType: 1, scale: [3, {}, { reflect: true }], messageOverrides: [0, {}, { attribute: false }] };
}
static {
this.styles = styles;
}
async setFocus(options) {
return this.focusSetter(() => this.headerRef.value, options);
}
willUpdate(changes) {
if (changes.has("expanded") && this.hasUpdated) {
if (this.expanded) {
this.calciteAccordionItemExpand.emit();
} else {
this.calciteAccordionItemCollapse.emit();
}
}
}
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);
}
handleContentEndSlotChange(event) {
this.hasContentEnd = slotChangeHasAssignedElement(event);
}
handleContentStartSlotChange(event) {
this.hasContentStart = slotChangeHasAssignedElement(event);
}
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() {
const { hasActionsStart } = this;
return html`<div class=${safeClassMap({ [CSS.actionsStart]: true, [CSS.hasActions]: hasActionsStart })} .hidden=${!hasActionsStart}><slot name=${SLOTS.actionsStart} @slotchange=${this.handleActionsStartSlotChange}></slot></div>`;
}
renderActionsEnd() {
const { hasActionsEnd } = this;
return html`<div class=${safeClassMap({ [CSS.actionsEnd]: true, [CSS.hasActions]: hasActionsEnd })} .hidden=${!hasActionsEnd}><slot name=${SLOTS.actionsEnd} @slotchange=${this.handleActionsEndSlotChange}></slot></div>`;
}
renderContentEnd() {
return html`<div class=${safeClassMap(CSS.slotContentEnd)} .hidden=${!this.hasContentEnd}><slot name=${SLOTS.contentEnd} @slotchange=${this.handleContentEndSlotChange}></slot></div>`;
}
renderContentStart() {
return html`<div class=${safeClassMap(CSS.slotContentStart)} .hidden=${!this.hasContentStart}><slot name=${SLOTS.contentStart} @slotchange=${this.handleContentStartSlotChange}></slot></div>`;
}
render() {
const { iconFlipRtl, heading, headingLevel, messages, expanded } = this;
const dir = getElementDir(this.el);
const expandIconTitle = expanded ? messages.collapse : messages.expand;
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({
[CSS.iconPosition(this.iconPosition)]: true,
[CSS.iconType(this.iconType)]: true
})}><div class=${safeClassMap({
[CSS.header]: true,
[CSS_UTILITY.rtl]: dir === "rtl",
[CSS.headerAppearance(this.appearance)]: true
})}>${this.renderActionsStart()}<button aria-controls=${IDS.section} .ariaExpanded=${expanded} class=${safeClassMap(CSS.headerContent)} id=${IDS.sectionToggle} @click=${this.itemHeaderClickHandler} type=button ${ref(this.headerRef)}><div class=${safeClassMap(CSS.headerContainer)}>${this.renderContentStart()}${iconStartEl}<div class=${safeClassMap(CSS.headerText)}>${Heading({ class: CSS.heading, level: headingLevel, children: heading })}${description ? html`<span class=${safeClassMap(CSS.description)}>${description}</span>` : null}</div>${iconEndEl}${this.renderContentEnd()}</div><calcite-icon class=${safeClassMap(CSS.expandIcon)} .icon=${this.iconType === "chevron" ? ICONS.chevronDown : this.iconType === "caret" ? ICONS.caretDown : expanded ? ICONS.minus : ICONS.plus} .scale=${getIconScale(this.scale)} title=${expandIconTitle ?? nothing}></calcite-icon></button>${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
};