UNPKG

@esri/calcite-components

Version:

Web Components for Esri's Calcite Design System.

136 lines (135 loc) • 9.61 kB
/* COPYRIGHT Esri - https://js.arcgis.com/5.0/LICENSE.txt */ import { c as customElement } from "../../chunks/runtime.js"; import { keyed } from "lit/directives/keyed.js"; import { LitElement, createEvent, safeClassMap, nothing } from "@arcgis/lumina"; import { css, html } from "lit"; import { s as slotChangeHasAssignedElement } from "../../chunks/dom.js"; import { i as isActivationKey } from "../../chunks/key.js"; import { g as getIconScale } from "../../chunks/component.js"; import { u as useT9n } from "../../chunks/useT9n.js"; import { l as logger } from "../../chunks/logger.js"; import { u as useSetFocus } from "../../chunks/useSetFocus.js"; const IDS = { content: "content", toggle: "toggle" }; const CSS = { chevronIcon: "chevron-icon", content: "content", iconStart: "icon--start", iconEnd: "icon--end", invalid: "invalid", sectionHeaderText: "section-header__text", statusIcon: "status-icon", switch: "switch", toggle: "toggle", toggleContainer: "toggle-container", toggleSwitchContent: "toggle--switch__content", toggleSwitchText: "toggle--switch__text", valid: "valid" }; const ICONS = { menuExpanded: "chevron-up", menuCollapsed: "chevron-down", valid: "check-circle", invalid: "exclamation-mark-triangle" }; const styles = css`:host{box-sizing:border-box;display:block;color:var(--calcite-block-section-header-text-color, var(--calcite-color-text-2))}:host([expanded]){border-width:0px;border-block-end-width:1px;border-style:solid;border-block-end-color:var(--calcite-block-section-border-color, var(--calcite-color-border-3))}:host([expanded]) .toggle{color:var(--calcite-block-section-text-color-hover, var(--calcite-color-text-1))}:host([expanded]) .toggle:hover{color:var(--calcite-block-section-text-color-hover, var(--calcite-color-text-1))}:host([expanded]) .icon--end,:host([expanded]) .icon--start{color:var(--calcite-block-section-text-color, var(--calcite-color-text-1))}:host([expanded]) .chevron-icon{color:var(--calcite-block-section-text-color, var(--calcite-color-text-3))}:host([expanded]) .chevron-icon:hover{color:var(--calcite-block-section-text-color-hover, var(--calcite-color-text-1))}:host([expanded]) .toggle-container:hover calcite-switch{--calcite-switch-background-color: var(--calcite-color-brand-hover)}:host(:last-child){border-block-end-width:0px}:host([scale=s]) .toggle{padding-block:var(--calcite-spacing-xxs);gap:var(--calcite-spacing-sm);font-size:var(--calcite-font-size-sm)}:host([scale=s]) .content{padding-block:var(--calcite-block-section-content-space, var(--calcite-spacing-xxs))}:host([scale=m]) .toggle{padding-block:var(--calcite-spacing-sm);gap:var(--calcite-spacing-md);font-size:var(--calcite-font-size)}:host([scale=m]) .content{padding-block:var(--calcite-block-section-content-space, var(--calcite-spacing-sm))}:host([scale=l]) .toggle{padding-block:var(--calcite-spacing-md);gap:var(--calcite-spacing-lg);font-size:var(--calcite-font-size-md)}:host([scale=l]) .content{padding-block:var(--calcite-block-section-content-space, var(--calcite-spacing-md))}.toggle{display:flex;inline-size:100%;cursor:pointer;-webkit-user-select:none;user-select:none;align-items:center;border-width:0px;outline-color:transparent;font-family:inherit;color:var(--calcite-block-section-header-text-color, var(--calcite-color-text-2));background-color:var(--calcite-block-section-background-color, var(--calcite-color-foreground-1));font-weight:var(--calcite-font-weight-regular);padding-inline:0;line-height:var(--calcite-font-line-height-relative-snug)}.toggle:focus{outline:var(--calcite-border-width-md) solid var(--calcite-color-focus, var(--calcite-ui-focus-color, var(--calcite-color-brand)));z-index:var(--calcite-z-index)}.toggle:hover{color:var(--calcite-block-section-text-color-hover, var(--calcite-color-text-1))}.section-header__text{margin-block:0px;flex:1 1 auto;text-align:initial;word-wrap:anywhere}.toggle-container{position:relative;display:flex;align-items:center;word-break:break-word}.toggle-container .toggle--switch__content{display:flex;flex:1 1 auto;align-items:center}.toggle-container .icon--end,.toggle-container .icon--start,.toggle-container .chevron-icon{display:flex;align-items:center;color:var(--calcite-block-section-text-color, var(--calcite-color-text-3))}.toggle-container:hover .chevron-icon{color:var(--calcite-block-section-text-color-hover, var(--calcite-color-text-1))}.toggle-container:hover calcite-switch{--calcite-switch-background-color: var(--calcite-color-text-3)}.status-icon{display:flex;align-items:center}.status-icon.valid{color:var(--calcite-color-status-success)}.status-icon.invalid{color:var(--calcite-color-status-danger)}:host([hidden]){display:none}[hidden]{display:none}`; class BlockSection extends LitElement { constructor() { super(...arguments); this.messages = useT9n(); this.focusSetter = useSetFocus()(this); this.defaultSlotHasElements = false; this.expanded = false; this.scale = "m"; this.toggleDisplay = "button"; this.calciteBlockSectionCollapse = createEvent({ cancelable: false }); this.calciteBlockSectionExpand = createEvent({ cancelable: false }); this.calciteBlockSectionToggle = createEvent({ cancelable: false }); } static { this.properties = { defaultSlotHasElements: [16, {}, { state: true }], expanded: [7, {}, { reflect: true, type: Boolean }], iconEnd: [3, { type: String }, { reflect: true }], iconFlipRtl: [3, {}, { reflect: true }], iconStart: [3, { type: String }, { reflect: true }], messageOverrides: [0, {}, { attribute: false }], open: [7, {}, { reflect: true, type: Boolean }], scale: [3, {}, { reflect: true }], status: [3, {}, { reflect: true }], text: 1, toggleDisplay: [3, {}, { reflect: true }] }; } static { this.styles = styles; } get open() { return this.expanded; } set open(value) { logger.deprecated("property", { component: this, name: "open", removalVersion: 5, suggested: "expanded" }); this.expanded = value; } async setFocus(options) { return this.focusSetter(() => this.el, options); } willUpdate(changes) { if (changes.has("expanded") && this.hasUpdated) { if (this.expanded) { this.calciteBlockSectionExpand.emit(); } else { this.calciteBlockSectionCollapse.emit(); } } } handleHeaderKeyDown(event) { if (isActivationKey(event.key)) { this.toggleSection(); event.preventDefault(); event.stopPropagation(); } } toggleSection() { this.expanded = !this.expanded; this.calciteBlockSectionToggle.emit(); } handleDefaultSlot(event) { this.defaultSlotHasElements = slotChangeHasAssignedElement(event); } renderStatusIcon() { const { status } = this; const statusIcon = ICONS[status] ?? false; const statusIconClasses = { [CSS.statusIcon]: true, [CSS.valid]: status == "valid", [CSS.invalid]: status == "invalid" }; return statusIcon ? html`<calcite-icon class=${safeClassMap(statusIconClasses)} .icon=${statusIcon} .scale=${getIconScale(this.scale)}></calcite-icon>` : null; } renderIcon(position) { const { iconFlipRtl, iconStart, iconEnd } = this; const icon = position === "start" ? iconStart : iconEnd; if (icon === void 0) { return null; } const flipRtlStart = iconFlipRtl === "both" || iconFlipRtl === "start"; const flipRtlEnd = iconFlipRtl === "both" || iconFlipRtl === "end"; const isIconStart = position === "start"; return keyed(isIconStart ? iconStart : iconEnd, html`<calcite-icon class=${safeClassMap(isIconStart ? CSS.iconStart : CSS.iconEnd)} .flipRtl=${isIconStart ? flipRtlStart : flipRtlEnd} .icon=${isIconStart ? iconStart : iconEnd} .scale=${getIconScale(this.scale)}></calcite-icon>`); } render() { const { messages, expanded, text, toggleDisplay } = this; const arrowIcon = expanded ? ICONS.menuExpanded : ICONS.menuCollapsed; const toggleLabel = expanded ? messages.collapse : messages.expand; const headerNode = toggleDisplay === "switch" ? html`<div class=${safeClassMap({ [CSS.toggleContainer]: true })}><div aria-controls=${IDS.content} .ariaExpanded=${expanded} class=${safeClassMap({ [CSS.toggle]: true })} id=${IDS.toggle} @click=${this.toggleSection} @keydown=${this.handleHeaderKeyDown} role=button tabindex=0 title=${toggleLabel ?? nothing}>${this.renderIcon("start")}<div class=${safeClassMap(CSS.toggleSwitchContent)}><span class=${safeClassMap(CSS.toggleSwitchText)}>${text}</span></div>${this.renderIcon("end")}${this.renderStatusIcon()}<calcite-switch .checked=${expanded} class=${safeClassMap(CSS.switch)} inert .label=${toggleLabel} .scale=${this.scale}></calcite-switch></div></div>` : html`<div class=${safeClassMap({ [CSS.toggleContainer]: true })}><button aria-controls=${IDS.content} .ariaExpanded=${expanded} class=${safeClassMap({ [CSS.toggle]: true })} id=${IDS.toggle} @click=${this.toggleSection}>${this.renderIcon("start")}<span class=${safeClassMap(CSS.sectionHeaderText)}>${text}</span>${this.renderIcon("end")}${this.renderStatusIcon()}<calcite-icon class=${safeClassMap(CSS.chevronIcon)} .icon=${arrowIcon} .scale=${getIconScale(this.scale)}></calcite-icon></button></div>`; return html`${headerNode}<section aria-labelledby=${IDS.toggle} class=${safeClassMap({ [CSS.content]: this.defaultSlotHasElements })} .hidden=${!expanded} id=${IDS.content}><slot @slotchange=${this.handleDefaultSlot}></slot></section>`; } } customElement("calcite-block-section", BlockSection); export { BlockSection };