import { r as registerInstance, c as createEvent, h } from './index-67f7ec52.js';
import { d as async, S as Subscriber, f as isFunction, e as isArray, O as Observable } from './scheduleArray-b9669898.js';
import { f as from, m as map, S as SimpleOuterSubscriber, a as SimpleInnerSubscriber, i as innerSubscribe, d as distinctUntilChanged, b as filter } from './filter-aeb65cac.js';

function mergeMap(project, resultSelector, concurrent = Number.POSITIVE_INFINITY) {
    if (typeof resultSelector === 'function') {
        return (source) => source.pipe(mergeMap((a, i) => from(project(a, i)).pipe(map((b, ii) => resultSelector(a, b, i, ii))), concurrent));
    }
    else if (typeof resultSelector === 'number') {
        concurrent = resultSelector;
    }
    return (source) => source.lift(new MergeMapOperator(project, concurrent));
}
class MergeMapOperator {
    constructor(project, concurrent = Number.POSITIVE_INFINITY) {
        this.project = project;
        this.concurrent = concurrent;
    }
    call(observer, source) {
        return source.subscribe(new MergeMapSubscriber(observer, this.project, this.concurrent));
    }
}
class MergeMapSubscriber extends SimpleOuterSubscriber {
    constructor(destination, project, concurrent = Number.POSITIVE_INFINITY) {
        super(destination);
        this.project = project;
        this.concurrent = concurrent;
        this.hasCompleted = false;
        this.buffer = [];
        this.active = 0;
        this.index = 0;
    }
    _next(value) {
        if (this.active < this.concurrent) {
            this._tryNext(value);
        }
        else {
            this.buffer.push(value);
        }
    }
    _tryNext(value) {
        let result;
        const index = this.index++;
        try {
            result = this.project(value, index);
        }
        catch (err) {
            this.destination.error(err);
            return;
        }
        this.active++;
        this._innerSub(result);
    }
    _innerSub(ish) {
        const innerSubscriber = new SimpleInnerSubscriber(this);
        const destination = this.destination;
        destination.add(innerSubscriber);
        const innerSubscription = innerSubscribe(ish, innerSubscriber);
        if (innerSubscription !== innerSubscriber) {
            destination.add(innerSubscription);
        }
    }
    _complete() {
        this.hasCompleted = true;
        if (this.active === 0 && this.buffer.length === 0) {
            this.destination.complete();
        }
        this.unsubscribe();
    }
    notifyNext(innerValue) {
        this.destination.next(innerValue);
    }
    notifyComplete() {
        const buffer = this.buffer;
        this.active--;
        if (buffer.length > 0) {
            this._next(buffer.shift());
        }
        else if (this.active === 0 && this.hasCompleted) {
            this.destination.complete();
        }
    }
}

function debounceTime(dueTime, scheduler = async) {
    return (source) => source.lift(new DebounceTimeOperator(dueTime, scheduler));
}
class DebounceTimeOperator {
    constructor(dueTime, scheduler) {
        this.dueTime = dueTime;
        this.scheduler = scheduler;
    }
    call(subscriber, source) {
        return source.subscribe(new DebounceTimeSubscriber(subscriber, this.dueTime, this.scheduler));
    }
}
class DebounceTimeSubscriber extends Subscriber {
    constructor(destination, dueTime, scheduler) {
        super(destination);
        this.dueTime = dueTime;
        this.scheduler = scheduler;
        this.debouncedSubscription = null;
        this.lastValue = null;
        this.hasValue = false;
    }
    _next(value) {
        this.clearDebounce();
        this.lastValue = value;
        this.hasValue = true;
        this.add(this.debouncedSubscription = this.scheduler.schedule(dispatchNext, this.dueTime, this));
    }
    _complete() {
        this.debouncedNext();
        this.destination.complete();
    }
    debouncedNext() {
        this.clearDebounce();
        if (this.hasValue) {
            const { lastValue } = this;
            this.lastValue = null;
            this.hasValue = false;
            this.destination.next(lastValue);
        }
    }
    clearDebounce() {
        const debouncedSubscription = this.debouncedSubscription;
        if (debouncedSubscription !== null) {
            this.remove(debouncedSubscription);
            debouncedSubscription.unsubscribe();
            this.debouncedSubscription = null;
        }
    }
}
function dispatchNext(subscriber) {
    subscriber.debouncedNext();
}

function noop() { }

function tap(nextOrObserver, error, complete) {
    return function tapOperatorFunction(source) {
        return source.lift(new DoOperator(nextOrObserver, error, complete));
    };
}
class DoOperator {
    constructor(nextOrObserver, error, complete) {
        this.nextOrObserver = nextOrObserver;
        this.error = error;
        this.complete = complete;
    }
    call(subscriber, source) {
        return source.subscribe(new TapSubscriber(subscriber, this.nextOrObserver, this.error, this.complete));
    }
}
class TapSubscriber extends Subscriber {
    constructor(destination, observerOrNext, error, complete) {
        super(destination);
        this._tapNext = noop;
        this._tapError = noop;
        this._tapComplete = noop;
        this._tapError = error || noop;
        this._tapComplete = complete || noop;
        if (isFunction(observerOrNext)) {
            this._context = this;
            this._tapNext = observerOrNext;
        }
        else if (observerOrNext) {
            this._context = observerOrNext;
            this._tapNext = observerOrNext.next || noop;
            this._tapError = observerOrNext.error || noop;
            this._tapComplete = observerOrNext.complete || noop;
        }
    }
    _next(value) {
        try {
            this._tapNext.call(this._context, value);
        }
        catch (err) {
            this.destination.error(err);
            return;
        }
        this.destination.next(value);
    }
    _error(err) {
        try {
            this._tapError.call(this._context, err);
        }
        catch (err) {
            this.destination.error(err);
            return;
        }
        this.destination.error(err);
    }
    _complete() {
        try {
            this._tapComplete.call(this._context);
        }
        catch (err) {
            this.destination.error(err);
            return;
        }
        return this.destination.complete();
    }
}

function fromEvent(target, eventName, options, resultSelector) {
    if (isFunction(options)) {
        resultSelector = options;
        options = undefined;
    }
    if (resultSelector) {
        return fromEvent(target, eventName, options).pipe(map(args => isArray(args) ? resultSelector(...args) : resultSelector(args)));
    }
    return new Observable(subscriber => {
        function handler(e) {
            if (arguments.length > 1) {
                subscriber.next(Array.prototype.slice.call(arguments));
            }
            else {
                subscriber.next(e);
            }
        }
        setupSubscription(target, eventName, handler, subscriber, options);
    });
}
function setupSubscription(sourceObj, eventName, handler, subscriber, options) {
    let unsubscribe;
    if (isEventTarget(sourceObj)) {
        const source = sourceObj;
        sourceObj.addEventListener(eventName, handler, options);
        unsubscribe = () => source.removeEventListener(eventName, handler, options);
    }
    else if (isJQueryStyleEventEmitter(sourceObj)) {
        const source = sourceObj;
        sourceObj.on(eventName, handler);
        unsubscribe = () => source.off(eventName, handler);
    }
    else if (isNodeStyleEventEmitter(sourceObj)) {
        const source = sourceObj;
        sourceObj.addListener(eventName, handler);
        unsubscribe = () => source.removeListener(eventName, handler);
    }
    else if (sourceObj && sourceObj.length) {
        for (let i = 0, len = sourceObj.length; i < len; i++) {
            setupSubscription(sourceObj[i], eventName, handler, subscriber, options);
        }
    }
    else {
        throw new TypeError('Invalid event target');
    }
    subscriber.add(unsubscribe);
}
function isNodeStyleEventEmitter(sourceObj) {
    return sourceObj && typeof sourceObj.addListener === 'function' && typeof sourceObj.removeListener === 'function';
}
function isJQueryStyleEventEmitter(sourceObj) {
    return sourceObj && typeof sourceObj.on === 'function' && typeof sourceObj.off === 'function';
}
function isEventTarget(sourceObj) {
    return sourceObj && typeof sourceObj.addEventListener === 'function' && typeof sourceObj.removeEventListener === 'function';
}

const dropdownAsyncCss = "fl-dropdown .dropdown-menu{max-height:min(20rem, 50vh)}fl-dropdown .dropdown-menu .dropdown-item{cursor:pointer}fl-dropdown .dropdown-menu .dropdown-item.selected{background-color:rgba(253, 189, 0, 0.5)}";

const DEFAULT_SEARCH_LENGTH = 3;
const SelectInputAsync = class {
  constructor(hostRef) {
    registerInstance(this, hostRef);
    this.valueChanged = createEvent(this, "valueChanged", 7);
    this.required = false;
    this.disabled = false;
    this.minSearchStringLength = DEFAULT_SEARCH_LENGTH;
    this.isMouseOver = false;
    this.searchState = 'pristine';
    this.inputValue = '';
    this.isDropdownVisible = false;
    this.filteredOptions = [];
    this.shouldExecuteSearch = (searchQuery) => {
      var _a;
      return (this.isDropdownVisible &&
        (searchQuery === null || searchQuery === void 0 ? void 0 : searchQuery.length) >= this.minSearchStringLength &&
        ((_a = this.selectedOption) === null || _a === void 0 ? void 0 : _a.label) !== searchQuery);
    };
    this.onBeginSearch = (searchQuery) => {
      this.inputValue = searchQuery;
      this.searchState = 'in progress';
    };
    this.onCompleteSearch = (results) => {
      this.filteredOptions = results;
      this.highlightedOptionIndex = undefined;
      this.searchState = 'done';
    };
    this.renderFilteredResults = () => {
      if (this.searchState === 'pristine') {
        return h("span", { class: "dropdown-item disabled" }, "Start typing to find the results");
      }
      if (this.searchState === 'in progress') {
        return (h("div", { class: "d-flex justify-content-end align-items-center pr-4" }, h("span", { class: "dropdown-item disabled" }, "Searching..."), h("i", { class: "dot-falling" })));
      }
      if (this.filteredOptions.length === 0) {
        return h("span", { class: "dropdown-item disabled" }, "No items match your search");
      }
      return this.filteredOptions.map((option, index) => (h("span", { class: {
          'dropdown-item text-wrap': true,
          selected: this.isOptionSelected(option),
          active: this.highlightedOptionIndex === index
        }, onClick: (_event) => {
          this.toggleDropdown(false);
          this.selectOption(option);
        } }, option.label)));
    };
    this.resetInput = () => {
      var _a, _b;
      this.inputValue = (_b = (_a = this.selectedOption) === null || _a === void 0 ? void 0 : _a.label) !== null && _b !== void 0 ? _b : '';
    };
    this.toggleDropdown = (newState) => {
      this.isDropdownVisible = newState;
    };
    this.processKeyboardNavigation = (event) => {
      const ENTER_KEY = 'Enter';
      const DOWN_KEY = 'ArrowDown';
      const UP_KEY = 'ArrowUp';
      const ESC_KEY = 'Escape';
      switch (event.key) {
        case DOWN_KEY:
          this.toggleDropdown(true);
          this.highlightNextItem();
          return true;
        case UP_KEY:
          this.highlightPreviousItem();
          return true;
        case ENTER_KEY:
          if (this.highlightedOptionIndex !== undefined) {
            this.toggleDropdown(false);
            this.selectOption(this.filteredOptions[this.highlightedOptionIndex]);
          }
          return true;
        case ESC_KEY:
          this.inputElement.blur();
          return true;
      }
      return false;
    };
    this.highlightPreviousItem = () => {
      if (this.filteredOptions.length === 0) {
        return;
      }
      this.highlightedOptionIndex =
        this.highlightedOptionIndex === undefined ? 0 : Math.max(this.highlightedOptionIndex - 1, 0);
    };
    this.highlightNextItem = () => {
      if (this.filteredOptions.length === 0) {
        return;
      }
      this.highlightedOptionIndex =
        this.highlightedOptionIndex === undefined
          ? 0
          : Math.min(this.highlightedOptionIndex + 1, this.filteredOptions.length - 1);
    };
    this.selectOption = (option) => {
      this.selectedOption = option;
      this.inputValue = option.label;
      this.valueChanged.emit(option);
    };
    this.isOptionSelected = (option) => {
      var _a;
      return ((_a = this.selectedOption) === null || _a === void 0 ? void 0 : _a.label) === option.label;
    };
  }
  componentWillLoad() {
    this.selectedOption = this.value;
  }
  componentDidLoad() {
    this.searchResultsSubscription = fromEvent(this.inputElement, 'keyup')
      .pipe(debounceTime(500), map((_) => this.inputElement.value), distinctUntilChanged(), filter(this.shouldExecuteSearch), tap(this.onBeginSearch), mergeMap(this._searchFunction), tap(this.onCompleteSearch))
      .subscribe();
  }
  componentDidUnload() {
    this.searchResultsSubscription.unsubscribe();
  }
  handleFocus() {
    this.toggleDropdown(true);
  }
  handleBlur() {
    if (this.isMouseOver) {
      return;
    }
    this.toggleDropdown(false);
    this.highlightedOptionIndex = undefined;
    this.resetInput();
  }
  handleKeyDown(event) {
    if (this.processKeyboardNavigation(event)) {
      event.preventDefault();
    }
  }
  render() {
    var _a;
    return [
      h("div", { class: "dropdown" }, h("input", { type: "text", class: "form-control", placeholder: this.placeholder, required: this.required, disabled: this.disabled, value: this.inputValue, ref: (el) => (this.inputElement = el) }), h("div", { class: {
          'invalid-feedback': true,
          'd-none': this.isDropdownVisible
        } }, (_a = this.requiredValidationMessage) !== null && _a !== void 0 ? _a : 'Required.'), h("div", { class: {
          'dropdown-menu shadow mt-0 w-100 overflow-auto': true,
          show: this.isDropdownVisible
        }, onMouseEnter: (_event) => (this.isMouseOver = true), onMouseLeave: (_event) => (this.isMouseOver = false) }, this.renderFilteredResults()))
    ];
  }
  get _searchFunction() {
    if (this.searchFunction === undefined) {
      throw new Error("Can't render <fl-dropdown-async/> component with no searchFunction");
    }
    return this.searchFunction;
  }
};
SelectInputAsync.style = dropdownAsyncCss;

export { SelectInputAsync as fl_dropdown_async };
