import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
import { useMemo, forwardRef, createElement, createContext, useRef, useId, useState, useContext, useEffect, useCallback } from 'react';
import { C as Chip } from './Chip-CxgryK86.js';
import { d as ToolbarItemWrapper, u as useToolbarSize, T as ToolbarButtonToggle, b as ToolbarContext, g as getToolbarElements, a as updateToolbarItemsTabIndex } from './ToolbarButtonToggle-3xbnm1Qr.js';
import { S as SvgKeyboardArrowDown } from './keyboard_arrow_down-C8WQ38p1.js';
import { S as SvgEvent, a as DateModeToFormatMap } from './TimezoneMessage-BrKB_psP.js';
import { c as cx } from './index-De1g9FRV.js';
import { B as Button } from './Button-BNzCI47m.js';
import { M as MultiSelectField, a as MultiSelectFieldSync } from './MultiSelectFieldSync-B1tkEtft.js';
import { M as MultiSelectMenu, a as MultiSelectMenuSync } from './MultiSelectMenuSync-Deki_z-0.js';
import { S as SelectField, a as SelectFieldSync } from './SelectFieldSync-VShqP5J0.js';
import { S as SelectMenu, a as SelectMenuSync } from './SelectMenuSync-BDx1yhZT.js';
import { T as TreeSelectField, a as TreeSelectFieldSync } from './TreeSelectFieldSync-CdtC8d3Q.js';
import { a as TreeSelectMenu, T as TreeSelectMenuSync } from './TreeSelectMenuSync-CPuQWUNU.js';
import { C as Checkbox } from './Checkbox-zz9TyZWn.js';
import { a as OptionsPopover } from './useAdaptiveView-AvsDkChF.js';
import { M as MenuFooter } from './MenuFooter-Ck9L599M.js';
import { D as DateTime } from './luxon-wpz4A-OQ.js';
import { u as useDateFieldSingleConversion, a as useDateFieldSingleState, M as MaskedDateInput, b as DateFieldSingleCalendar, D as DateFieldSingle } from './DateFieldSingle-CgMPTi1v.js';
import { F as Flex } from './Flex-Bb3iHExM.js';
import { u as useConfirmationDraft } from './confirmationTypes-CG7xl50f.js';
import { D as Dialog } from './Dialog-BxulNN8n.js';
import { u as useDateFieldRangeConversion, a as useDateFieldRangeState, M as MaskedDateRangeInput, b as DateFieldRangeCalendar, D as DateFieldRange } from './DateFieldRange-CP7QgS6P.js';
import { w as warnOnce } from './warnOnce-Y9PRHcU4.js';
import { F as FieldLabel } from './FieldLabel-Cm5A1Jcx.js';
import { G as Grid } from './Grid-ho1pGJ5L.js';
import { N as NumberField } from './NumberField-CjC6KHKl.js';
import { T as Text } from './Text-mDcQHC2U.js';
import { T as TextField } from './TextField-WQTlqKso.js';
import { S as SvgClose } from './close-DZj38AEh.js';
import { a as SvgSearch, s as styles$1 } from './SearchField-X4B7f23E.js';
import { t as textFieldStyles } from './TextField.module-DklyLNKz.js';
import { I as Icon } from './Icon-B4uCvMU9.js';
import { useTrackingId } from './useTrackingId.js';
import { R as Radio } from './Radio-D9w_-JYw.js';

import './filter-state.css';const FilterItemWrapper = ({ children }) => {
  const props = useMemo(
    () => ({
      item: {
        itemType: "button",
        itemProps: {
          children: null,
          "aria-hidden": true
        }
      },
      children
    }),
    [children]
  );
  return /* @__PURE__ */ jsx(ToolbarItemWrapper, { ...props });
};

const styles = {
	"filter-button-trigger": "_filter-button-trigger_1kmgt_1",
	"filter-button-trigger--selected": "_filter-button-trigger--selected_1kmgt_5",
	"filter-drawer-trigger": "_filter-drawer-trigger_1kmgt_25",
	"filter-drawer-trigger--chipped": "_filter-drawer-trigger--chipped_1kmgt_31",
	"filter-numeric-range-separator": "_filter-numeric-range-separator_1kmgt_63"
};

const FilterTriggerButton = forwardRef(function FilterTriggerButton2({ filterId, label, isSelected, icon = "dropdown", className, ...rest }, ref) {
  const toolbarSize = useToolbarSize();
  const iconOptions = icon === "calendar" ? { before: SvgEvent } : { after: SvgKeyboardArrowDown };
  const buttonClass = cx(
    styles["filter-button-trigger"],
    {
      [styles["filter-button-trigger--selected"]]: isSelected
    },
    className
  );
  return /* @__PURE__ */ jsx(
    Button,
    {
      ref,
      appearance: "ghost",
      size: toolbarSize,
      icon: iconOptions,
      "data-id": filterId,
      "data-anv": "toolbar-button",
      className: buttonClass,
      ...rest,
      children: label
    }
  );
});

const isSelected$a = (filter) => !!filter.selectedOptions && filter.selectedOptions.length > 0;
const formatLabel$b = (filter) => {
  const count = filter.selectedOptions?.length ?? 0;
  if (count === 0) return filter.label;
  const countLabel = count.toString();
  return /* @__PURE__ */ jsxs(Fragment, { children: [
    filter.label,
    /* @__PURE__ */ jsx(
      Chip,
      {
        label: countLabel,
        color: "#0265DC",
        size: "small",
        "aria-label": `${countLabel} selected items`
      }
    )
  ] });
};
const passThroughMenuProps$5 = (filter) => {
  const {
    id: _id,
    label: _label,
    type: _type,
    selectedOptions: _selectedOptions,
    drawerOnly: _drawerOnly,
    ...rest
  } = filter;
  return rest;
};
const asyncMultiSelectAdapter = {
  getValue: (filter) => filter.selectedOptions ?? [],
  setValue: (filter, value) => ({ ...filter, selectedOptions: value }),
  reset: (filter) => ({ ...filter, selectedOptions: [] }),
  isActive: isSelected$a,
  preserveState: (newFilter, existingFilter) => ({
    ...newFilter,
    selectedOptions: existingFilter.selectedOptions
  }),
  // No items array to rebind against — the selectedOptions are canonical.
  cloneWithItemRefs: (filter) => ({ ...filter }),
  renderBarControl: ({ filter, updateFilter, controlledFiltering }) => /* @__PURE__ */ jsx(FilterItemWrapper, { children: /* @__PURE__ */ jsx(
    MultiSelectMenu,
    {
      ...passThroughMenuProps$5(filter),
      id: filter.id,
      label: filter.label,
      value: filter.selectedOptions ?? [],
      onSelectedOptionsChange: (options) => updateFilter(filter.id, options, true),
      confirmation: controlledFiltering,
      clear: {
        onClick: () => updateFilter(filter.id, [], true)
      },
      trigger: (triggerProps) => /* @__PURE__ */ jsx(
        FilterTriggerButton,
        {
          ...triggerProps,
          filterId: filter.id,
          label: formatLabel$b(filter),
          isSelected: isSelected$a(filter)
        }
      )
    }
  ) }, filter.id),
  renderDrawer: ({ originalFilter, draftFilter, onDraftChange }) => /* @__PURE__ */ createElement(
    MultiSelectField,
    {
      ...passThroughMenuProps$5(originalFilter),
      key: draftFilter.id,
      label: originalFilter.label,
      value: draftFilter.selectedOptions ?? [],
      onSelectedOptionsChange: (options) => onDraftChange(draftFilter.id, options)
    }
  ),
  formatLabel: formatLabel$b,
  isSelected: isSelected$a
};

const formatLabel$a = (filter) => {
  if (filter.selectedOption) {
    return `${filter.label}: ${filter.selectedOption.label}`;
  }
  return filter.label;
};
const isSelected$9 = (filter) => filter.selectedOption !== void 0;
const passThroughMenuProps$4 = (filter) => {
  const {
    id: _id,
    label: _label,
    type: _type,
    selectedOption: _selectedOption,
    drawerOnly: _drawerOnly,
    ...rest
  } = filter;
  return rest;
};
const asyncSelectAdapter = {
  getValue: (filter) => filter.selectedOption,
  setValue: (filter, value) => ({ ...filter, selectedOption: value }),
  reset: (filter) => ({ ...filter, selectedOption: void 0 }),
  isActive: isSelected$9,
  preserveState: (newFilter, existingFilter) => ({
    ...newFilter,
    selectedOption: existingFilter.selectedOption
  }),
  // No items array to rebind against — the selectedOption is canonical.
  cloneWithItemRefs: (filter) => ({ ...filter }),
  renderBarControl: ({ filter, updateFilter }) => /* @__PURE__ */ jsx(FilterItemWrapper, { children: /* @__PURE__ */ jsx(
    SelectMenu,
    {
      ...passThroughMenuProps$4(filter),
      id: filter.id,
      label: filter.label,
      value: filter.selectedOption ?? null,
      onSelectedOptionChange: (option) => updateFilter(filter.id, option ?? void 0, true),
      clear: {
        onClick: () => updateFilter(filter.id, void 0, true)
      },
      trigger: (triggerProps) => /* @__PURE__ */ jsx(
        FilterTriggerButton,
        {
          ...triggerProps,
          filterId: filter.id,
          label: formatLabel$a(filter),
          isSelected: isSelected$9(filter)
        }
      )
    }
  ) }, filter.id),
  renderDrawer: ({ originalFilter, draftFilter, onDraftChange }) => /* @__PURE__ */ createElement(
    SelectField,
    {
      ...passThroughMenuProps$4(originalFilter),
      key: draftFilter.id,
      label: originalFilter.label,
      value: draftFilter.selectedOption ?? null,
      onSelectedOptionChange: (option) => onDraftChange(draftFilter.id, option ?? void 0)
    }
  ),
  formatLabel: formatLabel$a,
  isSelected: isSelected$9
};

const isSelected$8 = (filter) => !!filter.selectedNodes && filter.selectedNodes.length > 0;
const formatLabel$9 = (filter) => {
  const count = filter.selectedNodes?.length ?? 0;
  if (count === 0) return filter.label;
  const countLabel = count.toString();
  return /* @__PURE__ */ jsxs(Fragment, { children: [
    filter.label,
    /* @__PURE__ */ jsx(
      Chip,
      {
        label: countLabel,
        color: "#0265DC",
        size: "small",
        "aria-label": `${countLabel} selected items`
      }
    )
  ] });
};
const passThroughMenuProps$3 = (filter) => {
  const {
    id: _id,
    label: _label,
    type: _type,
    selectedNodes: _selectedNodes,
    drawerOnly: _drawerOnly,
    ...rest
  } = filter;
  return rest;
};
const asyncTreeAdapter = {
  getValue: (filter) => filter.selectedNodes ?? [],
  setValue: (filter, value) => ({ ...filter, selectedNodes: value }),
  reset: (filter) => ({ ...filter, selectedNodes: [] }),
  isActive: isSelected$8,
  preserveState: (newFilter, existingFilter) => ({
    ...newFilter,
    selectedNodes: existingFilter.selectedNodes
  }),
  // No items array to rebind against — the selected node values are canonical.
  cloneWithItemRefs: (filter) => ({ ...filter }),
  renderBarControl: ({ filter, updateFilter, controlledFiltering }) => /* @__PURE__ */ jsx(FilterItemWrapper, { children: /* @__PURE__ */ jsx(
    TreeSelectMenu,
    {
      ...passThroughMenuProps$3(filter),
      id: filter.id,
      label: filter.label,
      value: filter.selectedNodes ?? [],
      onSelectedOptionsChange: (nodes) => updateFilter(filter.id, nodes, true),
      confirmation: controlledFiltering,
      clear: {
        onClick: () => updateFilter(filter.id, [], true),
        disabled: !isSelected$8(filter)
      },
      trigger: (triggerProps) => /* @__PURE__ */ jsx(
        FilterTriggerButton,
        {
          ...triggerProps,
          filterId: filter.id,
          label: formatLabel$9(filter),
          isSelected: isSelected$8(filter)
        }
      )
    }
  ) }, filter.id),
  renderDrawer: ({ originalFilter, draftFilter, onDraftChange }) => /* @__PURE__ */ createElement(
    TreeSelectField,
    {
      ...passThroughMenuProps$3(originalFilter),
      key: draftFilter.id,
      label: originalFilter.label,
      value: draftFilter.selectedNodes ?? [],
      onSelectedOptionsChange: (nodes) => onDraftChange(draftFilter.id, nodes)
    }
  ),
  formatLabel: formatLabel$9,
  isSelected: isSelected$8
};

const FilterToggleButton = ({
  id,
  checked,
  children,
  ...props
}) => {
  return /* @__PURE__ */ jsx(FilterItemWrapper, { children: /* @__PURE__ */ jsx(
    ToolbarButtonToggle,
    {
      id,
      checked,
      isFilter: true,
      ...props,
      className: styles["filter-button-trigger"],
      "data-anv": "toolbar-boolean-filter",
      children
    }
  ) });
};

const booleanAdapter = {
  getValue: (filter) => filter.checked,
  setValue: (filter, value) => ({ ...filter, checked: value }),
  reset: (filter) => ({ ...filter, checked: false }),
  isActive: (filter) => filter.checked,
  preserveState: (newFilter, existingFilter) => ({
    ...newFilter,
    checked: existingFilter.checked
  }),
  cloneWithItemRefs: (filter) => ({ ...filter }),
  renderBarControl: ({ filter, updateFilter }) => /* @__PURE__ */ jsx(
    FilterToggleButton,
    {
      id: filter.id,
      checked: filter.checked,
      onClick: () => updateFilter(filter.id, !filter.checked, true),
      children: filter.label
    },
    filter.id
  ),
  renderDrawer: ({ draftFilter, onDraftChange }) => /* @__PURE__ */ jsx(
    Checkbox,
    {
      label: draftFilter.label,
      checked: draftFilter.checked,
      onChange: (e) => onDraftChange(draftFilter.id, e?.target.checked ?? false)
    },
    draftFilter.id
  ),
  formatLabel: (filter) => filter.label,
  isSelected: (filter) => filter.checked
};

const FilterGroupContext = createContext({
  filterGroupRef: { current: null },
  filters: [],
  updateFilter: () => {
  },
  onFilterChange: () => {
  },
  controlledFiltering: false,
  associatedContent: "",
  showInlineFilters: false,
  drawerOnlyFilters: []
});

const hasChangedFilter = (a, b) => {
  if (Array.isArray(a) && Array.isArray(b)) {
    if (a.length !== b.length) return true;
    if (a.length === 0) return false;
    const aItems = a;
    const bItems = b;
    if (aItems[0] && "id" in aItems[0]) {
      const aIds = new Set(aItems.map((item) => item.id));
      return bItems.some(
        (item) => !aIds.has(item.id)
      );
    }
    return JSON.stringify(a) !== JSON.stringify(b);
  }
  if (a && b && typeof a === "object" && typeof b === "object" && "id" in a && "id" in b) {
    if (a.id !== b.id) return true;
    if ("value" in a && "value" in b) {
      return JSON.stringify(a.value) !== JSON.stringify(b.value);
    }
    return false;
  }
  return a !== b;
};

const FilterPopoverButton = (props) => {
  const { filter, label, isSelected, committedValue, children } = props;
  const commitOnSelect = props.commitOnSelect === true;
  const initialValue = commitOnSelect ? void 0 : props.initialValue;
  const keepOpenOnUncontrolledChange = !commitOnSelect && (props.keepOpenOnUncontrolledChange ?? false);
  const triggerRef = useRef(null);
  const popoverId = useId();
  const [isOpen, setIsOpen] = useState(false);
  const { updateFilter, controlledFiltering } = useContext(FilterGroupContext);
  const [draftValue, setDraftValue] = useState(initialValue);
  const draftValueRef = useRef(draftValue);
  useEffect(() => {
    draftValueRef.current = draftValue;
  }, [draftValue]);
  const prevIsOpenRef = useRef(isOpen);
  const prevCommittedValueRef = useRef(committedValue);
  useEffect(() => {
    if (commitOnSelect) return;
    const justOpened = isOpen && !prevIsOpenRef.current;
    prevIsOpenRef.current = isOpen;
    if (isOpen) {
      const shouldSync = justOpened || prevCommittedValueRef.current !== committedValue;
      if (shouldSync) {
        setDraftValue(committedValue);
      }
      prevCommittedValueRef.current = committedValue;
    }
  }, [isOpen, committedValue, commitOnSelect]);
  const closeAndRestoreFocus = useCallback(() => {
    setIsOpen(false);
    triggerRef.current?.focus();
  }, []);
  const handleDraftChange = useCallback(
    (value) => {
      if (commitOnSelect) {
        if (hasChangedFilter(value, committedValue)) {
          updateFilter(filter.id, value, true);
        }
        closeAndRestoreFocus();
        return;
      }
      if (!hasChangedFilter(value, draftValueRef.current)) return;
      draftValueRef.current = value;
      setDraftValue(value);
      if (!controlledFiltering) {
        updateFilter(filter.id, value, true);
        if (!keepOpenOnUncontrolledChange) {
          closeAndRestoreFocus();
        }
      }
    },
    [
      commitOnSelect,
      committedValue,
      controlledFiltering,
      filter.id,
      keepOpenOnUncontrolledChange,
      updateFilter,
      closeAndRestoreFocus
    ]
  );
  const handleApply = useCallback(() => {
    if (hasChangedFilter(draftValue, committedValue)) {
      updateFilter(filter.id, draftValue, true);
    }
    closeAndRestoreFocus();
  }, [
    draftValue,
    committedValue,
    filter.id,
    updateFilter,
    closeAndRestoreFocus
  ]);
  const handleCancel = useCallback(() => {
    if (!controlledFiltering) {
      closeAndRestoreFocus();
      return;
    }
    setDraftValue(committedValue);
    closeAndRestoreFocus();
  }, [controlledFiltering, committedValue, closeAndRestoreFocus]);
  const handlePopoverClose = useCallback(() => {
    if (commitOnSelect) {
      setIsOpen(false);
      return;
    }
    if (controlledFiltering) {
      setDraftValue(committedValue);
      setIsOpen(false);
    } else if (keepOpenOnUncontrolledChange) {
      setIsOpen(false);
    } else {
      if (hasChangedFilter(draftValueRef.current, committedValue)) {
        updateFilter(filter.id, draftValueRef.current, true);
      }
      setIsOpen(false);
    }
  }, [
    commitOnSelect,
    controlledFiltering,
    keepOpenOnUncontrolledChange,
    committedValue,
    filter.id,
    updateFilter
  ]);
  const bodyValue = commitOnSelect ? committedValue : draftValue;
  const showConfirmationFooter = controlledFiltering && !commitOnSelect;
  useEffect(() => {
    if (!isOpen || !showConfirmationFooter) return;
    const popoverEl = document.getElementById(popoverId);
    if (!popoverEl) return;
    const handler = (e) => {
      if (e.key !== "Enter" || e.defaultPrevented) return;
      handleApply();
    };
    popoverEl.addEventListener("keydown", handler);
    return () => popoverEl.removeEventListener("keydown", handler);
  }, [isOpen, showConfirmationFooter, popoverId, handleApply]);
  return /* @__PURE__ */ jsxs(FilterItemWrapper, { children: [
    /* @__PURE__ */ jsx(
      FilterTriggerButton,
      {
        ref: triggerRef,
        filterId: filter.id,
        label,
        isSelected,
        "aria-haspopup": "dialog",
        "aria-expanded": isOpen,
        "aria-controls": popoverId,
        onClick: () => setIsOpen((prev) => !prev),
        onKeyDown: (e) => {
          if (e.key === "Escape" && isOpen) {
            e.preventDefault();
            handlePopoverClose();
          }
        }
      }
    ),
    /* @__PURE__ */ jsx(
      OptionsPopover,
      {
        id: popoverId,
        referenceElement: triggerRef,
        open: isOpen,
        onClose: handlePopoverClose,
        footer: showConfirmationFooter ? /* @__PURE__ */ jsx(
          MenuFooter,
          {
            confirmation: {
              onApply: handleApply,
              onCancel: handleCancel
            }
          }
        ) : void 0,
        children: children({ value: bodyValue, onChange: handleDraftChange })
      }
    )
  ] });
};

const formatLabel$8 = (filter) => {
  if (filter.labelChipCount) {
    return /* @__PURE__ */ jsxs(Fragment, { children: [
      filter.label,
      /* @__PURE__ */ jsx(
        Chip,
        {
          label: filter.labelChipCount.toString(),
          color: "#0265DC",
          size: "small",
          "aria-label": `${filter.labelChipCount} selected items`
        }
      )
    ] });
  }
  return filter.label;
};
const customAdapter = {
  getValue: (filter) => filter.value,
  setValue: (filter, value) => ({ ...filter, value }),
  reset: (filter) => ({ ...filter, value: void 0 }),
  isActive: (filter) => filter.value !== void 0,
  preserveState: (newFilter, existingFilter) => ({
    ...newFilter,
    value: existingFilter.value
  }),
  cloneWithItemRefs: (filter) => {
    const { value } = filter;
    if (value === void 0) return { ...filter, value: void 0 };
    if (Array.isArray(value)) return { ...filter, value: [...value] };
    if (typeof value === "object" && value !== null) {
      return { ...filter, value: { ...value } };
    }
    return { ...filter, value };
  },
  renderBarControl: ({ filter }) => /* @__PURE__ */ jsx(
    FilterPopoverButton,
    {
      filter,
      label: formatLabel$8(filter),
      isSelected: filter.value !== void 0,
      committedValue: filter.value,
      initialValue: void 0,
      children: ({ value, onChange }) => (
        // drawer-only customs are filtered out before reaching
        // renderBarControl, so this guard is purely for TS narrowing across
        // the CustomFilter union (buttonRender is `never` when drawerOnly).
        filter.drawerOnly ? null : filter.buttonRender({ value, onChange })
      )
    },
    filter.id
  ),
  renderDrawer: ({ originalFilter, draftFilter, onDraftChange }) => /* @__PURE__ */ jsx("div", { children: originalFilter.drawerRender?.({
    value: draftFilter.value,
    onChange: (value) => onDraftChange(draftFilter.id, value)
  }) }, draftFilter.id),
  formatLabel: formatLabel$8,
  isSelected: (filter) => filter.value !== void 0
};

const toDate = (value) => {
  if (!value) return null;
  const date = DateTime.fromISO(value, { zone: "utc" }).startOf("day");
  return date.isValid ? date : null;
};
const getDateConstraintReason = (value, { minDate, maxDate, unavailable }) => {
  const date = toDate(value);
  if (!date) return null;
  const unavailableDates = unavailable?.dates?.map(toDate).filter((d) => d !== null);
  if (unavailableDates?.some((d) => d.equals(date))) return "unavailable";
  if (unavailable?.daysOfWeek?.includes(date.weekday)) {
    return "unavailable";
  }
  const min = toDate(minDate);
  const max = toDate(maxDate);
  if (min && date < min) return "minDate";
  if (max && date > max) return "maxDate";
  return null;
};
const formatDate = (value, mode = "mm/dd/yyyy") => {
  const date = toDate(value);
  return date ? date.toFormat(DateModeToFormatMap[mode]) : "";
};
const defaultReasonMessage = (reason, { minDate, maxDate }, mode) => {
  switch (reason) {
    case "minDate":
      return `Date must be on or after ${formatDate(minDate, mode)}.`;
    case "maxDate":
      return `Date must be on or before ${formatDate(maxDate, mode)}.`;
    case "unavailable":
      return "This date is unavailable.";
  }
};
const resolveDateFilterError = (filter, value) => {
  const reason = getDateConstraintReason(value, filter);
  if (!reason || !value) return void 0;
  return filter.getErrorMessage?.({ reason, value }) ?? defaultReasonMessage(
    reason,
    { minDate: filter.minDate, maxDate: filter.maxDate },
    filter.mode
  );
};
const getDateRangeConstraintViolation = (value, constraints) => {
  const start = value?.startDate ?? null;
  const end = value?.endDate ?? null;
  const startReason = getDateConstraintReason(start, constraints);
  if (startReason && start) {
    return { reason: startReason, field: "start", value: start };
  }
  const endReason = getDateConstraintReason(end, constraints);
  if (endReason && end) {
    return { reason: endReason, field: "end", value: end };
  }
  const startDate = toDate(start);
  const endDate = toDate(end);
  if (startDate && endDate && startDate > endDate) {
    return { reason: "startAfterEnd" };
  }
  return null;
};
const resolveDateRangeFilterError = (filter, value) => {
  const violation = getDateRangeConstraintViolation(value, filter);
  if (!violation) return void 0;
  const context = violation.reason === "startAfterEnd" ? { reason: "startAfterEnd" } : {
    reason: violation.reason,
    field: violation.field,
    value: violation.value
  };
  const custom = filter.getErrorMessage?.(context);
  if (custom) return custom;
  if (violation.reason === "startAfterEnd") {
    return "Start date must be on or before the end date.";
  }
  return defaultReasonMessage(
    violation.reason,
    { minDate: filter.minDate, maxDate: filter.maxDate },
    filter.mode
  );
};

const FilterDateSingle = (props) => {
  if (props.variant === "inline") {
    return /* @__PURE__ */ jsx(
      Body$1,
      {
        filter: props.filter,
        value: props.draftValue,
        onChange: props.onDraftChange
      }
    );
  }
  return /* @__PURE__ */ jsx(PopoverShell$1, { ...props });
};
const Body$1 = ({
  filter,
  value: draftValue,
  onChange: onDraftChange
}) => {
  const maskedDateInputRef = useRef(null);
  const handleChange = (change) => {
    onDraftChange(change.date);
  };
  const { value, minDate, maxDate, unavailable, onChange } = useDateFieldSingleConversion({
    value: draftValue,
    onChange: handleChange,
    minDate: filter.minDate,
    maxDate: filter.maxDate,
    unavailable: filter.unavailable
  });
  const { handleInputChange, handleCalendarSelection } = useDateFieldSingleState({
    valueProp: value,
    onChange: (change) => onChange({ ...change, isDateValid: true })
  });
  const error = resolveDateFilterError(filter, draftValue);
  return /* @__PURE__ */ jsxs(Flex, { gap: 4, direction: "column", children: [
    /* @__PURE__ */ jsx(
      MaskedDateInput,
      {
        mode: filter.mode,
        ref: maskedDateInputRef,
        onChange: handleInputChange,
        lastValidDate: value ?? null,
        autoComplete: "off",
        error
      }
    ),
    /* @__PURE__ */ jsx(
      DateFieldSingleCalendar,
      {
        value: value ?? null,
        onSelection: handleCalendarSelection,
        minDate,
        maxDate,
        unavailable
      }
    )
  ] });
};
const PopoverShell$1 = ({
  filter,
  committedValue,
  onCommit,
  controlledFiltering,
  label,
  isSelected,
  clear
}) => {
  const triggerRef = useRef(null);
  const popoverId = useId();
  const [isOpen, setIsOpen] = useState(false);
  const isEqual = useCallback(
    (a, b) => !hasChangedFilter(a, b),
    []
  );
  const { displayValue, setDraft, apply, cancel } = useConfirmationDraft(
    {
      value: committedValue,
      onCommit,
      isOpen,
      enabled: controlledFiltering,
      isEqual
    }
  );
  const handleClose = useCallback(() => {
    if (controlledFiltering) {
      cancel();
    }
    setIsOpen(false);
  }, [controlledFiltering, cancel]);
  const handleApply = useCallback(() => {
    apply();
    setIsOpen(false);
  }, [apply]);
  return /* @__PURE__ */ jsxs(FilterItemWrapper, { children: [
    /* @__PURE__ */ jsx(
      FilterTriggerButton,
      {
        ref: triggerRef,
        filterId: filter.id,
        label,
        isSelected,
        icon: "calendar",
        "aria-haspopup": "dialog",
        "aria-expanded": isOpen,
        onClick: () => setIsOpen((prev) => !prev)
      }
    ),
    /* @__PURE__ */ jsx(
      OptionsPopover,
      {
        id: popoverId,
        referenceElement: triggerRef,
        open: isOpen,
        onClose: handleClose,
        footer: clear || controlledFiltering ? /* @__PURE__ */ jsx(
          MenuFooter,
          {
            clear: clear ? {
              ...clear,
              onClick: () => {
                clear.onClick();
                setIsOpen(false);
                triggerRef.current?.focus();
              }
            } : void 0,
            confirmation: controlledFiltering ? {
              onApply: handleApply,
              onCancel: handleClose
            } : void 0
          }
        ) : void 0,
        children: isOpen ? /* @__PURE__ */ jsx(Body$1, { filter, value: displayValue, onChange: setDraft }) : null
      }
    )
  ] });
};

const formatLabel$7 = (filter) => {
  if (filter.value) {
    const date = DateTime.fromISO(filter.value, { zone: "local" });
    return `${filter.label}: ${date.monthShort} ${date.day}, ${date.year}`;
  }
  return filter.label;
};
const dateAdapter = {
  getValue: (filter) => filter.value ?? null,
  setValue: (filter, value) => ({ ...filter, value }),
  reset: (filter) => ({ ...filter, value: null }),
  isActive: (filter) => filter.value !== null && filter.value !== void 0,
  preserveState: (newFilter, existingFilter) => ({
    ...newFilter,
    value: existingFilter.value
  }),
  cloneWithItemRefs: (filter) => ({ ...filter, value: filter.value ?? null }),
  renderBarControl: ({ filter, updateFilter, controlledFiltering }) => /* @__PURE__ */ jsx(
    FilterDateSingle,
    {
      filter,
      committedValue: filter.value ?? null,
      onCommit: (value) => updateFilter(filter.id, value, true),
      controlledFiltering,
      label: formatLabel$7(filter),
      isSelected: !!filter.value,
      clear: {
        onClick: () => updateFilter(filter.id, null, true)
      }
    },
    filter.id
  ),
  renderDrawer: ({ draftFilter, onDraftChange }) => /* @__PURE__ */ jsx(
    DateFieldSingle,
    {
      label: draftFilter.label,
      value: draftFilter.value ?? null,
      onChange: (change) => onDraftChange(draftFilter.id, change.date),
      mode: draftFilter.mode,
      minDate: draftFilter.minDate,
      maxDate: draftFilter.maxDate,
      unavailable: draftFilter.unavailable,
      error: resolveDateFilterError(draftFilter, draftFilter.value ?? null)
    },
    draftFilter.id
  ),
  formatLabel: formatLabel$7,
  isSelected: (filter) => !!filter.value
};

const FilterDateRange = (props) => {
  if (props.variant === "inline") {
    return /* @__PURE__ */ jsx(
      Body,
      {
        filter: props.filter,
        value: props.draftValue,
        onChange: props.onDraftChange
      }
    );
  }
  return /* @__PURE__ */ jsx(PopoverShell, { ...props });
};
const Body = ({
  filter,
  value: draftValue,
  onChange: onDraftChange
}) => {
  const maskedDateRangeInputRef = useRef(null);
  const handleChange = (change) => {
    const hasCompleteRange = change.startDate && change.endDate;
    const isClearingRange = !change.startDate && !change.endDate;
    if (hasCompleteRange || isClearingRange) {
      onDraftChange({
        startDate: change.startDate,
        endDate: change.endDate
      });
    }
  };
  const { value, minDate, maxDate, unavailable, onChange } = useDateFieldRangeConversion({
    value: draftValue,
    onChange: handleChange,
    minDate: filter.minDate,
    maxDate: filter.maxDate,
    unavailable: filter.unavailable
  });
  const { handleInputChange, handleCalendarSelection } = useDateFieldRangeState(
    {
      valueProp: value,
      onChange: (change) => {
        const hasCompleteRange = change.startDate && change.endDate;
        const isClearingRange = change.isInputEmpty;
        if (change.isInputValid && hasCompleteRange || isClearingRange) {
          onChange({ ...change, isDateRangeValid: true });
        }
      }
    }
  );
  const error = resolveDateRangeFilterError(filter, draftValue);
  return /* @__PURE__ */ jsxs(Flex, { gap: 4, direction: "column", children: [
    /* @__PURE__ */ jsx(
      MaskedDateRangeInput,
      {
        mode: filter.mode,
        ref: maskedDateRangeInputRef,
        onChange: handleInputChange,
        startDate: value?.startDate ?? null,
        endDate: value?.endDate ?? null,
        autoComplete: "off",
        error
      }
    ),
    /* @__PURE__ */ jsx(
      DateFieldRangeCalendar,
      {
        startDate: value?.startDate ?? null,
        endDate: value?.endDate ?? null,
        onSelection: handleCalendarSelection,
        minDate,
        maxDate,
        unavailable
      }
    )
  ] });
};
const PopoverShell = ({
  filter,
  committedValue,
  onCommit,
  controlledFiltering,
  label,
  isSelected,
  clear
}) => {
  const triggerRef = useRef(null);
  const popoverId = useId();
  const [isOpen, setIsOpen] = useState(false);
  const isEqual = useCallback(
    (a, b) => !hasChangedFilter(a, b),
    []
  );
  const { displayValue, setDraft, apply, cancel } = useConfirmationDraft(
    {
      value: committedValue,
      onCommit,
      isOpen,
      enabled: controlledFiltering,
      isEqual
    }
  );
  const handleClose = useCallback(() => {
    if (controlledFiltering) {
      cancel();
    }
    setIsOpen(false);
  }, [controlledFiltering, cancel]);
  const handleApply = useCallback(() => {
    apply();
    setIsOpen(false);
  }, [apply]);
  return /* @__PURE__ */ jsxs(FilterItemWrapper, { children: [
    /* @__PURE__ */ jsx(
      FilterTriggerButton,
      {
        ref: triggerRef,
        filterId: filter.id,
        label,
        isSelected,
        icon: "calendar",
        "aria-haspopup": "dialog",
        "aria-expanded": isOpen,
        onClick: () => setIsOpen((prev) => !prev)
      }
    ),
    /* @__PURE__ */ jsx(
      OptionsPopover,
      {
        id: popoverId,
        referenceElement: triggerRef,
        open: isOpen,
        onClose: handleClose,
        footer: clear || controlledFiltering ? /* @__PURE__ */ jsx(
          MenuFooter,
          {
            clear: clear ? {
              ...clear,
              onClick: () => {
                clear.onClick();
                setIsOpen(false);
                triggerRef.current?.focus();
              }
            } : void 0,
            confirmation: controlledFiltering ? {
              onApply: handleApply,
              onCancel: handleClose
            } : void 0
          }
        ) : void 0,
        children: isOpen ? /* @__PURE__ */ jsx(Body, { filter, value: displayValue, onChange: setDraft }) : null
      }
    )
  ] });
};

const LIBRARY_OPTION_LABELS = {
  on: "On",
  before: "Before",
  after: "After",
  customRange: "Custom Range"
};
const LIBRARY_OPTION_IDS_ORDERED = [
  "on",
  "before",
  "after",
  "customRange"
];
const LIBRARY_OPTION_ID_SET = new Set(LIBRARY_OPTION_IDS_ORDERED);
const isDateListLibraryOptionId = (id) => LIBRARY_OPTION_ID_SET.has(id);
const getDateListLibraryOptionLabel = (id) => LIBRARY_OPTION_LABELS[id];
const dateListLibraryOptions = LIBRARY_OPTION_IDS_ORDERED.map((id) => ({
  id,
  label: `${LIBRARY_OPTION_LABELS[id]}…`
}));
const getVisibleDateListDefaultOptions = (filter) => {
  const excluded = new Set(filter.excludeDefaultOptions ?? []);
  if (excluded.size === 0) return dateListLibraryOptions;
  return dateListLibraryOptions.filter((opt) => !excluded.has(opt.id));
};
const isDateListRangeLibraryId = (id) => id === "customRange";
const formatDateForLabel = (iso) => {
  const d = DateTime.fromISO(iso, { zone: "local" });
  return `${d.monthShort} ${d.day}, ${d.year}`;
};
const formatRangeForLabel = (range) => {
  const start = DateTime.fromISO(range.startDate, { zone: "local" });
  const end = DateTime.fromISO(range.endDate, { zone: "local" });
  const sameYear = start.year === end.year;
  const formattedStart = sameYear ? `${start.monthShort} ${start.day}` : `${start.monthShort} ${start.day}, ${start.year}`;
  return `${formattedStart} – ${end.monthShort} ${end.day}, ${end.year}`;
};
const formatDateListSelectionLabel = (selection) => {
  if (selection.value === null) return selection.label;
  const formatted = typeof selection.value === "string" ? formatDateForLabel(selection.value) : formatRangeForLabel(selection.value);
  if (selection.id === "customRange") return formatted;
  return `${selection.label}: ${formatted}`;
};

const DateListDialog = ({
  libraryId,
  parentFilterId,
  initialValue,
  mode,
  dialogCtaLabel,
  onCommit,
  onCancel
}) => {
  const [dateDraft, setDateDraft] = useState(null);
  const [rangeDraft, setRangeDraft] = useState(null);
  useEffect(() => {
    if (!libraryId) return;
    if (isDateListRangeLibraryId(libraryId)) {
      setRangeDraft(
        initialValue && typeof initialValue === "object" ? {
          startDate: initialValue.startDate,
          endDate: initialValue.endDate
        } : null
      );
      setDateDraft(null);
    } else {
      setDateDraft(typeof initialValue === "string" ? initialValue : null);
      setRangeDraft(null);
    }
  }, [libraryId, initialValue]);
  const dialogOpen = libraryId !== null;
  const dialogLabel = libraryId ? getDateListLibraryOptionLabel(libraryId) : "";
  const isRange = libraryId ? isDateListRangeLibraryId(libraryId) : false;
  const canCommit = isRange ? Boolean(rangeDraft?.startDate && rangeDraft?.endDate) : Boolean(dateDraft);
  const handleCommit = () => {
    if (!libraryId) return;
    if (isRange) {
      if (!rangeDraft?.startDate || !rangeDraft?.endDate) return;
      onCommit({
        id: libraryId,
        label: dialogLabel,
        value: {
          startDate: rangeDraft.startDate,
          endDate: rangeDraft.endDate
        }
      });
    } else {
      if (!dateDraft) return;
      onCommit({ id: libraryId, label: dialogLabel, value: dateDraft });
    }
  };
  return /* @__PURE__ */ jsx(Dialog, { open: dialogOpen, onClose: onCancel, children: libraryId && /* @__PURE__ */ jsxs(Fragment, { children: [
    /* @__PURE__ */ jsx(Dialog.Header, { children: dialogLabel }),
    /* @__PURE__ */ jsx(Dialog.Content, { children: isRange ? /* @__PURE__ */ jsx(
      FilterDateRange,
      {
        variant: "inline",
        filter: {
          id: `${parentFilterId}--date-list-dialog-range`,
          label: dialogLabel,
          type: "dateRange",
          value: rangeDraft,
          mode
        },
        draftValue: rangeDraft,
        onDraftChange: setRangeDraft
      }
    ) : /* @__PURE__ */ jsx(
      FilterDateSingle,
      {
        variant: "inline",
        filter: {
          id: `${parentFilterId}--date-list-dialog-date`,
          label: dialogLabel,
          type: "date",
          value: dateDraft,
          mode
        },
        draftValue: dateDraft,
        onDraftChange: setDateDraft
      }
    ) }),
    /* @__PURE__ */ jsx(Dialog.Footer, { children: /* @__PURE__ */ jsxs(Flex, { gap: 2, justifyContent: "flex-end", children: [
      /* @__PURE__ */ jsx(Dialog.CancelButton, { appearance: "ghost", "aria-label": "Cancel", children: "Cancel" }),
      /* @__PURE__ */ jsx(
        Button,
        {
          appearance: "primary",
          disabled: !canCommit,
          onClick: handleCommit,
          children: dialogCtaLabel
        }
      )
    ] }) })
  ] }) });
};
const FilterDateList = ({
  filter,
  committedValue,
  onCommit,
  label,
  isSelected,
  dialogCtaLabel,
  clear
}) => {
  const [openLibraryId, setOpenLibraryId] = useState(null);
  const excludeDefaultOptions = filter.excludeDefaultOptions;
  const visibleLibraryOptions = useMemo(
    () => getVisibleDateListDefaultOptions({ excludeDefaultOptions }),
    [excludeDefaultOptions]
  );
  useEffect(() => {
    const libraryLabels = new Set(visibleLibraryOptions.map((o) => o.label));
    filter.options.forEach((opt) => {
      if (isDateListLibraryOptionId(opt.id)) {
        warnOnce(
          `[FilterDateList] Consumer option id "${opt.id}" is reserved for a library option ("on", "before", "after", "customRange"). Use a different id.`
        );
      }
      if (libraryLabels.has(opt.label)) {
        warnOnce(
          `[FilterDateList] Consumer option label "${opt.label}" collides with a library option label ("On…", "Before…", "After…", "Custom Range…"). Use a different label.`
        );
      }
    });
  }, [filter.options, visibleLibraryOptions]);
  const options = useMemo(
    () => [
      ...filter.options.map((opt) => ({
        id: opt.id,
        label: opt.label
      })),
      ...visibleLibraryOptions.map((opt) => ({
        id: opt.id,
        label: opt.label
      }))
    ],
    [filter.options, visibleLibraryOptions]
  );
  const selectedOption = useMemo(
    () => committedValue ? options.find((opt) => opt.id === committedValue.id) ?? null : null,
    [options, committedValue]
  );
  const handleSelectedOptionChange = (option) => {
    if (!option) {
      onCommit(void 0);
      return;
    }
    const id = String(option.id);
    if (isDateListLibraryOptionId(id)) {
      setOpenLibraryId(id);
      return;
    }
    const consumerOption = filter.options.find((opt) => opt.id === id);
    if (!consumerOption) return;
    onCommit({
      id: consumerOption.id,
      label: consumerOption.label,
      value: consumerOption.value
    });
  };
  const dialogInitialValue = openLibraryId && committedValue?.id === openLibraryId && committedValue.value !== null ? committedValue.value : void 0;
  return /* @__PURE__ */ jsxs(Fragment, { children: [
    /* @__PURE__ */ jsx(FilterItemWrapper, { children: /* @__PURE__ */ jsx(
      SelectMenuSync,
      {
        id: filter.id,
        label: filter.label,
        options,
        value: selectedOption,
        onSelectedOptionChange: handleSelectedOptionChange,
        disableSearch: true,
        clear,
        trigger: (triggerProps) => /* @__PURE__ */ jsx(
          FilterTriggerButton,
          {
            ...triggerProps,
            filterId: filter.id,
            label,
            isSelected,
            icon: "calendar"
          }
        )
      }
    ) }),
    /* @__PURE__ */ jsx(
      DateListDialog,
      {
        libraryId: openLibraryId,
        parentFilterId: filter.id,
        initialValue: dialogInitialValue,
        mode: filter.mode,
        dialogCtaLabel,
        onCommit: (option) => {
          onCommit(option);
          setOpenLibraryId(null);
        },
        onCancel: () => setOpenLibraryId(null)
      }
    )
  ] });
};

const isSelected$7 = (filter) => filter.selectedOption !== void 0 && filter.selectedOption.value !== null;
const formatLabel$6 = (filter) => {
  const selected = filter.selectedOption;
  if (!selected || selected.value === null) return filter.label;
  return formatDateListSelectionLabel(selected);
};
const dateListAdapter = {
  getValue: (filter) => filter.selectedOption,
  setValue: (filter, value) => ({ ...filter, selectedOption: value }),
  reset: (filter) => ({ ...filter, selectedOption: void 0 }),
  isActive: isSelected$7,
  preserveState: (newFilter, existingFilter) => ({
    ...newFilter,
    selectedOption: existingFilter.selectedOption
  }),
  cloneWithItemRefs: (filter) => ({ ...filter }),
  renderBarControl: ({ filter, updateFilter }) => /* @__PURE__ */ jsx(
    FilterDateList,
    {
      filter,
      committedValue: filter.selectedOption,
      onCommit: (value) => updateFilter(filter.id, value, true),
      label: formatLabel$6(filter),
      isSelected: isSelected$7(filter),
      dialogCtaLabel: "Apply",
      clear: {
        onClick: () => updateFilter(filter.id, void 0, true)
      }
    },
    filter.id
  ),
  renderDrawer: ({
    originalFilter,
    draftFilter,
    onDraftChange,
    requestDateListDialog
  }) => {
    const consumerSelectOptions = originalFilter.options.map((opt) => ({
      id: opt.id,
      label: opt.label,
      extra: { value: opt.value }
    }));
    const librarySelectOptions = getVisibleDateListDefaultOptions(originalFilter).map((opt) => ({
      id: opt.id,
      label: opt.label,
      extra: { value: null }
    }));
    const allSelectOptions = [
      ...consumerSelectOptions,
      ...librarySelectOptions
    ];
    const selectedSelectOption = draftFilter.selectedOption ? {
      id: draftFilter.selectedOption.id,
      label: formatDateListSelectionLabel(draftFilter.selectedOption),
      extra: {
        value: draftFilter.selectedOption.value
      }
    } : null;
    return /* @__PURE__ */ jsx(
      SelectFieldSync,
      {
        label: originalFilter.label,
        placeholder: "Select an option...",
        disableSearch: true,
        options: allSelectOptions,
        value: selectedSelectOption,
        onSelectedOptionChange: (option) => {
          if (!option) {
            onDraftChange(draftFilter.id, void 0);
            return;
          }
          const id = String(option.id);
          if (isDateListLibraryOptionId(id)) {
            requestDateListDialog(draftFilter.id, id);
            return;
          }
          onDraftChange(draftFilter.id, {
            id,
            label: option.label,
            value: option.extra?.value ?? null
          });
        }
      },
      draftFilter.id
    );
  },
  formatLabel: formatLabel$6,
  isSelected: isSelected$7
};

const formatLabel$5 = (filter) => {
  if (filter.value?.startDate && filter.value?.endDate) {
    const start = DateTime.fromISO(filter.value.startDate, {
      zone: "local"
    });
    const end = DateTime.fromISO(filter.value.endDate, {
      zone: "local"
    });
    const isSameYear = start.year === end.year;
    const formattedStart = isSameYear ? `${start.monthShort} ${start.day}` : `${start.monthShort} ${start.day}, ${start.year}`;
    return `${filter.label}: ${formattedStart} – ${end.monthShort} ${end.day}, ${end.year}`;
  }
  return filter.label;
};
const isSelected$6 = (filter) => !!(filter.value?.startDate && filter.value?.endDate);
const dateRangeAdapter = {
  getValue: (filter) => filter.value ?? null,
  setValue: (filter, value) => ({ ...filter, value }),
  reset: (filter) => ({ ...filter, value: null }),
  isActive: (filter) => filter.value !== null && filter.value !== void 0 && filter.value.startDate !== null && filter.value.endDate !== null,
  preserveState: (newFilter, existingFilter) => ({
    ...newFilter,
    value: existingFilter.value
  }),
  cloneWithItemRefs: (filter) => ({
    ...filter,
    value: filter.value ?? null
  }),
  renderBarControl: ({ filter, updateFilter, controlledFiltering }) => /* @__PURE__ */ jsx(
    FilterDateRange,
    {
      filter,
      committedValue: filter.value ?? null,
      onCommit: (value) => updateFilter(filter.id, value, true),
      controlledFiltering,
      label: formatLabel$5(filter),
      isSelected: isSelected$6(filter),
      clear: {
        onClick: () => updateFilter(filter.id, null, true)
      }
    },
    filter.id
  ),
  renderDrawer: ({ draftFilter, onDraftChange }) => /* @__PURE__ */ jsx(
    DateFieldRange,
    {
      label: draftFilter.label,
      value: draftFilter.value ?? null,
      onChange: (change) => onDraftChange(draftFilter.id, {
        startDate: change.startDate,
        endDate: change.endDate
      }),
      mode: draftFilter.mode,
      minDate: draftFilter.minDate,
      maxDate: draftFilter.maxDate,
      unavailable: draftFilter.unavailable,
      error: resolveDateRangeFilterError(
        draftFilter,
        draftFilter.value ?? null
      )
    },
    draftFilter.id
  ),
  formatLabel: formatLabel$5,
  isSelected: isSelected$6
};

const isSelected$5 = (filter) => !!filter.selectedOptions && filter.selectedOptions.length > 0;
const formatLabel$4 = (filter) => {
  const count = filter.selectedOptions?.length ?? 0;
  if (count === 0) return filter.label;
  const countLabel = count.toString();
  return /* @__PURE__ */ jsxs(Fragment, { children: [
    filter.label,
    /* @__PURE__ */ jsx(
      Chip,
      {
        label: countLabel,
        color: "#0265DC",
        size: "small",
        "aria-label": `${countLabel} selected items`
      }
    )
  ] });
};
const passThroughMenuProps$2 = (filter) => {
  const {
    id: _id,
    label: _label,
    type: _type,
    selectedOptions: _selectedOptions,
    simpleDrawerVariant: _simpleDrawerVariant,
    drawerOnly: _drawerOnly,
    ...rest
  } = filter;
  return rest;
};
const multiSelectAdapter = {
  getValue: (filter) => filter.selectedOptions ?? [],
  setValue: (filter, value) => ({ ...filter, selectedOptions: value }),
  reset: (filter) => ({ ...filter, selectedOptions: [] }),
  isActive: isSelected$5,
  preserveState: (newFilter, existingFilter) => ({
    ...newFilter,
    selectedOptions: existingFilter.selectedOptions
  }),
  // Options are owned by the consumer; MultiSelectMenuSync handles identity
  // internally — no rebinding needed.
  cloneWithItemRefs: (filter) => ({ ...filter }),
  renderBarControl: ({ filter, updateFilter, controlledFiltering }) => /* @__PURE__ */ jsx(FilterItemWrapper, { children: /* @__PURE__ */ jsx(
    MultiSelectMenuSync,
    {
      ...passThroughMenuProps$2(filter),
      id: filter.id,
      label: filter.label,
      value: filter.selectedOptions ?? [],
      onSelectedOptionsChange: (options) => updateFilter(filter.id, options, true),
      confirmation: controlledFiltering,
      clear: {
        onClick: () => updateFilter(filter.id, [], true)
      },
      trigger: (triggerProps) => /* @__PURE__ */ jsx(
        FilterTriggerButton,
        {
          ...triggerProps,
          filterId: filter.id,
          label: formatLabel$4(filter),
          isSelected: isSelected$5(filter)
        }
      )
    }
  ) }, filter.id),
  renderDrawer: ({ originalFilter, draftFilter, onDraftChange }) => {
    if (originalFilter.simpleDrawerVariant) {
      return /* @__PURE__ */ jsx(Checkbox.Group, { legend: originalFilter.label, children: originalFilter.options.map((option) => /* @__PURE__ */ jsx(
        Checkbox,
        {
          label: option.label,
          checked: draftFilter.selectedOptions?.some(
            (selected) => selected.id === option.id
          ) ?? false,
          onChange: (e) => {
            const currentSelected = draftFilter.selectedOptions ?? [];
            if (e?.target.checked) {
              onDraftChange(draftFilter.id, [...currentSelected, option]);
            } else {
              onDraftChange(
                draftFilter.id,
                currentSelected.filter(
                  (selected) => selected.id !== option.id
                )
              );
            }
          }
        },
        option.id
      )) }, draftFilter.id);
    }
    return /* @__PURE__ */ createElement(
      MultiSelectFieldSync,
      {
        ...passThroughMenuProps$2(originalFilter),
        key: draftFilter.id,
        label: originalFilter.label,
        value: draftFilter.selectedOptions ?? [],
        onSelectedOptionsChange: (options) => onDraftChange(draftFilter.id, options)
      }
    );
  },
  formatLabel: formatLabel$4,
  isSelected: isSelected$5
};

const clampToBounds = (n, minValue, maxValue) => {
  if (n === void 0) return void 0;
  let result = n;
  if (minValue !== void 0) result = Math.max(result, minValue);
  if (maxValue !== void 0) result = Math.min(result, maxValue);
  return result;
};
const FilterNumericRange = ({
  filter,
  value,
  onChange,
  layout
}) => {
  const inclusive = filter.inclusiveBounds === true;
  const minFieldLabel = inclusive ? "Min" : "Above";
  const maxFieldLabel = inclusive ? "Max" : "Below";
  const minimumFractionDigits = filter.minimumFractionDigits ?? (filter.mode === "currency" ? 2 : filter.mode === "percentage" ? 0 : void 0);
  const maximumFractionDigits = filter.maximumFractionDigits ?? (filter.mode === "currency" ? 2 : filter.mode === "percentage" ? 3 : void 0);
  const decoratorProps = {
    ...filter.mode === "currency" && { prefix: "$" },
    ...filter.mode === "percentage" && { suffix: "%" },
    ...minimumFractionDigits !== void 0 && { minimumFractionDigits },
    ...maximumFractionDigits !== void 0 && { maximumFractionDigits }
  };
  const update = (next) => {
    const min = clampToBounds(next.min, filter.minValue, filter.maxValue);
    const max = clampToBounds(next.max, filter.minValue, filter.maxValue);
    onChange(min === void 0 && max === void 0 ? null : { min, max });
  };
  const sharedNumberFieldProps = {
    hideControls: filter.hideControls ?? true,
    step: filter.step,
    minValue: filter.minValue,
    maxValue: filter.maxValue,
    ...decoratorProps
  };
  const minField = /* @__PURE__ */ jsx(
    NumberField,
    {
      label: minFieldLabel,
      value: value?.min ?? null,
      onChange: (n) => update({ min: n ?? void 0, max: value?.max }),
      ...sharedNumberFieldProps
    }
  );
  const maxField = /* @__PURE__ */ jsx(
    NumberField,
    {
      label: maxFieldLabel,
      value: value?.max ?? null,
      onChange: (n) => update({ min: value?.min, max: n ?? void 0 }),
      ...sharedNumberFieldProps
    }
  );
  if (layout === "compact") {
    return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: "2", grow: 1, children: [
      minField,
      maxField
    ] });
  }
  return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: "2", grow: 1, children: [
    /* @__PURE__ */ jsx(FieldLabel, { children: filter.label }),
    /* @__PURE__ */ jsxs(Grid, { templateColumns: "1fr auto 1fr", gap: "2", children: [
      minField,
      /* @__PURE__ */ jsx(
        Flex,
        {
          alignItems: "center",
          justifyContent: "center",
          className: styles["filter-numeric-range-separator"],
          children: /* @__PURE__ */ jsx(Text, { children: "to" })
        }
      ),
      maxField
    ] })
  ] });
};

const formatBound = (n, filter) => {
  const minimumFractionDigits = filter.minimumFractionDigits ?? (filter.mode === "currency" ? 2 : filter.mode === "percentage" ? 0 : void 0);
  const maximumFractionDigits = filter.maximumFractionDigits ?? (filter.mode === "currency" ? 2 : filter.mode === "percentage" ? 3 : void 0);
  const formatOptions = {};
  if (minimumFractionDigits !== void 0) {
    formatOptions.minimumFractionDigits = minimumFractionDigits;
  }
  if (maximumFractionDigits !== void 0) {
    formatOptions.maximumFractionDigits = maximumFractionDigits;
  }
  const formatted = n.toLocaleString("en-US", formatOptions);
  if (filter.mode === "currency") return `$${formatted}`;
  if (filter.mode === "percentage") return `${formatted}%`;
  return formatted;
};
const formatLabel$3 = (filter) => {
  const hasMin = filter.value?.min !== void 0;
  const hasMax = filter.value?.max !== void 0;
  if (!hasMin && !hasMax) return filter.label;
  const inclusive = filter.inclusiveBounds === true;
  const minSymbol = inclusive ? "≥" : ">";
  const maxSymbol = inclusive ? "≤" : "<";
  if (hasMin && hasMax) {
    return `${filter.label}: ${formatBound(filter.value.min, filter)} to ${formatBound(filter.value.max, filter)}`;
  }
  if (hasMin) {
    return `${filter.label}: ${minSymbol} ${formatBound(filter.value.min, filter)}`;
  }
  return `${filter.label}: ${maxSymbol} ${formatBound(filter.value.max, filter)}`;
};
const isSelected$4 = (filter) => filter.value !== null && filter.value !== void 0 && (filter.value.min !== void 0 || filter.value.max !== void 0);
const numericRangeAdapter = {
  getValue: (filter) => filter.value ?? null,
  setValue: (filter, value) => ({ ...filter, value }),
  reset: (filter) => ({ ...filter, value: null }),
  isActive: isSelected$4,
  preserveState: (newFilter, existingFilter) => ({
    ...newFilter,
    value: existingFilter.value
  }),
  cloneWithItemRefs: (filter) => ({
    ...filter,
    value: filter.value ? { ...filter.value } : null
  }),
  renderBarControl: ({ filter }) => /* @__PURE__ */ jsx(
    FilterPopoverButton,
    {
      filter,
      label: formatLabel$3(filter),
      isSelected: isSelected$4(filter),
      committedValue: filter.value ?? null,
      initialValue: null,
      keepOpenOnUncontrolledChange: true,
      children: ({ value, onChange }) => /* @__PURE__ */ jsx(
        FilterNumericRange,
        {
          filter,
          value,
          onChange,
          layout: "compact"
        }
      )
    },
    filter.id
  ),
  renderDrawer: ({ draftFilter, onDraftChange }) => /* @__PURE__ */ jsx(
    FilterNumericRange,
    {
      filter: draftFilter,
      value: draftFilter.value ?? null,
      onChange: (value) => onDraftChange(draftFilter.id, value),
      layout: "grid"
    },
    draftFilter.id
  ),
  formatLabel: formatLabel$3,
  isSelected: isSelected$4
};

const FilterSearchField = ({
  filter,
  value,
  onChange
}) => {
  const { toolbarRef } = useContext(ToolbarContext);
  const size = useToolbarSize();
  const hasValue = !!value;
  const inputRef = useRef(null);
  const clearButtonRef = useRef(null);
  const placeholder = filter.placeholder ?? "Search...";
  const focusRovingItem = (edge) => {
    if (!toolbarRef.current) return;
    const items = getToolbarElements(toolbarRef.current);
    const target = edge === "first" ? items[0] : items[items.length - 1];
    if (!target) return;
    updateToolbarItemsTabIndex(toolbarRef.current, target);
    target.focus();
  };
  const handleChange = (e) => {
    onChange(e.target.value);
  };
  const handleClear = () => {
    onChange("");
    inputRef.current?.focus();
  };
  const handleInputKeyDown = (e) => {
    const input = e.currentTarget;
    if (e.code === "ArrowRight") {
      if (!hasValue) {
        e.preventDefault();
        focusRovingItem("first");
      } else if (input.selectionStart === input.value.length) {
        e.preventDefault();
        clearButtonRef.current?.focus();
      }
    } else if (e.code === "ArrowLeft") {
      if (input.selectionStart === 0) {
        e.preventDefault();
        focusRovingItem("last");
      }
    }
  };
  const handleClearKeyDown = (e) => {
    if (e.code === "Enter" || e.code === "Space") {
      e.preventDefault();
      handleClear();
    } else if (e.code === "ArrowLeft") {
      e.preventDefault();
      inputRef.current?.focus();
    } else if (e.code === "ArrowRight") {
      e.preventDefault();
      focusRovingItem("first");
    }
  };
  const trackingId = useTrackingId({
    name: "FilterSearchField",
    data: { value }
  });
  return /* @__PURE__ */ jsx(
    "div",
    {
      className: cx(
        textFieldStyles["textfield"],
        styles$1["searchfield"]
      ),
      "data-anv": "filter-search-field",
      children: /* @__PURE__ */ jsxs(
        "div",
        {
          className: cx(
            textFieldStyles["input-wrapper"],
            styles$1["input-wrapper"],
            {
              [textFieldStyles["xsmall"]]: size === "xsmall",
              [textFieldStyles["small"]]: size === "small",
              [textFieldStyles["large"]]: size === "large"
            }
          ),
          role: "presentation",
          onClick: () => inputRef.current?.focus(),
          children: [
            /* @__PURE__ */ jsx("div", { "aria-hidden": true, className: textFieldStyles["prefix"], children: /* @__PURE__ */ jsx(Icon, { svg: SvgSearch }) }),
            /* @__PURE__ */ jsx(
              "input",
              {
                className: cx(textFieldStyles["input"], styles$1["input"], {
                  [styles$1["input--has-value"]]: hasValue
                }),
                ref: inputRef,
                onChange: handleChange,
                onKeyDown: handleInputKeyDown,
                placeholder,
                value,
                type: "search",
                autoComplete: "off",
                "aria-label": filter.label,
                "data-tracking-id": trackingId
              }
            ),
            /* @__PURE__ */ jsx(
              Icon,
              {
                ref: clearButtonRef,
                "aria-label": "Clear search",
                svg: SvgClose,
                role: "button",
                onClick: handleClear,
                onKeyDown: handleClearKeyDown,
                tabIndex: -1,
                className: styles$1["clear"],
                style: {
                  visibility: hasValue ? "visible" : "hidden"
                }
              }
            )
          ]
        }
      )
    }
  );
};
FilterSearchField.displayName = "FilterSearchField";

const isSelected$3 = (filter) => filter.value !== void 0 && filter.value !== "";
const searchAdapter = {
  getValue: (filter) => filter.value ?? "",
  setValue: (filter, value) => ({ ...filter, value: value || void 0 }),
  reset: (filter) => ({ ...filter, value: void 0 }),
  isActive: isSelected$3,
  preserveState: (newFilter, existingFilter) => ({
    ...newFilter,
    value: existingFilter.value
  }),
  cloneWithItemRefs: (filter) => ({ ...filter }),
  // Always visible inline — no popover/Apply affordance to gate behind, so
  // (like the boolean adapter) this commits on every keystroke regardless
  // of controlledFiltering.
  renderBarControl: ({ filter, updateFilter }) => /* @__PURE__ */ jsx(
    FilterSearchField,
    {
      filter,
      value: filter.value ?? "",
      onChange: (value) => updateFilter(filter.id, value, true)
    },
    filter.id
  ),
  renderDrawer: ({ draftFilter, onDraftChange }) => /* @__PURE__ */ jsx(
    TextField,
    {
      label: draftFilter.label,
      placeholder: draftFilter.placeholder,
      value: draftFilter.value ?? "",
      onChange: (e) => onDraftChange(draftFilter.id, e.target.value || void 0)
    },
    draftFilter.id
  ),
  formatLabel: (filter) => filter.label,
  isSelected: isSelected$3
};

const formatLabel$2 = (filter) => {
  if (filter.selectedOption) {
    return `${filter.label}: ${filter.selectedOption.label}`;
  }
  return filter.label;
};
const isSelected$2 = (filter) => filter.selectedOption !== void 0;
const passThroughMenuProps$1 = (filter) => {
  const {
    id: _id,
    label: _label,
    type: _type,
    selectedOption: _selectedOption,
    simpleDrawerVariant: _simpleDrawerVariant,
    drawerOnly: _drawerOnly,
    ...rest
  } = filter;
  return rest;
};
const singleSelectAdapter = {
  getValue: (filter) => filter.selectedOption,
  setValue: (filter, value) => ({ ...filter, selectedOption: value }),
  reset: (filter) => ({ ...filter, selectedOption: void 0 }),
  isActive: isSelected$2,
  preserveState: (newFilter, existingFilter) => ({
    ...newFilter,
    selectedOption: existingFilter.selectedOption
  }),
  // Options are owned by the consumer; SelectMenuSync handles option identity
  // internally — no rebinding needed here.
  cloneWithItemRefs: (filter) => ({ ...filter }),
  renderBarControl: ({ filter, updateFilter }) => /* @__PURE__ */ jsx(FilterItemWrapper, { children: /* @__PURE__ */ jsx(
    SelectMenuSync,
    {
      ...passThroughMenuProps$1(filter),
      id: filter.id,
      label: filter.label,
      value: filter.selectedOption ?? null,
      onSelectedOptionChange: (option) => updateFilter(filter.id, option ?? void 0, true),
      clear: {
        onClick: () => updateFilter(filter.id, void 0, true)
      },
      trigger: (triggerProps) => /* @__PURE__ */ jsx(
        FilterTriggerButton,
        {
          ...triggerProps,
          filterId: filter.id,
          label: formatLabel$2(filter),
          isSelected: isSelected$2(filter)
        }
      )
    }
  ) }, filter.id),
  renderDrawer: ({ originalFilter, draftFilter, onDraftChange }) => {
    if (originalFilter.simpleDrawerVariant) {
      return /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Radio.Group, { legend: originalFilter.label, children: originalFilter.options.map((option) => /* @__PURE__ */ jsx(
        Radio,
        {
          name: `${originalFilter.id}-radio`,
          value: String(option.id),
          label: option.label,
          checked: draftFilter.selectedOption?.id === option.id,
          onChange: (e) => {
            if (e?.target.checked) {
              const selected = originalFilter.options.find(
                (opt) => String(opt.id) === e.target.value
              );
              onDraftChange(draftFilter.id, selected);
            }
          }
        },
        option.id
      )) }) }, draftFilter.id);
    }
    return /* @__PURE__ */ createElement(
      SelectFieldSync,
      {
        ...passThroughMenuProps$1(originalFilter),
        key: draftFilter.id,
        label: originalFilter.label,
        value: draftFilter.selectedOption ?? null,
        onSelectedOptionChange: (option) => onDraftChange(draftFilter.id, option ?? void 0)
      }
    );
  },
  formatLabel: formatLabel$2,
  isSelected: isSelected$2
};

const FilterTextInput = ({
  filter,
  value,
  onChange,
  layout
}) => {
  const truncate = (s) => filter.maxLength !== void 0 ? s.slice(0, filter.maxLength) : s;
  const counterProps = filter.showCounter ? { showCounter: true, maxLength: filter.maxLength } : { maxLength: filter.maxLength };
  return /* @__PURE__ */ jsx(
    TextField,
    {
      label: filter.label,
      hideLabel: layout === "compact",
      placeholder: filter.placeholder,
      value,
      onChange: (e) => onChange(truncate(e.target.value)),
      ...counterProps
    }
  );
};

const TRIGGER_VALUE_MAX_CHARS = 24;
const formatLabel$1 = (filter) => {
  if (!filter.value) return filter.label;
  const display = filter.value.length > TRIGGER_VALUE_MAX_CHARS ? `${filter.value.slice(0, TRIGGER_VALUE_MAX_CHARS)}…` : filter.value;
  return `${filter.label}: ${display}`;
};
const isSelected$1 = (filter) => filter.value !== void 0 && filter.value !== "";
const textInputAdapter = {
  getValue: (filter) => filter.value ?? "",
  // Normalise empty → undefined on write so `isSelected` / activeFilters lists
  // treat a cleared field as inactive without needing extra guards.
  setValue: (filter, value) => ({ ...filter, value: value || void 0 }),
  reset: (filter) => ({ ...filter, value: void 0 }),
  isActive: isSelected$1,
  preserveState: (newFilter, existingFilter) => ({
    ...newFilter,
    value: existingFilter.value
  }),
  cloneWithItemRefs: (filter) => ({ ...filter }),
  renderBarControl: ({ filter }) => /* @__PURE__ */ jsx(
    FilterPopoverButton,
    {
      filter,
      label: formatLabel$1(filter),
      isSelected: isSelected$1(filter),
      committedValue: filter.value ?? "",
      initialValue: "",
      keepOpenOnUncontrolledChange: true,
      children: ({ value, onChange }) => /* @__PURE__ */ jsx(
        FilterTextInput,
        {
          filter,
          value,
          onChange,
          layout: "compact"
        }
      )
    },
    filter.id
  ),
  renderDrawer: ({ draftFilter, onDraftChange }) => /* @__PURE__ */ jsx(
    FilterTextInput,
    {
      filter: draftFilter,
      value: draftFilter.value ?? "",
      onChange: (value) => onDraftChange(draftFilter.id, value || void 0),
      layout: "grid"
    },
    draftFilter.id
  ),
  formatLabel: formatLabel$1,
  isSelected: isSelected$1
};

const isSelected = (filter) => !!filter.selectedNodes && filter.selectedNodes.length > 0;
const formatLabel = (filter) => {
  const count = filter.selectedNodes?.length ?? 0;
  if (count === 0) return filter.label;
  const countLabel = count.toString();
  return /* @__PURE__ */ jsxs(Fragment, { children: [
    filter.label,
    /* @__PURE__ */ jsx(
      Chip,
      {
        label: countLabel,
        color: "#0265DC",
        size: "small",
        "aria-label": `${countLabel} selected items`
      }
    )
  ] });
};
const passThroughMenuProps = (filter) => {
  const {
    id: _id,
    label: _label,
    type: _type,
    selectedNodes: _selectedNodes,
    drawerOnly: _drawerOnly,
    ...rest
  } = filter;
  return rest;
};
const treeAdapter = {
  getValue: (filter) => filter.selectedNodes ?? [],
  setValue: (filter, value) => ({ ...filter, selectedNodes: value }),
  reset: (filter) => ({ ...filter, selectedNodes: [] }),
  isActive: isSelected,
  preserveState: (newFilter, existingFilter) => ({
    ...newFilter,
    selectedNodes: existingFilter.selectedNodes
  }),
  // The tree's `options` are owned by the consumer; the selected node values
  // are canonical and carry their own id/label — no rebinding needed.
  cloneWithItemRefs: (filter) => ({ ...filter }),
  renderBarControl: ({ filter, updateFilter, controlledFiltering }) => /* @__PURE__ */ jsx(FilterItemWrapper, { children: /* @__PURE__ */ jsx(
    TreeSelectMenuSync,
    {
      ...passThroughMenuProps(filter),
      id: filter.id,
      label: filter.label,
      value: filter.selectedNodes ?? [],
      onSelectedOptionsChange: (nodes) => updateFilter(filter.id, nodes, true),
      confirmation: controlledFiltering,
      clear: {
        onClick: () => updateFilter(filter.id, [], true),
        disabled: !isSelected(filter)
      },
      trigger: (triggerProps) => /* @__PURE__ */ jsx(
        FilterTriggerButton,
        {
          ...triggerProps,
          filterId: filter.id,
          label: formatLabel(filter),
          isSelected: isSelected(filter)
        }
      )
    }
  ) }, filter.id),
  renderDrawer: ({ originalFilter, draftFilter, onDraftChange }) => /* @__PURE__ */ createElement(
    TreeSelectFieldSync,
    {
      ...passThroughMenuProps(originalFilter),
      key: draftFilter.id,
      label: originalFilter.label,
      value: draftFilter.selectedNodes ?? [],
      onSelectedOptionsChange: (nodes) => onDraftChange(draftFilter.id, nodes)
    }
  ),
  formatLabel,
  isSelected
};

const filterAdapters = {
  boolean: booleanAdapter,
  custom: customAdapter,
  singleSelect: singleSelectAdapter,
  multiSelect: multiSelectAdapter,
  date: dateAdapter,
  dateRange: dateRangeAdapter,
  dateList: dateListAdapter,
  asyncSelect: asyncSelectAdapter,
  asyncMultiSelect: asyncMultiSelectAdapter,
  tree: treeAdapter,
  asyncTree: asyncTreeAdapter,
  numericRange: numericRangeAdapter,
  textInput: textInputAdapter,
  search: searchAdapter
};
const unknownAdapter = {
  getValue: () => void 0,
  setValue: (filter) => filter,
  reset: (filter) => filter,
  isActive: () => false,
  preserveState: (newFilter) => newFilter,
  cloneWithItemRefs: (filter) => filter,
  renderBarControl: () => null,
  renderDrawer: () => null,
  formatLabel: (filter) => filter.label,
  isSelected: () => false
};
const getAdapter = (filter) => filterAdapters[filter.type] ?? unknownAdapter;

const getActiveFilters = (filters) => filters.filter((filter) => getAdapter(filter).isActive(filter));
const checkActiveFilters = (filters) => getActiveFilters(filters).length > 0;
const resetFilters = (filters) => filters.map((filter) => getAdapter(filter).reset(filter));
const updateSingleFilter = (filters, filterId, value) => filters.map((filter) => {
  if (filter.id !== filterId) return filter;
  return getAdapter(filter).setValue(filter, value);
});
const hasFilterSelectionChanged = (existingFilter, newFilter) => {
  const existingValue = getAdapter(existingFilter).getValue(existingFilter);
  const newValue = getAdapter(newFilter).getValue(newFilter);
  return existingValue !== newValue;
};
const preserveFilterState = (newFilter, existingFilter) => getAdapter(newFilter).preserveState(newFilter, existingFilter);
const cloneFiltersWithItemRefs = (filters) => filters.map(
  (filter) => getAdapter(filter).cloneWithItemRefs(filter)
);

export { DateListDialog as D, FilterGroupContext as F, checkActiveFilters as a, getAdapter as b, cloneFiltersWithItemRefs as c, FilterItemWrapper as d, FilterTriggerButton as e, getActiveFilters as g, hasFilterSelectionChanged as h, preserveFilterState as p, resetFilters as r, styles as s, updateSingleFilter as u };
//# sourceMappingURL=filter-state-DKXF5MeW.js.map
