@esri/calcite-components
Version:
Web Components for Esri's Calcite Design System.
124 lines (123 loc) • 8.4 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 customElement } from "../../chunks/runtime.js";
import { html } from "lit-html";
import { keyed } from "lit-html/directives/keyed.js";
import { LitElement, createEvent, safeClassMap, nothing } from "@arcgis/lumina";
import { h as focusFirstTabbable } from "../../chunks/dom.js";
import { i as isActivationKey } from "../../chunks/key.js";
import { c as componentFocusable } from "../../chunks/component.js";
import { u as useT9n } from "../../chunks/useT9n.js";
import { l as logger } from "../../chunks/logger.js";
import { css } from "@lit/reactive-element/css-tag.js";
const IDS = {
content: "content",
toggle: "toggle"
};
const CSS = {
chevronIcon: "chevron-icon",
content: "content",
iconStart: "icon--start",
iconEnd: "icon--end",
invalid: "invalid",
sectionHeader: "section-header",
sectionHeaderText: "section-header__text",
statusIcon: "status-icon",
switch: "switch",
toggle: "toggle",
toggleSwitch: "toggle--switch",
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;font-size:var(--calcite-font-size--1);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))}: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]) .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(:last-child){border-block-end-width:0px}.toggle{inline-size:100%;border-width:0px;font-family:var(--calcite-font-family);gap:var(--calcite-spacing-md);color:var(--calcite-block-section-header-text-color, var(--calcite-color-text-2));background-color:var(--calcite-block-section-background-color, transparent);font-weight:var(--calcite-font-weight-normal)}.toggle:hover{color:var(--calcite-block-section-text-color-hover, var(--calcite-color-text-1))}.toggle--switch,.section-header{margin-inline:0px;margin-block:.25rem;display:flex;cursor:pointer;-webkit-user-select:none;user-select:none;align-items:center;padding-inline:0px;padding-block:.5rem;font-size:var(--calcite-font-size--1);outline-color:transparent}.toggle--switch:focus,.section-header: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))))}.toggle--switch:hover,.section-header: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;background-color:var(--calcite-block-section-background-color, transparent)}.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 .icon--end:hover,.toggle-container .icon--start:hover,.toggle-container .chevron-icon:hover{color:var(--calcite-block-section-text-color-hover, var(--calcite-color-text-1))}.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.expanded = false;
this.toggleDisplay = "button";
this.calciteBlockSectionToggle = createEvent({ cancelable: false });
}
static {
this.properties = { expanded: [7, {}, { reflect: true, type: Boolean }], iconEnd: [3, {}, { reflect: true }], iconFlipRtl: [3, {}, { reflect: true }], iconStart: [3, {}, { reflect: true }], messageOverrides: [0, {}, { attribute: false }], open: [7, {}, { reflect: true, type: Boolean }], 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", {
name: "open",
removalVersion: 4,
suggested: "expanded"
});
this.expanded = value;
}
async setFocus() {
await componentFocusable(this);
focusFirstTabbable(this.el);
}
handleHeaderKeyDown(event) {
if (isActivationKey(event.key)) {
this.toggleSection();
event.preventDefault();
event.stopPropagation();
}
}
toggleSection() {
this.expanded = !this.expanded;
this.calciteBlockSectionToggle.emit();
}
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=s></calcite-icon>` : null;
}
renderIcon(icon) {
const { iconFlipRtl } = this;
if (icon === void 0) {
return null;
}
const flipRtlStart = iconFlipRtl === "both" || iconFlipRtl === "start";
const flipRtlEnd = iconFlipRtl === "both" || iconFlipRtl === "end";
const isIconStart = icon === this.iconStart;
return keyed(isIconStart ? this.iconStart : this.iconEnd, html`<calcite-icon class=${safeClassMap(isIconStart ? CSS.iconStart : CSS.iconEnd)} .flipRtl=${isIconStart ? flipRtlStart : flipRtlEnd} .icon=${isIconStart ? this.iconStart : this.iconEnd} scale=s></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,
[CSS.toggleSwitch]: true
})} id=${IDS.toggle} @click=${this.toggleSection} @keydown=${this.handleHeaderKeyDown} role=button tabindex=0 title=${toggleLabel ?? nothing}>${this.renderIcon(this.iconStart)}<div class=${safeClassMap(CSS.toggleSwitchContent)}><span class=${safeClassMap(CSS.toggleSwitchText)}>${text}</span></div>${this.renderIcon(this.iconEnd)}${this.renderStatusIcon()}<calcite-switch .checked=${expanded} class=${safeClassMap(CSS.switch)} inert .label=${toggleLabel} scale=s></calcite-switch></div></div>` : html`<div class=${safeClassMap({
[CSS.toggleContainer]: true
})}><button aria-controls=${IDS.content} .ariaExpanded=${expanded} class=${safeClassMap({
[CSS.sectionHeader]: true,
[CSS.toggle]: true
})} id=${IDS.toggle} @click=${this.toggleSection}>${this.renderIcon(this.iconStart)}<span class=${safeClassMap(CSS.sectionHeaderText)}>${text}</span>${this.renderIcon(this.iconEnd)}${this.renderStatusIcon()}<calcite-icon class=${safeClassMap(CSS.chevronIcon)} .icon=${arrowIcon} scale=s></calcite-icon></button></div>`;
return html`${headerNode}<section aria-labelledby=${IDS.toggle} class=${safeClassMap(CSS.content)} .hidden=${!expanded} id=${IDS.content}><slot></slot></section>`;
}
}
customElement("calcite-block-section", BlockSection);
export {
BlockSection
};