@esri/calcite-components
Version:
Web Components for Esri's Calcite Design System.
274 lines (273 loc) • 13.7 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 { ref } from "lit-html/directives/ref.js";
import { html as html$1, nothing } from "lit";
import { safeClassMap, LitElement, createEvent } from "@arcgis/lumina";
import { d as focusElementInGroup, s as slotChangeGetAssignedElements } from "../../chunks/dom.js";
import { c as createObserver } from "../../chunks/observers.js";
import { g as guid } from "../../chunks/guid.js";
import { u as useT9n } from "../../chunks/useT9n.js";
import { i as isHidden } from "../../chunks/component.js";
import { svg, html } from "lit-html";
import { css } from "@lit/reactive-element/css-tag.js";
const CSS$1 = {
actionIcon: "action-icon",
actionContainer: "action-container",
stepBarContainer: "step-bar-container",
singleView: "single-view"
};
const CSS = {
stepBar: "step-bar",
stepBarActive: "step-bar--active",
stepBarComplete: "step-bar--complete",
stepBarDisabled: "step-bar--disabled",
stepBarError: "step-bar--error",
stepBarInActive: "step-bar--inactive"
};
const StepBar = ({ disabled, active, complete, error }) => html`<svg class=${safeClassMap({
[CSS.stepBar]: true
})}>${svg`<rect class=${safeClassMap({
[CSS.stepBarActive]: active,
[CSS.stepBarComplete]: complete,
[CSS.stepBarDisabled]: disabled,
[CSS.stepBarError]: error,
[CSS.stepBarInActive]: true
})} width=100% x=0 y=0 />`}</svg>`;
const styles = css`:host([scale=s]){--calcite-internal-stepper-item-spacing-unit-s: .25rem;--calcite-internal-stepper-action-block-size: 2.75rem;--calcite-internal-stepper-action-inline-size: 2rem;--calcite-internal-step-bar-gap: .25rem}:host([scale=m]){--calcite-internal-stepper-item-spacing-unit-s: .5rem;--calcite-internal-stepper-action-block-size: 3.25rem;--calcite-internal-stepper-action-inline-size: 2.5rem}:host([scale=l]){--calcite-internal-stepper-item-spacing-unit-s: .75rem;--calcite-internal-stepper-action-block-size: 4rem;--calcite-internal-stepper-action-inline-size: 3rem;--calcite-internal-step-bar-gap: .75rem}:host{display:flex}.container{position:relative;display:flex;inline-size:100%;min-inline-size:fit-content;flex-direction:row;flex-wrap:wrap;align-items:stretch;justify-content:space-between}:host([layout=vertical]) .container{flex:1 1 auto;flex-direction:column}:host([layout=horizontal]) .container,:host([layout=horizontal-single]) .container{display:grid;grid-template-areas:"items" "content";gap:.5rem var(--calcite-stepper-bar-gap, var(--calcite-internal-stepper-item-spacing-unit-s))}:host([layout=horizontal][scale=s]) .container,:host([layout=horizontal-single][scale=s]) .container{gap:.25rem var(--calcite-stepper-bar-gap, var(--calcite-internal-stepper-item-spacing-unit-s))}:host([layout=horizontal][scale=l]) .container,:host([layout=horizontal-single][scale=l]) .container{gap:.75rem var(--calcite-stepper-bar-gap, var(--calcite-internal-stepper-item-spacing-unit-s))}:host([layout=horizontal]) .container.single-view{display:flex;grid-template-columns:none}.action-icon{position:relative;display:flex;flex-grow:0;block-size:var(--calcite-internal-stepper-action-block-size);inline-size:var(--calcite-internal-stepper-action-inline-size)}.action-container{position:absolute;display:flex;justify-content:space-between;padding-block:.25rem;inline-size:100%}.step-bar{display:flex;block-size:100%;inline-size:100%}.step-bar-container{position:absolute;display:flex;align-items:flex-start;justify-content:space-between;block-size:.125rem;inline-size:100%;gap:var(--calcite-stepper-bar-gap, var(--calcite-internal-step-bar-gap, .5rem))}.step-bar--inactive{fill:var(--calcite-stepper-bar-inactive-fill-color, var(--calcite-color-border-3, #dfdfdf));fill-opacity:1;block-size:100%}.step-bar--active{fill:var(--calcite-stepper-bar-active-fill-color, var(--calcite-color-brand))}.step-bar--complete{fill:var(--calcite-stepper-bar-complete-fill-color, var(--calcite-color-brand));fill-opacity:.5}.step-bar--error{fill:var(--calcite-stepper-bar-error-fill-color, var(--calcite-color-status-danger))}.step-bar--disabled{opacity:.5}:host([hidden]){display:none}[hidden]{display:none}`;
class Stepper extends LitElement {
constructor() {
super();
this.enabledItems = [];
this.guid = `calcite-stepper-action-${guid()}`;
this.itemMap = /* @__PURE__ */ new Map();
this.items = [];
this.multipleViewMode = false;
this.mutationObserver = createObserver("mutation", () => this.updateItems());
this.messages = useT9n();
this.icon = false;
this.layout = "horizontal";
this.numbered = false;
this.scale = "m";
this.selectedItem = null;
this.calciteInternalStepperItemChange = createEvent({
cancelable: false
});
this.calciteStepperChange = createEvent({ cancelable: false });
this.calciteStepperItemChange = createEvent({ cancelable: false });
this.listen("calciteInternalStepperItemKeyEvent", this.calciteInternalStepperItemKeyEvent);
this.listen("calciteInternalStepperItemRegister", this.registerItem);
this.listen("calciteInternalStepperItemSelect", this.updateItem);
this.listen("calciteStepperItemSelect", this.handleItemSelect);
}
static {
this.properties = { currentActivePosition: [16, {}, { state: true }], icon: [7, {}, { reflect: true, type: Boolean }], layout: [3, {}, { reflect: true }], messageOverrides: [0, {}, { attribute: false }], numbered: [7, {}, { reflect: true, type: Boolean }], numberingSystem: [3, {}, { reflect: true }], scale: [3, {}, { reflect: true }], selectedItem: [0, {}, { attribute: false }] };
}
static {
this.styles = styles;
}
async endStep() {
const enabledStepIndex = this.getEnabledStepIndex(this.items.length - 1, "previous");
if (typeof enabledStepIndex !== "number") {
return;
}
this.updateStep(enabledStepIndex);
}
async goToStep(step) {
const position = step - 1;
if (this.currentActivePosition !== position) {
this.updateStep(position);
}
}
async nextStep() {
const enabledStepIndex = this.getEnabledStepIndex(this.currentActivePosition + 1, "next");
if (typeof enabledStepIndex !== "number") {
return;
}
this.updateStep(enabledStepIndex);
}
async prevStep() {
const enabledStepIndex = this.getEnabledStepIndex(this.currentActivePosition - 1, "previous");
if (typeof enabledStepIndex !== "number") {
return;
}
this.updateStep(enabledStepIndex);
}
async startStep() {
const enabledStepIndex = this.getEnabledStepIndex(0, "next");
if (typeof enabledStepIndex !== "number") {
return;
}
this.updateStep(enabledStepIndex);
}
connectedCallback() {
super.connectedCallback();
this.mutationObserver?.observe(this.el, { childList: true });
this.updateItems();
}
willUpdate(changes) {
if (changes.has("icon") && (this.hasUpdated || this.icon !== false) || changes.has("layout") && (this.hasUpdated || this.layout !== "horizontal") || changes.has("numbered") && (this.hasUpdated || this.numbered !== false) || changes.has("scale") && (this.hasUpdated || this.scale !== "m")) {
this.updateItems();
this.determineActiveStepper();
}
if (changes.has("numberingSystem")) {
this.setStepperItemNumberingSystem();
}
if (changes.has("currentActivePosition")) {
requestAnimationFrame(() => {
this.determineActiveStepper();
});
}
}
loaded() {
if (typeof this.currentActivePosition !== "number") {
const enabledStepIndex = this.getFirstEnabledStepperPosition();
if (enabledStepIndex === 0) {
this.currentActivePosition = enabledStepIndex;
}
this.calciteInternalStepperItemChange.emit({
position: enabledStepIndex
});
}
}
disconnectedCallback() {
super.disconnectedCallback();
this.mutationObserver?.disconnect();
}
calciteInternalStepperItemKeyEvent(event) {
const item = event.detail.item;
const itemToFocus = event.target;
switch (item.key) {
case "ArrowDown":
case "ArrowRight":
focusElementInGroup(this.enabledItems, itemToFocus, "next");
break;
case "ArrowUp":
case "ArrowLeft":
focusElementInGroup(this.enabledItems, itemToFocus, "previous");
break;
case "Home":
focusElementInGroup(this.enabledItems, itemToFocus, "first");
break;
case "End":
focusElementInGroup(this.enabledItems, itemToFocus, "last");
break;
}
event.stopPropagation();
}
registerItem(event) {
const item = event.target;
const { content, position } = event.detail;
this.itemMap.set(item, { position, content });
this.enabledItems = this.filterItems();
event.stopPropagation();
}
updateItem(event) {
const { position } = event.detail;
if (typeof position === "number") {
this.currentActivePosition = position;
this.selectedItem = event.target;
}
this.calciteInternalStepperItemChange.emit({
position
});
}
handleItemSelect() {
this.emitItemSelect();
}
emitItemSelect() {
this.calciteStepperItemChange.emit();
this.calciteStepperChange.emit();
}
updateItems() {
this.el.querySelectorAll("calcite-stepper-item").forEach((item) => {
item.icon = this.icon;
item.numbered = this.numbered;
item.layout = this.layout;
item.scale = this.scale;
});
}
determineActiveStepper() {
const { items } = this;
if (items.length < 2) {
return;
}
const { currentActivePosition, layout } = this;
this.multipleViewMode = layout !== "horizontal-single";
items.forEach((item, index) => {
item.itemHidden = layout === "horizontal-single" && index !== (currentActivePosition || 0);
});
}
getEnabledStepIndex(startIndex, direction = "next") {
const { items, currentActivePosition } = this;
let newIndex = startIndex;
while (items[newIndex]?.disabled && this.layout !== "horizontal-single") {
newIndex = newIndex + (direction === "previous" ? -1 : 1);
}
return newIndex !== currentActivePosition && newIndex < items.length && newIndex >= 0 ? newIndex : null;
}
updateStep(position) {
this.currentActivePosition = position;
this.calciteInternalStepperItemChange.emit({
position
});
}
filterItems() {
return this.items.filter((item) => !item.disabled && !isHidden(item));
}
setStepperItemNumberingSystem() {
this.items.forEach((item) => {
item.numberingSystem = this.numberingSystem;
});
}
handleActionClick(event) {
const currentActivePosition = this.currentActivePosition;
const target = event.target;
if (target.getAttribute("data-position") === "start") {
this.prevStep();
} else {
this.nextStep();
}
if (typeof this.currentActivePosition === "number" && currentActivePosition !== this.currentActivePosition && !this.items[this.currentActivePosition].disabled) {
this.emitItemSelect();
}
}
getFirstEnabledStepperPosition() {
const enabledStepIndex = this.items.findIndex((item) => !item.disabled);
if (enabledStepIndex > -1) {
return enabledStepIndex;
}
return 0;
}
setContainerEl(el) {
this.containerEl = el;
}
handleDefaultSlotChange(event) {
const items = slotChangeGetAssignedElements(event).filter((el) => el?.tagName === "CALCITE-STEPPER-ITEM" && !isHidden(el));
this.items = items;
const spacing = Array(items.length).fill("1fr").join(" ");
this.containerEl.style.gridTemplateAreas = spacing;
this.containerEl.style.gridTemplateColumns = spacing;
this.setStepperItemNumberingSystem();
}
render() {
this.el.ariaLabel = this.messages.label;
this.el.role = "region";
return html$1`<div class=${safeClassMap({ container: true, [CSS$1.singleView]: this.layout === "horizontal-single" })} ${ref(this.setContainerEl)}>${this.layout === "horizontal-single" && html$1`<div class=${safeClassMap({ [CSS$1.stepBarContainer]: true })}>${this.items.map((item, index) => StepBar({ active: index === this.currentActivePosition, complete: item.complete && index !== this.currentActivePosition && !item.error, disabled: item.disabled && index !== this.currentActivePosition, error: item.error && index !== this.currentActivePosition }))}</div>` || ""}${this.layout === "horizontal-single" && html$1`<div class=${safeClassMap({ [CSS$1.actionContainer]: true })}>${this.renderAction("start")}${this.renderAction("end")}</div>` || ""}<slot @slotchange=${this.handleDefaultSlotChange}></slot></div>`;
}
renderAction(position) {
const isPositionStart = position === "start";
const path = isPositionStart ? "chevron-left" : "chevron-right";
const { currentActivePosition, multipleViewMode, layout } = this;
const totalItems = this.items.length;
const id = `${this.guid}-${isPositionStart ? "start" : "end"}`;
return layout === "horizontal-single" && !multipleViewMode ? html$1`<calcite-action alignment=center appearance=transparent class=${safeClassMap({
[CSS$1.actionIcon]: true
})} compact data-position=${position ?? nothing} .disabled=${currentActivePosition === 0 && isPositionStart || currentActivePosition === totalItems - 1 && !isPositionStart} .icon=${path} icon-flip-rtl id=${id ?? nothing} @click=${this.handleActionClick} .scale=${this.scale} .text=${isPositionStart ? this.messages.previousStep : this.messages.nextStep}></calcite-action>` : null;
}
}
customElement("calcite-stepper", Stepper);
export {
Stepper
};