/* COPYRIGHT Esri - https://js.arcgis.com/5.1/LICENSE.txt */
import { D as DEBOUNCE, c as customElement } from "../../chunks/runtime.js";
import { debounce } from "es-toolkit";
import { css, html } from "lit";
import { LitElement, createEvent, safeClassMap } from "@arcgis/lumina";
import { c as createObserver } from "../../chunks/observers.js";
import { e as getRootNode, a as slotChangeGetAssignedElements } from "../../chunks/dom.js";
import { g as guid } from "../../chunks/guid.js";
import { u as useSetFocus } from "../../chunks/useSetFocus.js";
import { u as useCancelable } from "../../chunks/useCancelable.js";
import { u as useInteractive } from "../../chunks/useInteractive.js";
import { u as useSortable } from "../../chunks/useSortable.js";
import { i as isBlock } from "../../chunks/resources5.js";
const CSS = {
  container: "container",
  groupContainer: "group-container",
  scrim: "scrim",
  assistiveText: "assistive-text"
};
const blockGroupSelector = "calcite-block-group";
const blockSelector = "calcite-block";
const styles = css`:host([disabled]){cursor:default;-webkit-user-select:none;user-select:none;opacity:var(--calcite-opacity-disabled)}:host([disabled]) *,:host([disabled]) ::slotted(*){pointer-events:none}:host{display:block}.container{position:relative}.assistive-text{position:absolute;inline-size:1px;block-size:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}:host([hidden]){display:none}[hidden]{display:none}:host([disabled]) ::slotted([calcite-hydrated][disabled]),:host([disabled]) [calcite-hydrated][disabled]{opacity:1}.interaction-container{display:contents}`;
function updateBlockChildren(blockChildren) {
  blockChildren.forEach((block) => {
    block.setPosition = blockChildren.indexOf(block) + 1;
    block.setSize = blockChildren.length;
  });
}
class BlockGroup extends LitElement {
  constructor() {
    super();
    this.dragSelector = blockSelector;
    this.handleSelector = "calcite-sort-handle";
    this.mutationObserver = createObserver("mutation", () => {
      this.updateBlockItemsDebounced();
    });
    this.blockAndGroups = [];
    this.cancelable = useCancelable()(this);
    this.focusSetter = useSetFocus()(this);
    this.sortable = useSortable()(this);
    this.updateBlockItemsDebounced = debounce(this.updateBlockItems, DEBOUNCE.nextTick);
    this.interactiveContainer = useInteractive(this);
    this.sortHandleMenuItems = [];
    this.disabled = false;
    this.dragEnabled = false;
    this.loading = false;
    this.scale = "m";
    this.sortDisabled = false;
    this.calciteBlockGroupDragEnd = createEvent({ cancelable: false });
    this.calciteBlockGroupDragStart = createEvent({ cancelable: false });
    this.calciteBlockGroupMoveHalt = createEvent({ cancelable: false });
    this.calciteBlockGroupOrderChange = createEvent({ cancelable: false });
    this.listen("calciteInternalAssistiveTextChange", this.handleCalciteInternalAssistiveTextChange);
    this.listen("calciteBlockSortHandleBeforeOpen", this.updateBlockItemsDebounced);
    this.listen("calciteSortHandleReorder", this.handleSortReorder);
    this.listen("calciteSortHandleMove", this.handleSortMove);
    this.listen("calciteSortHandleAdd", this.handleSortAdd);
  }
  static {
    this.properties = { assistiveText: [16, {}, { state: true }], sortHandleMenuItems: [16, {}, { state: true }], canPull: [0, {}, { attribute: false }], canPut: [0, {}, { attribute: false }], disabled: [7, {}, { reflect: true, type: Boolean }], dragEnabled: [7, {}, { reflect: true, type: Boolean }], group: [3, {}, { reflect: true }], label: 1, loading: [7, {}, { reflect: true, type: Boolean }], scale: [3, {}, { reflect: true }], sortDisabled: [7, {}, { reflect: true, type: Boolean }] };
  }
  static {
    this.styles = styles;
  }
  emitOrderChangeEvent(detail) {
    this.calciteBlockGroupOrderChange.emit(detail);
  }
  async setFocus(options) {
    return this.focusSetter(() => this.el, options);
  }
  connectedCallback() {
    super.connectedCallback();
    this.connectObserver();
    this.updateBlockItemsDebounced();
    this.sortable.reset();
    this.setParentBlockGroup();
    this.cancelable.add(this.updateBlockItemsDebounced);
  }
  willUpdate(changes) {
    if (changes.has("group") || changes.has("canPull") && this.hasUpdated || changes.has("canPut") && this.hasUpdated || changes.has("dragEnabled") && (this.hasUpdated || this.dragEnabled !== false) || changes.has("sortDisabled") && (this.hasUpdated || this.sortDisabled !== false)) {
      this.updateBlockItemsDebounced();
    }
    if (changes.has("scale") && this.hasUpdated) {
      this.updateBlockAndGroupScale();
    }
  }
  disconnectedCallback() {
    super.disconnectedCallback();
    this.disconnectObserver();
  }
  updateBlockItems() {
    this.updateGroupItems();
    const { dragEnabled, el, sortDisabled, sortHandleMenuItems } = this;
    const items = Array.from(this.el.querySelectorAll(blockSelector));
    const fromEl = el;
    const fromElItems = Array.from(fromEl.children).filter(isBlock);
    items.forEach((item) => {
      if (item.closest(blockGroupSelector) === el) {
        item.moveToItems = sortHandleMenuItems.filter((moveToItem) => this.validateSortMenuItem({
          type: "move",
          fromEl,
          toEl: moveToItem.element,
          dragEl: item,
          newIndex: 0,
          oldIndex: fromElItems.indexOf(item)
        }));
        item.addToItems = this.sortHandleMenuItems.filter((moveToItem) => this.validateSortMenuItem({
          type: "add",
          fromEl,
          toEl: moveToItem.element,
          dragEl: item,
          newIndex: 0,
          oldIndex: fromElItems.indexOf(item)
        }));
        item.dragHandle = dragEnabled;
        item.sortDisabled = sortDisabled;
      }
    });
    this.sortable.reset();
  }
  updateGroupItems() {
    const { el, group } = this;
    const rootNode = getRootNode(el);
    const blockGroups = group ? Array.from(rootNode.querySelectorAll(`${blockGroupSelector}[group="${group}"]`)).filter((blockGroup) => !blockGroup.disabled && blockGroup.dragEnabled) : [];
    this.sortHandleMenuItems = blockGroups.map((element) => ({
      element,
      label: element.label ?? element.id,
      id: guid()
    }));
  }
  handleCalciteInternalAssistiveTextChange(event) {
    this.assistiveText = event.detail.message;
    event.stopPropagation();
  }
  handleSortReorder(event) {
    if (this.parentBlockGroupEl || event.defaultPrevented) {
      return;
    }
    event.preventDefault();
    this.handleReorder(event);
  }
  handleSortAdd(event) {
    if (this.parentBlockGroupEl || event.defaultPrevented) {
      return;
    }
    event.preventDefault();
    this.handleAdd(event);
  }
  handleSortMove(event) {
    if (this.parentBlockGroupEl || event.defaultPrevented) {
      return;
    }
    event.preventDefault();
    this.handleMove(event);
  }
  connectObserver() {
    this.mutationObserver?.observe(this.el, { childList: true, subtree: true });
  }
  disconnectObserver() {
    this.mutationObserver?.disconnect();
  }
  onGlobalDragStart() {
    this.disconnectObserver();
  }
  onGlobalDragEnd() {
    this.connectObserver();
  }
  onDragEnd(detail) {
    this.calciteBlockGroupDragEnd.emit(detail);
  }
  onDragStart(detail) {
    detail.dragEl.sortHandleOpen = false;
    this.calciteBlockGroupDragStart.emit(detail);
  }
  onDragSort(detail) {
    this.setParentBlockGroup();
    this.updateBlockItemsDebounced();
    this.calciteBlockGroupOrderChange.emit(detail);
  }
  setParentBlockGroup() {
    this.parentBlockGroupEl = this.el.parentElement?.closest(blockGroupSelector) || void 0;
  }
  handleDefaultSlotChange(event) {
    const blockChildren = [];
    this.blockAndGroups = slotChangeGetAssignedElements(event).filter((el) => {
      if (isBlock(el)) {
        blockChildren.push(el);
      }
      return el.matches(blockSelector) || el.matches(blockGroupSelector);
    });
    updateBlockChildren(blockChildren);
    this.updateBlockAndGroupScale();
  }
  updateBlockAndGroupScale() {
    this.blockAndGroups.forEach((el) => {
      el.scale = this.scale;
    });
  }
  validateSortMenuItem({ fromEl, toEl, dragEl, newIndex, oldIndex, type }) {
    if (!fromEl || !toEl || toEl === fromEl || dragEl.contains(toEl)) {
      return false;
    }
    const canPull = fromEl.canPull?.({
      toEl,
      fromEl,
      dragEl,
      newIndex,
      oldIndex
    }) ?? true;
    const canPut = toEl.canPut?.({
      toEl,
      fromEl,
      dragEl,
      newIndex,
      oldIndex
    }) ?? true;
    return (type === "add" ? canPull === "clone" : canPull === true) && canPut;
  }
  handleAdd(event) {
    const { addTo } = event.detail;
    const dragEl = event.target;
    const fromEl = dragEl?.parentElement;
    const toEl = addTo.element;
    const fromElItems = Array.from(fromEl.children).filter(isBlock);
    const oldIndex = fromElItems.indexOf(dragEl);
    const newIndex = 0;
    if (!this.validateSortMenuItem({ type: "add", fromEl, toEl, dragEl, newIndex, oldIndex })) {
      return;
    }
    dragEl.sortHandleOpen = false;
    this.disconnectObserver();
    const newEl = dragEl.cloneNode();
    toEl.prepend(newEl);
    this.updateBlockItemsDebounced();
    this.connectObserver();
    const eventDetail = {
      dragEl,
      fromEl,
      toEl,
      newIndex,
      oldIndex
    };
    this.calciteBlockGroupOrderChange.emit(eventDetail);
    toEl.emitOrderChangeEvent(eventDetail);
  }
  handleMove(event) {
    const { moveTo } = event.detail;
    const dragEl = event.target;
    const fromEl = dragEl?.parentElement;
    const toEl = moveTo.element;
    const fromElItems = Array.from(fromEl.children).filter(isBlock);
    const oldIndex = fromElItems.indexOf(dragEl);
    const newIndex = 0;
    if (!this.validateSortMenuItem({ type: "move", fromEl, toEl, dragEl, newIndex, oldIndex })) {
      return;
    }
    dragEl.sortHandleOpen = false;
    this.disconnectObserver();
    toEl.prepend(dragEl);
    this.updateBlockItemsDebounced();
    this.connectObserver();
    const eventDetail = {
      dragEl,
      fromEl,
      toEl,
      newIndex,
      oldIndex
    };
    this.calciteBlockGroupOrderChange.emit(eventDetail);
    toEl.emitOrderChangeEvent(eventDetail);
  }
  handleReorder(event) {
    const { reorder } = event.detail;
    const dragEl = event.target;
    const parentEl = dragEl?.parentElement;
    if (!parentEl) {
      return;
    }
    dragEl.sortHandleOpen = false;
    const sameParentItems = Array.from(parentEl.children).filter(isBlock);
    const lastIndex = sameParentItems.length - 1;
    const oldIndex = sameParentItems.indexOf(dragEl);
    let newIndex = oldIndex;
    switch (reorder) {
      case "top":
        newIndex = 0;
        break;
      case "bottom":
        newIndex = lastIndex;
        break;
      case "up":
        newIndex = oldIndex === 0 ? 0 : oldIndex - 1;
        break;
      case "down":
        newIndex = oldIndex === lastIndex ? lastIndex : oldIndex + 1;
        break;
    }
    this.disconnectObserver();
    const referenceEl = reorder === "up" || reorder === "top" ? sameParentItems[newIndex] : sameParentItems[newIndex].nextSibling;
    parentEl.insertBefore(dragEl, referenceEl);
    this.updateBlockItemsDebounced();
    this.connectObserver();
    this.calciteBlockGroupOrderChange.emit({
      dragEl,
      fromEl: parentEl,
      toEl: parentEl,
      newIndex,
      oldIndex
    });
  }
  render() {
    const { loading, label } = this;
    return this.interactiveContainer({ disabled: this.disabled, children: html`<div class=${safeClassMap(CSS.container)}>${this.dragEnabled ? html`<span aria-live=assertive class=${safeClassMap(CSS.assistiveText)}>${this.assistiveText}</span>` : null}${loading ? html`<calcite-scrim class=${safeClassMap(CSS.scrim)} .loading=${loading}></calcite-scrim>` : null}<div .ariaBusy=${loading} .ariaLabel=${label || ""} class=${safeClassMap(CSS.groupContainer)} role=group><slot @slotchange=${this.handleDefaultSlotChange}></slot></div></div>` });
  }
}
customElement("calcite-block-group", BlockGroup);
export {
  BlockGroup
};
