import { jsx, jsxs, Fragment } from "react/jsx-runtime";
import * as React from "react";
import { ChevronDown, X } from "lucide-react";
import { cn } from "../../lib/utils.js";
import { bareInputStyles, fieldWrapperStyles, EMPTY_DISPLAY, fieldDisplayTextClass, nakedCellRowModeAlign } from "../Field/field-wrapper.js";
import { Tag } from "../Tag/tag.js";
import { ItemPrefix, ItemSuffix, ICON_SIZE, ItemInlineAction } from "../../patterns/element-anatomy/item-anatomy.js";
import { useFieldContext, useResolvedFieldInvalid, useResolvedFieldDisabled, useResolvedFieldSize, useResolvedFieldMode, useResolvedFieldVariant } from "../Field/field-context.js";
import { SelectMenu } from "../SelectMenu/select-menu.js";
import { useIsTouchDevice } from "../../hooks/use-is-touch-device.js";
import { useControllable } from "../../hooks/use-controllable.js";
const tagPadding = {
  sm: "px-[calc((var(--field-height-sm)_-_1.25rem)_/_2)]",
  md: "px-[calc((var(--field-height-md)_-_1.5rem)_/_2)]",
  lg: "px-[calc((var(--field-height-lg)_-_1.5rem)_/_2)]"
};
const getIconSize = (size) => ICON_SIZE[size];
function SelectClearButton({
  size,
  onClear,
  stopPropagation = false
}) {
  return /* @__PURE__ */ jsx("span", { className: "relative z-10", children: /* @__PURE__ */ jsx(
    ItemInlineAction,
    {
      size,
      action: {
        icon: X,
        label: "清除選取",
        // i18n-allow: DS default inline-action label
        onClick: stopPropagation ? (e) => {
          e == null ? void 0 : e.stopPropagation();
          onClear();
        } : () => onClear()
      }
    }
  ) });
}
SelectClearButton.displayName = "SelectClearButton";
function CustomSelectTriggerContent({
  searchable,
  open,
  isTextDisplay,
  size,
  value,
  selectedLabel,
  selectedOpt,
  SelectedIcon,
  StartIcon,
  iconSize,
  placeholder,
  search,
  setSearch,
  inputRef,
  selectedItemRenderer
}) {
  if (searchable && open) {
    const triggerEmptyPlaceholder = placeholder || "搜尋…";
    const showSelectedOverlay = !search && selectedLabel;
    return /* @__PURE__ */ jsxs("span", { className: "relative flex-1 min-w-0 inline-flex items-center", children: [
      StartIcon && /* @__PURE__ */ jsx(ItemPrefix, { children: /* @__PURE__ */ jsx(StartIcon, { size: iconSize, className: "text-fg-muted pointer-events-none", "aria-hidden": true }) }),
      /* @__PURE__ */ jsx(
        "input",
        {
          ref: inputRef,
          value: search,
          onChange: (e) => setSearch(e.target.value),
          placeholder: showSelectedOverlay ? "" : triggerEmptyPlaceholder,
          className: cn(bareInputStyles, "cursor-text"),
          autoFocus: true
        }
      ),
      showSelectedOverlay && // 2026-05-16 Bug B 真 root cause fix(Claude+Codex M31 Step 5 比稿 consensus,user verbatim
      // 「修了一百次還沒好」+ codex cite W3C CSS Overflow / MDN / Mozilla Bug 972664#c1):
      // 原 `inline-flex items-center truncate` 套同一 span,text 變 anonymous flex item →
      // `text-overflow:ellipsis` 對 anonymous item 不 styleable → ellipsis dots 不可見(text 純 clip)。
      // 對齊 `person-display.tsx:148` 既有 DS canonical:outer flex container + inner truncate 真實 box。
      // DS-wide grep 29 個 truncate 都遵此 pattern,只本處違反 — 修齊。
      /* @__PURE__ */ jsx(
        "span",
        {
          "aria-hidden": "true",
          className: "pointer-events-none absolute inset-0 flex items-center text-fg-muted",
          children: /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: selectedLabel })
        }
      )
    ] });
  }
  if (selectedItemRenderer && value && selectedOpt) {
    return /* @__PURE__ */ jsxs(Fragment, { children: [
      StartIcon && /* @__PURE__ */ jsx(ItemPrefix, { children: /* @__PURE__ */ jsx(StartIcon, { size: iconSize, className: "text-fg-muted pointer-events-none", "aria-hidden": true }) }),
      /* @__PURE__ */ jsx("span", { className: cn("flex-1 min-w-0 inline-flex items-center", nakedCellRowModeAlign), children: selectedItemRenderer(selectedOpt) })
    ] });
  }
  if (isTextDisplay) {
    return /* @__PURE__ */ jsxs(Fragment, { children: [
      StartIcon && /* @__PURE__ */ jsx(ItemPrefix, { children: /* @__PURE__ */ jsx(StartIcon, { size: iconSize, className: "text-fg-muted pointer-events-none", "aria-hidden": true }) }),
      !StartIcon && SelectedIcon && value && /* @__PURE__ */ jsx(ItemPrefix, { children: /* @__PURE__ */ jsx(SelectedIcon, { size: iconSize, className: "pointer-events-none", "aria-hidden": true }) }),
      /* @__PURE__ */ jsx("span", { className: cn("flex-1 min-w-0 truncate", !value && "text-fg-muted"), children: value ? selectedLabel : placeholder ?? "選擇…" })
    ] });
  }
  return /* @__PURE__ */ jsxs(Fragment, { children: [
    value && (selectedOpt == null ? void 0 : selectedOpt.tagVariant) ? /* @__PURE__ */ jsx(Tag, { size, color: selectedOpt.tagVariant, className: "shrink-0 pointer-events-none", children: selectedLabel }) : value ? /* @__PURE__ */ jsx(Tag, { size, className: "shrink-0 pointer-events-none", children: selectedLabel }) : /* @__PURE__ */ jsx("span", { className: "text-fg-muted", children: placeholder ?? "選擇…" }),
    /* @__PURE__ */ jsx("span", { className: "flex-1" })
  ] });
}
CustomSelectTriggerContent.displayName = "CustomSelectTriggerContent";
function ReadonlyDisplay({
  mode,
  variant: variantProp,
  size,
  options,
  value,
  display,
  startIcon: StartIcon,
  className,
  placeholder,
  showDisplayEndIcon
}) {
  var _a;
  const resolvedMode = mode ?? "readonly";
  const variant = variantProp ?? "default";
  const sz = size ?? "md";
  const iconSize = getIconSize(sz);
  const label = ((_a = options == null ? void 0 : options.find((o) => o.value === value)) == null ? void 0 : _a.label) ?? value;
  const iconColor = resolvedMode === "disabled" ? "text-fg-disabled" : "text-fg-muted";
  const isTextDisplay = display !== "tag";
  const emptyColorCls = resolvedMode === "disabled" ? "text-fg-disabled" : "text-fg-muted";
  const emptyText = placeholder ?? EMPTY_DISPLAY;
  if (resolvedMode === "display") {
    if (!showDisplayEndIcon) {
      if (!value) return /* @__PURE__ */ jsx("span", { className: cn(fieldDisplayTextClass(sz), "text-fg-muted", className), children: emptyText });
      if (isTextDisplay) return /* @__PURE__ */ jsx("span", { className: cn(fieldDisplayTextClass(sz), "truncate", className), children: label });
      const selOpt2 = options == null ? void 0 : options.find((o) => o.value === value);
      const tVariant2 = selOpt2 == null ? void 0 : selOpt2.tagVariant;
      return /* @__PURE__ */ jsx(Tag, { size: sz, color: tVariant2, className, children: label });
    }
    const selOpt = options == null ? void 0 : options.find((o) => o.value === value);
    const tVariant = selOpt == null ? void 0 : selOpt.tagVariant;
    return /* @__PURE__ */ jsxs(
      "div",
      {
        className: cn(fieldWrapperStyles({ mode: "display", variant, size: sz }), value && !isTextDisplay && tagPadding[sz], className),
        "data-field-mode": "display",
        children: [
          isTextDisplay ? /* @__PURE__ */ jsx("span", { className: cn(bareInputStyles, "flex-1 min-w-0 truncate", !value && emptyColorCls), children: value ? label : emptyText }) : value ? /* @__PURE__ */ jsx(Tag, { size: sz, color: tVariant, children: label }) : /* @__PURE__ */ jsx("span", { className: cn("flex-1 min-w-0", emptyColorCls), children: emptyText }),
          /* @__PURE__ */ jsx(ItemSuffix, { children: /* @__PURE__ */ jsx(ChevronDown, { size: iconSize, className: "text-fg-muted pointer-events-none", "aria-hidden": true }) })
        ]
      }
    );
  }
  if (isTextDisplay) {
    return /* @__PURE__ */ jsxs("div", { className: cn(fieldWrapperStyles({ mode: resolvedMode, variant, size: sz }), className), "data-field-mode": resolvedMode, children: [
      StartIcon && /* @__PURE__ */ jsx(ItemPrefix, { children: /* @__PURE__ */ jsx(StartIcon, { size: iconSize, className: cn("pointer-events-none", iconColor), "aria-hidden": true }) }),
      /* @__PURE__ */ jsx("span", { className: cn("flex-1 min-w-0 truncate", resolvedMode === "disabled" && "text-fg-disabled"), children: value ? label : /* @__PURE__ */ jsx("span", { className: emptyColorCls, children: emptyText }) })
    ] });
  }
  const selectedOpt = options == null ? void 0 : options.find((o) => o.value === value);
  const tagVariant = selectedOpt == null ? void 0 : selectedOpt.tagVariant;
  return /* @__PURE__ */ jsx("div", { className: cn(fieldWrapperStyles({ mode: resolvedMode, variant, size: sz }), value && tagPadding[sz], className), "data-field-mode": resolvedMode, children: value ? /* @__PURE__ */ jsx(Tag, { size: sz, color: tagVariant, children: label }) : /* @__PURE__ */ jsx("span", { className: emptyColorCls, children: emptyText }) });
}
const NativeSelect = React.forwardRef(
  ({ mode, variant: variantProp, error: errorProp = false, size: sizeProp, options, value: valueProp, defaultValue, onChange, placeholder, className, disabled: disabledProp, clearable = false, display = "plain", startIcon: StartIcon, showDisplayEndIcon, id: idProp, "aria-describedby": ariaDescribedByProp, "aria-errormessage": ariaErrorMessageProp, ...props }, ref) => {
    const fieldCtx = useFieldContext();
    const error = useResolvedFieldInvalid(errorProp);
    const disabled = useResolvedFieldDisabled(disabledProp);
    const size = useResolvedFieldSize(sizeProp);
    const resolvedMode = useResolvedFieldMode({ mode, disabled });
    const variant = useResolvedFieldVariant(variantProp);
    const iconSize = getIconSize(size);
    const [value, setValue] = useControllable({
      value: valueProp,
      defaultValue: defaultValue ?? null,
      onChange: onChange ? (next) => onChange(next ?? "") : void 0
    });
    const handleNativeChange = (v) => setValue(v);
    const showClear = clearable && value && resolvedMode === "edit";
    const isTextDisplay = display === "plain";
    const selectRef = React.useRef(null);
    const setSelectRef = React.useCallback((el) => {
      selectRef.current = el;
      if (typeof ref === "function") ref(el);
      else if (ref) ref.current = el;
    }, [ref]);
    if (resolvedMode !== "edit") {
      return /* @__PURE__ */ jsx(ReadonlyDisplay, { mode: resolvedMode, variant, size, options, value, display, startIcon: StartIcon, className, placeholder, showDisplayEndIcon });
    }
    const selectEl = /* @__PURE__ */ jsxs(
      "select",
      {
        ref: setSelectRef,
        id: idProp ?? (fieldCtx == null ? void 0 : fieldCtx.id),
        value: value ?? "",
        onChange: (e) => handleNativeChange(e.target.value),
        disabled,
        "aria-invalid": error || void 0,
        "aria-required": (fieldCtx == null ? void 0 : fieldCtx.required) || void 0,
        "aria-describedby": ariaDescribedByProp ?? (fieldCtx == null ? void 0 : fieldCtx.descriptionId),
        "aria-errormessage": ariaErrorMessageProp ?? (error ? fieldCtx == null ? void 0 : fieldCtx.errorId : void 0),
        className: cn(bareInputStyles, "cursor-pointer appearance-none", !value && "text-fg-muted", !isTextDisplay && value && "absolute inset-0 w-full h-full opacity-0 z-0"),
        ...props,
        children: [
          placeholder && /* @__PURE__ */ jsx("option", { value: "", disabled: true, children: placeholder }),
          options.map((opt) => /* @__PURE__ */ jsx("option", { value: opt.value, children: opt.label }, opt.value))
        ]
      }
    );
    const clearEl = showClear ? /* @__PURE__ */ jsx(SelectClearButton, { size: size ?? "md", onClear: () => handleNativeChange("") }) : null;
    const chevronEl = /* @__PURE__ */ jsx(ItemSuffix, { className: "relative z-10 pointer-events-none", children: /* @__PURE__ */ jsx(ChevronDown, { size: iconSize, className: "text-fg-muted", "aria-hidden": true }) });
    const selectedOpt = options == null ? void 0 : options.find((o) => o.value === value);
    const label = (selectedOpt == null ? void 0 : selectedOpt.label) ?? value;
    const nativeTagVariant = selectedOpt == null ? void 0 : selectedOpt.tagVariant;
    const SelectedOptIcon = selectedOpt == null ? void 0 : selectedOpt.icon;
    if (!isTextDisplay) {
      return /* @__PURE__ */ jsxs(
        "div",
        {
          className: cn(
            fieldWrapperStyles({ mode: "edit", variant, size }),
            value && tagPadding[size],
            "relative",
            error && ["border-error hover:border-error-hover", "focus-within:border-error focus-within:hover:border-error"],
            className
          ),
          style: { paddingRight: "0.75rem" },
          "data-field-mode": "edit",
          "data-error": error ? "" : void 0,
          children: [
            value ? /* @__PURE__ */ jsx(Tag, { size, color: nativeTagVariant, className: "shrink-0 relative z-10 pointer-events-none", children: label }) : /* @__PURE__ */ jsx("span", { className: "text-fg-muted", children: placeholder ?? "選擇..." }),
            selectEl,
            /* @__PURE__ */ jsx("span", { className: "flex-1" }),
            clearEl,
            chevronEl
          ]
        }
      );
    }
    return /* @__PURE__ */ jsxs(
      "div",
      {
        className: cn(
          fieldWrapperStyles({ mode: "edit", variant, size }),
          error && ["border-error hover:border-error-hover", "focus-within:border-error focus-within:hover:border-error"],
          className
        ),
        "data-field-mode": "edit",
        "data-error": error ? "" : void 0,
        children: [
          StartIcon && /* @__PURE__ */ jsx(ItemPrefix, { children: /* @__PURE__ */ jsx(StartIcon, { size: iconSize, className: "text-fg-muted pointer-events-none", "aria-hidden": true }) }),
          !StartIcon && SelectedOptIcon && value && /* @__PURE__ */ jsx(ItemPrefix, { children: /* @__PURE__ */ jsx(SelectedOptIcon, { size: iconSize, className: "pointer-events-none", "aria-hidden": true }) }),
          selectEl,
          clearEl,
          chevronEl
        ]
      }
    );
  }
);
NativeSelect.displayName = "NativeSelect";
const CustomSelect = React.forwardRef(
  ({ mode, variant: variantProp, error: errorProp = false, size: sizeProp, options, groups, value: valueProp, defaultValue, onChange, placeholder, className, disabled: disabledProp, clearable = false, display = "plain", startIcon: StartIcon, searchable = false, loading, minRows, defaultOpen = false, onOpenChange, selectedItemRenderer, showDisplayEndIcon, id: idProp, "aria-describedby": ariaDescribedByProp, "aria-errormessage": ariaErrorMessageProp, "aria-label": ariaLabel }, ref) => {
    const fieldCtx = useFieldContext();
    const error = useResolvedFieldInvalid(errorProp);
    const disabled = useResolvedFieldDisabled(disabledProp);
    const size = useResolvedFieldSize(sizeProp);
    const resolvedMode = useResolvedFieldMode({ mode, disabled });
    const variant = useResolvedFieldVariant(variantProp);
    const iconSize = getIconSize(size);
    const [value, setValue] = useControllable({
      value: valueProp,
      defaultValue: defaultValue ?? null,
      onChange: onChange ? (next) => onChange(next ?? "") : void 0
    });
    const showClear = clearable && value && resolvedMode === "edit";
    const isTextDisplay = display === "plain";
    const [open, setOpen] = React.useState(defaultOpen);
    const [search, setSearch] = React.useState("");
    const inputRef = React.useRef(null);
    React.useEffect(() => {
      if (!open) setSearch("");
    }, [open]);
    const selectedOpt = options == null ? void 0 : options.find((o) => o.value === value);
    const selectedLabel = (selectedOpt == null ? void 0 : selectedOpt.label) ?? value ?? "";
    const SelectedIcon = selectedOpt == null ? void 0 : selectedOpt.icon;
    const filteredOptions = searchable && search ? options.filter((o) => o.label.toLowerCase().includes(search.toLowerCase())) : options;
    const menuOptions = React.useMemo(
      () => filteredOptions.map((opt) => ({
        value: opt.value,
        label: opt.label,
        icon: isTextDisplay ? opt.icon : void 0,
        avatar: opt.avatar,
        description: opt.description,
        disabled: opt.disabled,
        group: opt.group
      })),
      [filteredOptions, isTextDisplay]
    );
    const renderLabel = React.useMemo(() => {
      if (isTextDisplay) return void 0;
      return (menuOpt) => {
        const srcOpt = options.find((o) => o.value === menuOpt.value);
        if (srcOpt == null ? void 0 : srcOpt.tagVariant) {
          return /* @__PURE__ */ jsx(Tag, { size, color: srcOpt.tagVariant, children: menuOpt.label });
        }
        return menuOpt.label;
      };
    }, [isTextDisplay, options, size]);
    const handleValueChange = React.useCallback(
      (newValue) => {
        setValue(Array.isArray(newValue) ? newValue[0] : newValue);
      },
      [setValue]
    );
    if (resolvedMode !== "edit") {
      return /* @__PURE__ */ jsx(ReadonlyDisplay, { mode: resolvedMode, variant, size, options, value, display, startIcon: StartIcon, className, placeholder, showDisplayEndIcon });
    }
    const clearEl = showClear ? /* @__PURE__ */ jsx(SelectClearButton, { size: size ?? "md", onClear: () => setValue(""), stopPropagation: true }) : null;
    const chevronEl = /* @__PURE__ */ jsx(ItemSuffix, { children: /* @__PURE__ */ jsx(ChevronDown, { size: iconSize, className: cn("text-fg-muted transition-transform", open && "rotate-180"), "aria-hidden": true }) });
    const triggerContent = /* @__PURE__ */ jsx(
      CustomSelectTriggerContent,
      {
        searchable,
        open,
        isTextDisplay,
        size,
        value,
        selectedLabel,
        selectedOpt,
        SelectedIcon,
        StartIcon,
        iconSize,
        placeholder,
        search,
        setSearch,
        inputRef,
        selectedItemRenderer
      }
    );
    const trigger = /* @__PURE__ */ jsxs(
      "div",
      {
        ref,
        id: idProp ?? (fieldCtx == null ? void 0 : fieldCtx.id),
        role: "combobox",
        "aria-expanded": open,
        "aria-haspopup": "listbox",
        "aria-label": ariaLabel,
        "aria-invalid": error || void 0,
        "aria-required": (fieldCtx == null ? void 0 : fieldCtx.required) || void 0,
        "aria-describedby": ariaDescribedByProp ?? (fieldCtx == null ? void 0 : fieldCtx.descriptionId),
        "aria-errormessage": ariaErrorMessageProp ?? (error ? fieldCtx == null ? void 0 : fieldCtx.errorId : void 0),
        tabIndex: 0,
        className: cn(
          fieldWrapperStyles({ mode: "edit", variant, size }),
          !isTextDisplay && value && !searchable && tagPadding[size],
          // 2026-05-06 v13.3 SSOT retire:per-control `open && 'border-primary'` 移除。Field default
          // state machine `data-[state=open]:border-border-hover`(灰深)處理 open;若 trigger focused
          // (Radix focus on open),focus-within:!border-primary 強制勝出顯藍。focus dominates everything
          // 全 DS 一致(Material/Polaris/Ant 共識),改 Field default 一處全 control 自動跟動。
          error && ["border-error hover:border-error-hover", "focus-within:border-error focus-within:hover:border-error"],
          "cursor-pointer",
          className
        ),
        style: !isTextDisplay ? { paddingRight: "0.75rem" } : void 0,
        "data-field-mode": "edit",
        "data-error": error ? "" : void 0,
        onKeyDown: (e) => {
          if (e.key === "Enter" || e.key === " ") {
            if (!searchable) {
              e.preventDefault();
              setOpen(true);
            }
          }
          if (e.key === "Escape") setOpen(false);
        },
        children: [
          triggerContent,
          clearEl,
          chevronEl
        ]
      }
    );
    return /* @__PURE__ */ jsx(
      SelectMenu,
      {
        options: menuOptions,
        groups,
        value: value ?? null,
        onValueChange: handleValueChange,
        searchable: false,
        loading,
        size,
        minRows,
        open,
        onOpenChange: (o) => {
          setOpen(o);
          onOpenChange == null ? void 0 : onOpenChange(o);
        },
        renderLabel,
        onOpenAutoFocus: searchable ? (e) => {
          var _a;
          e.preventDefault();
          (_a = inputRef.current) == null ? void 0 : _a.focus();
        } : void 0,
        children: trigger
      }
    );
  }
);
CustomSelect.displayName = "CustomSelect";
const Select = React.forwardRef(
  (props, ref) => {
    const isMobile = useIsTouchDevice();
    if (isMobile) {
      return /* @__PURE__ */ jsx(NativeSelect, { ref, ...props });
    }
    return /* @__PURE__ */ jsx(CustomSelect, { ref, ...props });
  }
);
Select.displayName = "Select";
const selectMeta = {
  component: "Select",
  family: 4,
  variants: {},
  sizes: {},
  states: ["default", "hover", "active", "focus-visible", "disabled"],
  tokens: {
    bg: [],
    fg: ["text-fg-disabled", "text-fg-muted"],
    ring: []
  }
};
export {
  Select,
  selectMeta
};
//# sourceMappingURL=select.js.map
