import { RanElement } from '../../utils';
import '@/components/select/option';
import '@/components/dropdown';
import '@/components/select/dropdown-item';
import { FloatingController } from '../../utils/floating';
import type { Placement } from '../../utils/placement';
import '@/components/input';
import { EventManager } from '../../utils/builder';
interface Option {
    label: string | number;
    value: string | number;
    disabled?: boolean;
}
/**
 * @fires show - The panel is about to appear.
 * @fires after-show - The panel has appeared and any entrance animation has finished.
 * @fires hide - The panel is about to close.
 * @fires after-hide - The panel has closed and any exit animation has finished.
 */
export declare class Select extends RanElement {
    static formAssociated: boolean;
    _internals?: ElementInternals;
    _events: EventManager;
    _searchEvents: EventManager;
    removeTimeId?: NodeJS.Timeout;
    _listboxId: string;
    _activeIndex: number;
    _slot: HTMLSlotElement;
    _shadowDom: ShadowRoot;
    _select: HTMLDivElement;
    _selection: HTMLDivElement;
    _search: HTMLInputElement;
    _icon: HTMLElement;
    _selectDropdown?: HTMLDivElement;
    _selectionDropdown?: HTMLElement;
    /**
     * Positioning, portalling, scroll-following, the enter/exit animation and the
     * show/hide events all live in the shared controller — r-popover drives the
     * same one, so the two cannot drift apart the way their hand-copied
     * reposition listeners had begun to.
     */
    _floating: FloatingController;
    _optionList: Option[];
    _optionLabelMapValue: Map<string, string>;
    _optionValueMapLabel: Map<string, string>;
    _activeOption?: HTMLElement;
    _text: HTMLSpanElement;
    _selector: HTMLDivElement;
    _label: HTMLLabelElement | undefined;
    onSearch?: (this: HTMLElement, ev: Event) => unknown;
    _typeaheadBuffer: string;
    _typeaheadTimeId?: NodeJS.Timeout;
    static get observedAttributes(): string[];
    constructor();
    get value(): string;
    set value(value: string);
    syncFormValue: () => void;
    get required(): boolean;
    set required(value: boolean | string);
    /**
     * @description: 获取字段上方的静态说明文字（label）。
     */
    get label(): string;
    /**
     * @description: 设置字段上方的静态说明文字（label）。
     */
    set label(value: string);
    /**
     * A static caption above the field — same pattern as r-input's `label`
     * (see input/index.ts `listenLabel`), so a labeled select and a labeled
     * input placed side by side in a form line up: same token, same "renders
     * above, reserves its own space, never overlaps" behavior. Associated via
     * `aria-label` (plain text) rather than `aria-labelledby` pointing at the
     * rendered `<label>`'s id: that label lives inside this select's own shadow
     * root, and a plain `aria-labelledby` id-ref cannot cross into a shadow
     * tree — even the host's own child shadow root counts as a separate tree.
     * Verified directly: with `aria-labelledby`, the combobox's computed
     * accessible name came back empty in the accessibility tree.
     */
    private _syncLabel;
    /**
     * Lets `required` be seen by form.checkValidity()/reportValidity()/:invalid,
     * and mirrors it into aria-required/aria-invalid for assistive tech.
     * Disabled selects never block submission, matching native semantics.
     */
    private _updateValidity;
    checkValidity(): boolean;
    reportValidity(): boolean;
    get validity(): ValidityState | undefined;
    get validationMessage(): string;
    /**
     * @description: 原生 form.reset() 时恢复到 defaultValue（若有）或清空选中项
     */
    formResetCallback(): void;
    get defaultValue(): string;
    set defaultValue(value: string);
    get showSearch(): string;
    set showSearch(value: string);
    get type(): string;
    set type(value: string);
    /**
     * Which side of the trigger the panel opens on, with an optional alignment.
     *
     * `bottom`, `bottom-end`, `top-center`, … — the same grammar r-popover takes,
     * because both now position through the same controller. A bare side means
     * `-start`. Typed rather than left as `string`: these are the values the
     * positioner understands, and an editor should say so.
     */
    get placement(): Placement;
    set placement(value: Placement);
    get sheet(): string;
    set sheet(value: string);
    get getPopupContainerId(): string;
    set getPopupContainerId(value: string);
    get dropdownclass(): string;
    set dropdownclass(value: string);
    get trigger(): string;
    set trigger(value: string);
    get disabled(): boolean;
    set disabled(value: boolean | string | undefined | null);
    initAria: () => void;
    updateAriaExpanded: (isExpanded: boolean) => void;
    /**
     * Whether the dropdown is showing.
     *
     * This attribute *is* the state; nothing else infers it. The panel's
     * `style.display` cannot serve that purpose because it lags the state by the
     * length of the exit animation, and every read of it during that window
     * answers about the frame rather than the intent. Reflecting it the way
     * `<details open>` and `<dialog open>` do also puts the state where a
     * consumer can reach it: `:host([open])` in CSS, `select.open = true` from
     * script, and an attribute assertion in a test instead of a poll.
     */
    get open(): boolean;
    set open(value: boolean);
    /** Drive the panel from `open`. Everything below it is the controller's. */
    _applyOpen: () => void;
    /** Open the dropdown. */
    show: () => void;
    /** Close the dropdown. */
    hide: () => void;
    /** Flip the dropdown between open and closed. */
    toggle: () => void;
    getDropdownOptions: () => HTMLElement[];
    syncActiveState: () => void;
    setActiveOptionByIndex: (targetIndex: number) => void;
    /**
     * Vertically center the closed-state label by matching its line-height to the
     * host height.
     *
     * Guarded on a non-zero height: during a custom-element **upgrade** (SSR/DSD
     * markup, or any element whose `value` attribute is present before it is laid
     * out) `attributeChangedCallback` runs before `connectedCallback`, so
     * `getBoundingClientRect()` still reports 0. Writing `line-height: 0px` then
     * collapses the label to invisible even though its text is correct — the
     * component looks empty until something re-selects the option. When there is
     * no layout yet we clear the inline value and let the stylesheet decide;
     * `connectedCallback` re-applies it once the element has a box.
     */
    applyLabelLineHeight: () => void;
    selectOptionElement: (optionElement: HTMLElement | null, shouldDispatch?: boolean) => void;
    isDropdownOpen: () => boolean;
    /**
     * Walk from `from` in the direction of `step` (clamped to the list bounds)
     * and return the first non-disabled option index, or -1 if none exists.
     * Keeps keyboard navigation from ever landing on a disabled option.
     */
    _nextEnabledIndex: (from: number, step: number) => number;
    keydownSelect: (e: KeyboardEvent) => void;
    /**
     * WAI-ARIA combobox type-ahead: typing a printable character jumps to the
     * next option (wrapping) whose label starts with the recently-typed
     * characters, matching the behavior of a native `<select>`.
     */
    _handleTypeahead: (e: KeyboardEvent) => void;
    handlerExternalCss(): void;
    /**
     * @description: 移除 select dropdown
     * @return {*}
     */
    setSelectDropdownDisplayNone: () => void;
    /**
     * @description: 添加 select dropdown
     * @return {*}
     */
    setSelectDropdownDisplayBlock: () => void;
    /**
     * Position the panel against the trigger.
     *
     * Kept as a method because it is part of this element's surface, but the work
     * is the shared controller's — including staying with the trigger when the
     * page scrolls, which this component and r-popover used to implement
     * separately, one carrying a comment that it mirrored the other.
     *
     * @param applyEntranceTransit - Only true for the call that opens the panel.
     * Scroll/resize repositioning reuses this while already open and must not
     * replay the entrance animation on every tick.
     */
    placementPosition: (applyEntranceTransit?: boolean) => void;
    /**
     * @description: 设置下拉框
     * @return {*}
     */
    /**
     * Toggle, not close-then-open. The old body ran both transitions on every
     * click and let the surviving one depend on which animation timer happened to
     * be in flight, so a run of clicks on a stationary pointer produced: open,
     * close, open-and-immediately-close, and an `aria-expanded` that had come
     * apart from what was on screen.
     */
    selectMouseDown: (e: Event) => void;
    removeDropDownTimeId: (e: Event) => void;
    /**
     * @description: 焦点移除的情况，需要移除 select 下拉框
     * @return {*}
     */
    selectBlur: (e: Event) => void;
    /**
     * @description: 选中一个选项的情况
     * @param {MouseEvent} e
     * @return {*}
     */
    clickOption: (e: MouseEvent) => void;
    /**
     * @description: 初始化创建选项下拉框
     * @return {*}
     */
    createOption: () => void;
    /**
     * @description: 移除选项下拉框
     * @return {*}
     */
    removeSelectDropdown: () => void;
    /**
     * @description: 当 select 中有 option 元素的时候，给 dropdown 添加元素
     * @return {*}
     */
    addOptionToSlot: () => void;
    createSelectDropdownContent: (options?: Option[]) => void;
    setDefaultValue: () => void;
    changeSearch: (e: Event) => void;
    clickRemoveSelect: (e: Event) => void;
    connectedCallback(): void;
    /**
     * Re-run the `value` → label/active-option reflection after connect.
     *
     * `syncSelectedFromValue` bails out when `_activeOption` already matches, which
     * is exactly the situation left behind by an upgrade-time sync: the option was
     * marked active but the label was written without layout. Clearing the cached
     * option first forces a full, correct pass.
     */
    reapplyValueAfterConnect: () => void;
    /**
     * (Re)wire the search-box listeners to match the current `showSearch` value.
     * Reactive: abort any previously-registered search listeners first, then
     * re-register only while `showSearch` is truthy. Safe to call on connect and
     * on every `showSearch` attribute change.
     */
    _applyShowSearch: () => void;
    disconnectedCallback(): void;
    attributeChangedCallback(name: string, oldValue: string, newValue: string): void;
    /**
     * Reflect a programmatic `value` change to the closed-state label. Lets
     * `select.value = 'x'` (or setAttribute('value', 'x')) update the displayed
     * selection without the consumer having to "nudge" the active option.
     */
    syncSelectedFromValue: (value: string) => void;
}
export default Select;
