UNPKG

@esri/calcite-components

Version:

Web Components for Esri's Calcite Design System.

195 lines (194 loc) • 18 kB
/* 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 };