function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
/*
 * Copyright 2025 Palantir Technologies, Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { CaretDown, Cross, SmallCross, Tick } from "@blueprintjs/icons";
import React, { useCallback, useState } from "react";
import { Combobox } from "../../base-components/combobox/Combobox.js";
import { Select } from "../../base-components/select/Select.js";
import { PortalDismissLayer } from "../../shared/PortalDismissLayer.js";
import { typedReactMemo } from "../../shared/typedMemo.js";
import comboboxStyles from "../../base-components/combobox/Combobox.module.css";
import selectStyles from "../../base-components/select/Select.module.css";
import dropdownStyles from "./DropdownField.module.css";
const EMPTY_ARRAY = [];

/**
 * SelectDropdown is only used for single-select (the multi-select path
 * always routes to ComboboxDropdown). We keep the `Multiple` generic so
 * the spread from DropdownField type-checks, but SelectDropdown never
 * reads `isMultiple`.
 */

export const DropdownField = typedReactMemo(function ({
  isSearchable = false,
  isMultiple,
  itemToStringLabel,
  renderItemLabel,
  itemToKey,
  value,
  query,
  onQueryChange,
  disableClientSideFiltering,
  popupStatus,
  trailingItem,
  modal = true,
  ...rest
}) {
  // Ensure always controlled from first render: multi-select needs [],
  // single-select needs null. Passing undefined switches Base UI from
  // uncontrolled to controlled and triggers a warning.
  const normalizedValue = value ?? (isMultiple ? EMPTY_ARRAY : null);
  const resolvedItemToStringLabel = itemToStringLabel ?? defaultItemToStringLabel;
  const resolvedRenderItemLabel = renderItemLabel ?? resolvedItemToStringLabel;
  const getKey = useCallback(item => itemToKey?.(item) ?? resolvedItemToStringLabel(item), [itemToKey, resolvedItemToStringLabel]);

  // Multi-select always uses Combobox for the chip-based UI because it looks better
  if (isSearchable || isMultiple) {
    return /*#__PURE__*/React.createElement(ComboboxDropdown, _extends({}, rest, {
      isMultiple: isMultiple,
      value: normalizedValue,
      itemToStringLabel: resolvedItemToStringLabel,
      renderItemLabel: resolvedRenderItemLabel,
      getKey: getKey,
      isSearchable: isSearchable,
      query: query,
      onQueryChange: onQueryChange,
      disableClientSideFiltering: disableClientSideFiltering,
      popupStatus: popupStatus,
      trailingItem: trailingItem,
      modal: modal
    }));
  }

  // TODO: Support trailingItem
  return /*#__PURE__*/React.createElement(SelectDropdown, _extends({}, rest, {
    value: normalizedValue,
    itemToStringLabel: resolvedItemToStringLabel,
    renderItemLabel: resolvedRenderItemLabel,
    getKey: getKey,
    modal: modal
  }));
});
const SelectDropdown = typedReactMemo(function ({
  id,
  value,
  onChange,
  items,
  itemToStringLabel,
  renderItemLabel,
  getKey,
  isItemEqual,
  placeholder,
  portalRef,
  portalContainer,
  onBlur,
  modal = true,
  disabled
}) {
  const [open, setOpen] = useState(false);
  const isOpen = !disabled && open;
  const renderSingleSelectedItemLabel = useCallback(selectedValue => selectedValue == null ? null : renderItemLabel(selectedValue), [renderItemLabel]);
  const handleOpenChange = useCallback(nextOpen => {
    if (disabled) {
      return;
    }
    setOpen(nextOpen);
    // Mark the field as touched when the popover closes so RHF validates.
    // Opening the popover does not trigger validation.
    if (!nextOpen) {
      onBlur?.();
    }
  }, [disabled, onBlur]);
  const handleClear = useCallback(() => {
    // SelectDropdown is always single-select, so cleared value is null.
    onChange?.(null);
    handleOpenChange(false);
  }, [onChange, handleOpenChange]);
  const handleDismiss = useCallback(() => {
    handleOpenChange(false);
  }, [handleOpenChange]);
  return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Select.Root, {
    value: value,
    onValueChange: onChange,
    open: isOpen,
    onOpenChange: handleOpenChange,
    isItemEqualToValue: isItemEqual,
    itemToStringLabel: itemToStringLabel,
    modal: modal,
    disabled: disabled
  }, /*#__PURE__*/React.createElement(Select.Trigger, {
    id: id,
    placeholder: placeholder,
    disabled: disabled
  }, /*#__PURE__*/React.createElement("div", {
    className: selectStyles.osdkSelectValueContainer
  }, /*#__PURE__*/React.createElement(Select.Value, null, renderSingleSelectedItemLabel), placeholder != null && /*#__PURE__*/React.createElement("span", {
    className: selectStyles.osdkSelectPlaceholder
  }, placeholder)), value != null && /*#__PURE__*/React.createElement("span", {
    role: "button",
    "aria-label": "Clear",
    className: selectStyles.osdkSelectClear,
    "aria-disabled": disabled || undefined,
    onMouseDown: disabled ? undefined : preventTriggerOpen,
    onClick: disabled ? undefined : handleClear
  }, /*#__PURE__*/React.createElement(SmallCross, null)), /*#__PURE__*/React.createElement("span", {
    className: selectStyles.osdkSelectIcon
  }, /*#__PURE__*/React.createElement(CaretDown, null))), /*#__PURE__*/React.createElement(Select.Portal, {
    ref: portalRef,
    container: portalContainer
  }, isOpen && modal && /*#__PURE__*/React.createElement(PortalDismissLayer, {
    className: dropdownStyles.osdkSelectDismissLayer,
    onDismiss: handleDismiss
  }), /*#__PURE__*/React.createElement(Select.Positioner, null, /*#__PURE__*/React.createElement(Select.Popup, null, items.map(item => {
    const itemLabel = itemToStringLabel(item);
    return /*#__PURE__*/React.createElement(Select.Item, {
      key: getKey(item),
      value: item,
      label: itemLabel,
      "aria-label": itemLabel
    }, renderItemLabel(item));
  }))))));
});
const ComboboxDropdown = typedReactMemo(function ({
  id,
  value,
  onChange,
  items,
  itemToStringLabel,
  renderItemLabel,
  getKey,
  isItemEqual,
  isMultiple,
  isSearchable,
  placeholder,
  portalRef,
  portalContainer,
  query,
  onQueryChange,
  disableClientSideFiltering,
  popupStatus,
  trailingItem,
  onBlur,
  modal = true,
  disabled
}) {
  const [open, setOpen] = useState(false);
  const isOpen = !disabled && open;
  const hasValue = isMultiple ? Array.isArray(value) && value.length > 0 : value != null;
  const renderSingleSelectedItemLabel = useCallback(selectedValue => selectedValue == null ? null : renderItemLabel(selectedValue), [renderItemLabel]);
  const handleOpenChange = useCallback(nextOpen => {
    setOpen(nextOpen);
    if (!nextOpen) {
      onBlur?.();
    }
  }, [onBlur]);

  // Mark the field as touched on every value change so RHF revalidates
  // immediately — especially important for multi-select where the popup
  // stays open after toggling an item.
  const handleValueChange = useCallback((...args) => {
    onChange?.(...args);
    // Multi-select: popover stays open, so fire onBlur directly.
    // Single-select: popover closes on selection, handleOpenChange(false)
    // already fires onBlur.
    if (isMultiple) {
      onBlur?.();
    }
  }, [onChange, onBlur, isMultiple]);
  const handleClear = useCallback(() => {
    // TypeScript can't narrow the conditional type `Multiple extends true ? V[] : V`
    // at runtime, so we cast through the known parameter type at this single call site.
    const cleared = isMultiple ? EMPTY_ARRAY : null;
    handleValueChange(cleared);
    // Single-select: close after clearing. Multi-select: keep open for continued selection.
    if (!isMultiple) {
      handleOpenChange(false);
    }
  }, [isMultiple, handleValueChange, handleOpenChange]);
  const handleRemoveItem = useCallback(itemToRemove => {
    if (!isMultiple || !Array.isArray(value)) {
      return;
    }
    const next = value.filter(v => isItemEqual != null ? !isItemEqual(v, itemToRemove) : v !== itemToRemove);
    handleValueChange(next);
  }, [isMultiple, value, handleValueChange, isItemEqual]);
  const handleDismiss = useCallback(() => {
    handleOpenChange(false);
  }, [handleOpenChange]);
  const renderItem = useCallback(item => {
    const itemLabel = itemToStringLabel(item);
    return /*#__PURE__*/React.createElement(Combobox.Item, {
      key: getKey(item),
      value: item,
      "aria-label": itemLabel
    }, isMultiple && /*#__PURE__*/React.createElement(Combobox.ItemIndicator, null, /*#__PURE__*/React.createElement(Tick, null)), renderItemLabel(item));
  }, [getKey, isMultiple, itemToStringLabel, renderItemLabel]);
  return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Combobox.Root, {
    value: value,
    onValueChange: handleValueChange,
    open: isOpen,
    onOpenChange: handleOpenChange,
    multiple: isMultiple,
    itemToStringLabel: itemToStringLabel,
    isItemEqualToValue: isItemEqual,
    items: items,
    inputValue: query,
    onInputValueChange: onQueryChange,
    filter: disableClientSideFiltering ? null : undefined,
    disabled: disabled
  }, /*#__PURE__*/React.createElement(Combobox.Trigger, {
    id: id,
    disabled: disabled,
    className: isMultiple ? comboboxStyles.osdkComboboxTriggerMulti : undefined
  }, /*#__PURE__*/React.createElement("div", {
    className: comboboxStyles.osdkComboboxValueContainer
  }, isMultiple && Array.isArray(value) && value.length > 0 ? /*#__PURE__*/React.createElement("div", {
    className: comboboxStyles.osdkComboboxTriggerChips
  }, value.map(item => /*#__PURE__*/React.createElement("span", {
    key: getKey(item),
    className: comboboxStyles.osdkComboboxTriggerChip
  }, renderItemLabel(item), /*#__PURE__*/React.createElement("span", {
    role: "button",
    "aria-label": `Remove ${itemToStringLabel(item)}`,
    className: comboboxStyles.osdkComboboxTriggerChipRemove,
    "aria-disabled": disabled || undefined,
    onMouseDown: disabled ? undefined : preventTriggerOpen,
    onClick: disabled ? undefined : () => handleRemoveItem(item)
  }, /*#__PURE__*/React.createElement(Cross, {
    size: 12
  }))))) : /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Combobox.Value, null, renderSingleSelectedItemLabel), !hasValue && placeholder != null && /*#__PURE__*/React.createElement("span", {
    className: comboboxStyles.osdkComboboxPlaceholder
  }, placeholder))), hasValue && /*#__PURE__*/React.createElement("span", {
    role: "button",
    "aria-label": "Clear",
    className: comboboxStyles.osdkComboboxClear,
    "aria-disabled": disabled || undefined,
    onMouseDown: disabled ? undefined : preventTriggerOpen,
    onClick: disabled ? undefined : handleClear
  }, /*#__PURE__*/React.createElement(SmallCross, null)), /*#__PURE__*/React.createElement(Combobox.Icon, null, /*#__PURE__*/React.createElement(CaretDown, null))), /*#__PURE__*/React.createElement(Combobox.Portal, {
    ref: portalRef,
    container: portalContainer
  }, isOpen && modal && /*#__PURE__*/React.createElement(PortalDismissLayer, {
    className: dropdownStyles.osdkComboboxDismissLayer,
    onDismiss: handleDismiss
  }), /*#__PURE__*/React.createElement(Combobox.Positioner, null, /*#__PURE__*/React.createElement(Combobox.Popup, null, isSearchable && /*#__PURE__*/React.createElement("div", {
    className: comboboxStyles.osdkComboboxPopupSearchInput
  }, /*#__PURE__*/React.createElement(Combobox.SearchInput, {
    placeholder: "Search\u2026"
  })), popupStatus, popupStatus == null && /*#__PURE__*/React.createElement(Combobox.Empty, null, "No results"), /*#__PURE__*/React.createElement(Combobox.List, null, /*#__PURE__*/React.createElement(Combobox.Collection, null, renderItem), trailingItem))))));
});

// Prevent the clear/remove click from bubbling into the trigger
// and toggling the dropdown open/closed.
function preventTriggerOpen(e) {
  e.stopPropagation();
  e.preventDefault();
}
function defaultItemToStringLabel(item) {
  if (item == null || typeof item !== "object") {
    return String(item);
  }
  if ("label" in item && item.label != null && typeof item.label === "string") {
    return item.label;
  }
  return String(item);
}
//# sourceMappingURL=DropdownField.js.map