@esri/calcite-components
Version:
Web Components for Esri's Calcite Design System.
136 lines (135 loc) • 9.61 kB
JavaScript
/* 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
};