@esri/calcite-components
Version:
Web Components for Esri's Calcite Design System.
159 lines (158 loc) • 6.6 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 } from "lit";
import { LitElement, safeClassMap } from "@arcgis/lumina";
import { c as createObserver } from "../../chunks/observers.js";
import { c as componentFocusable } from "../../chunks/component.js";
import { z as whenAnimationDone } from "../../chunks/dom.js";
import { css } from "@lit/reactive-element/css-tag.js";
const CSS = {
frame: "frame",
frameAdvancing: "frame--advancing",
frameRetreating: "frame--retreating"
};
const styles = css`:host{box-sizing:border-box;background-color:var(--calcite-color-foreground-1);color:var(--calcite-color-text-2);font-size:var(--calcite-font-size--1)}:host *{box-sizing:border-box}:host{position:relative;display:flex;inline-size:100%;flex:1 1 auto;align-items:stretch;overflow:hidden;background-color:transparent}:host .frame{position:relative;margin:0;display:flex;inline-size:100%;flex:1 1 auto;flex-direction:column;align-items:stretch;padding:0;animation-name:none;animation-duration:var(--calcite-animation-timing);background-color:var(--calcite-flow-background-color)}:host ::slotted(*){display:none;block-size:100%}:host ::slotted(*[selected]){display:flex}:host ::slotted(.calcite-match-height:last-child){display:flex;flex:1 1 auto;overflow:hidden}:host .frame--advancing{animation-name:calcite-frame-advance}:host .frame--retreating{animation-name:calcite-frame-retreat}@keyframes calcite-frame-advance{0%{--tw-bg-opacity: .5;transform:translate3d(50px,0,0)}to{--tw-bg-opacity: 1;transform:translateZ(0)}}@keyframes calcite-frame-retreat{0%{--tw-bg-opacity: .5;transform:translate3d(-50px,0,0)}to{--tw-bg-opacity: 1;transform:translateZ(0)}}:host([hidden]){display:none}[hidden]{display:none}`;
class Flow extends LitElement {
constructor() {
super();
this.itemMutationObserver = createObserver("mutation", () => this.updateItemsAndProps());
this.items = [];
this.selectedIndex = -1;
this.flowDirection = "standby";
this.listen("calciteInternalFlowItemChange", this.handleCalciteInternalFlowItemChange);
this.listen("calciteFlowItemBack", this.handleItemBackClick);
}
static {
this.properties = { flowDirection: [16, {}, { state: true }], customItemSelectors: 1 };
}
static {
this.styles = styles;
}
async back() {
const { items, selectedIndex } = this;
const selectedItem = items[selectedIndex];
const nextSelectedItem = items[selectedIndex - 1];
if (!selectedItem || !nextSelectedItem) {
return;
}
const beforeBack = selectedItem.beforeBack ? selectedItem.beforeBack : () => Promise.resolve();
try {
await beforeBack.call(selectedItem);
} catch {
return;
}
selectedItem.selected = false;
nextSelectedItem.selected = true;
return nextSelectedItem;
}
async setFocus() {
await componentFocusable(this);
const { items } = this;
const selectedItem = items[this.selectedIndex];
return selectedItem?.setFocus();
}
connectedCallback() {
super.connectedCallback();
this.itemMutationObserver?.observe(this.el, { childList: true, subtree: true });
}
willUpdate(changes) {
if (changes.has("flowDirection") && (this.hasUpdated || this.flowDirection !== "standby")) {
this.handleFlowDirectionChange(this.flowDirection);
}
}
loaded() {
this.updateItemsAndProps();
}
disconnectedCallback() {
super.disconnectedCallback();
this.itemMutationObserver?.disconnect();
}
async handleFlowDirectionChange(flowDirection) {
if (flowDirection === "standby") {
return;
}
await whenAnimationDone(this.frameEl, flowDirection === "retreating" ? "calcite-frame-retreat" : "calcite-frame-advance");
this.resetFlowDirection();
}
handleCalciteInternalFlowItemChange(event) {
event.stopPropagation();
this.updateFlowProps();
}
async handleItemBackClick(event) {
if (event.defaultPrevented) {
return;
}
await this.back();
return this.setFocus();
}
resetFlowDirection() {
this.flowDirection = "standby";
}
getFlowDirection(oldSelectedIndex, newSelectedIndex) {
const allowRetreatingDirection = oldSelectedIndex > 0;
const allowAdvancingDirection = oldSelectedIndex > -1 && newSelectedIndex > 0;
if (!allowAdvancingDirection && !allowRetreatingDirection) {
return "standby";
}
return newSelectedIndex < oldSelectedIndex ? "retreating" : "advancing";
}
updateItemsAndProps() {
const { customItemSelectors, el } = this;
const newItems = Array.from(el.querySelectorAll(`calcite-flow-item${customItemSelectors ? `,${customItemSelectors}` : ""}`)).filter((flowItem) => flowItem.closest("calcite-flow") === el);
this.items = newItems;
this.ensureSelectedFlowItemExists();
this.updateFlowProps();
}
updateFlowProps() {
const { selectedIndex, items } = this;
const foundSelectedIndex = this.findSelectedFlowItemIndex(items);
items.forEach((flowItem, index) => {
const currentlySelected = index === foundSelectedIndex;
if (!currentlySelected) {
flowItem.menuOpen = false;
}
flowItem.showBackButton = currentlySelected && foundSelectedIndex > 0;
});
if (foundSelectedIndex === -1) {
return;
}
if (selectedIndex !== foundSelectedIndex) {
this.flowDirection = this.getFlowDirection(selectedIndex, foundSelectedIndex);
}
this.selectedIndex = foundSelectedIndex;
}
findSelectedFlowItemIndex(items) {
const selectedItem = items.slice(0).reverse().find((item) => !!item.selected);
return items.indexOf(selectedItem);
}
ensureSelectedFlowItemExists() {
const { items } = this;
const foundSelectedIndex = this.findSelectedFlowItemIndex(items);
if (foundSelectedIndex !== -1) {
return;
}
const lastItem = items[items.length - 1];
if (lastItem) {
lastItem.selected = true;
}
}
setFrameEl(el) {
this.frameEl = el;
}
render() {
const { flowDirection } = this;
const frameDirectionClasses = {
[CSS.frame]: true,
[CSS.frameAdvancing]: flowDirection === "advancing",
[CSS.frameRetreating]: flowDirection === "retreating"
};
return html`<div class=${safeClassMap(frameDirectionClasses)} ${ref(this.setFrameEl)}><slot></slot></div>`;
}
}
customElement("calcite-flow", Flow);
export {
Flow
};