UNPKG

@esri/calcite-components

Version:

Web Components for Esri's Calcite Design System.

159 lines (158 loc) • 6.6 kB
/*! 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 };