function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); }
function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
import { assign, Machine, send } from 'xstate';
import { SYMBOL_ALL } from './lib/constants';
export var ACTION_TYPES = {
  SYNC: 'SYNC',
  OPEN: 'OPEN',
  CLOSE: 'CLOSE',
  TOGGLE: 'TOGGLE',
  FOCUS: 'FOCUS',
  BLUR: 'BLUR',
  SELECT_FOCUSED_ITEM: 'SELECT_FOCUSED_ITEM',
  SELECT_ITEM: 'SELECT_ITEM',
  DESELECT_ITEM: 'DESELECT_ITEM',
  CHANGE_COMMIT: 'CHANGE_COMMIT',
  CHANGE_COMMIT_ABORT: 'CHANGE_COMMIT_ABORT',
  ITEM_CLICK: 'ITEM_CLICK',
  SEARCH_QUERY_UPDATE: 'SEARCH_QUERY_UPDATE',
  MOUSE_MOVE: 'MOUSE_MOVE',
  KEY_PRESS: 'KEY_PRESS',
  FOCUS_NEXT_ITEM: 'FOCUS_NEXT_ITEM',
  FOCUS_PREV_ITEM: 'FOCUS_PREV_ITEM'
};
var isEqualOptions = function isEqualOptions(a, b) {
  return a === b || a.value === b.value;
};
var includesOption = function includesOption(arr, option) {
  return typeof option !== 'undefined' && (arr.includes(option) || arr.some(function (x) {
    return x.value === option.value;
  }));
};
export var SelectMachine = Machine({
  id: 'inputSelect',
  type: 'parallel',
  context: {
    error: '',
    success: false,
    options: [],
    selectedItems: [],
    disabled: false,
    actions: [],
    open: true,
    itemFocusIdx: null,
    searchQuery: '',
    extraInfo: '',
    multiselect: false,
    label: '',
    lastNavigationType: null,
    placeholder: '',
    showSearch: false,
    visibleOptions: [],
    id: 'id-from-props',
    valueFromProps: [],
    uncommittedSelectedItems: [],
    disableSearchComponent: false,
    fullscreenOnMobile: false,
    preventScroll: false
  },
  on: _defineProperty({}, ACTION_TYPES.SYNC, {
    actions: 'syncProps',
    target: ['selection.unknown', 'interaction.unknown', 'open.unknown', 'correctness.unknown']
  }),
  states: {
    open: {
      initial: 'unknown',
      on: _defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty({}, ACTION_TYPES.OPEN, {
        target: '.on',
        actions: 'restoreFocusOrFocusFirst',
        cond: function cond(ctx) {
          return ctx.actions.length > 0 || ctx.visibleOptions.length > 0;
        }
      }), ACTION_TYPES.CLOSE, {
        target: '.off',
        actions: 'cleanSearch'
      }), ACTION_TYPES.TOGGLE, [{
        actions: send(ACTION_TYPES.CLOSE),
        cond: function cond(ctx) {
          return ctx.open;
        }
      }, {
        actions: send(ACTION_TYPES.OPEN)
      }]), ACTION_TYPES.BLUR, {
        actions: send(ACTION_TYPES.CLOSE)
      }), ACTION_TYPES.SELECT_ITEM, {
        actions: send(ACTION_TYPES.CLOSE),
        cond: function cond(ctx, e) {
          return e.payload && !e.payload.disabled && !ctx.multiselect;
        }
      }), ACTION_TYPES.DESELECT_ITEM, {
        actions: send(ACTION_TYPES.CLOSE),
        cond: function cond(ctx, e) {
          return e.payload && !e.payload.disabled && !ctx.multiselect;
        }
      }),
      states: {
        unknown: {
          always: [{
            target: 'on',
            cond: function cond(ctx) {
              return ctx.open;
            }
          }, {
            target: 'off'
          }]
        },
        on: {
          onEntry: 'open'
        },
        off: {
          onEntry: 'close'
        }
      }
    },
    selection: {
      initial: 'unknown',
      states: {
        unknown: {
          always: [{
            target: 'controlled',
            actions: 'forceValueFromProps',
            cond: function cond(ctx) {
              return !!ctx.valueFromProps;
            }
          }, {
            target: 'uncontrolled'
          }]
        },
        controlled: {
          initial: 'unknown',
          on: _defineProperty(_defineProperty(_defineProperty({}, ACTION_TYPES.SELECT_ITEM, {
            target: '.changeUncommitted',
            actions: 'updateUncommittedItems',
            cond: function cond(_, e) {
              return e.payload && !e.payload.disabled;
            }
          }), ACTION_TYPES.SELECT_FOCUSED_ITEM, {
            target: '.unknown',
            actions: 'sendSelectOrDeselectVisibleFocusedOption'
          }), ACTION_TYPES.DESELECT_ITEM, {
            target: '.changeUncommitted',
            actions: 'updateUncommittedItems',
            cond: function cond(ctx) {
              return !!ctx.multiselect;
            }
          }),
          states: {
            unknown: {
              always: [{
                target: 'incorrectSelection',
                cond: function cond(ctx) {
                  return ctx.selectedItems.some(function (x) {
                    return !includesOption(ctx.options, x);
                  });
                }
              }, {
                target: 'on',
                cond: function cond(ctx) {
                  return ctx.valueFromProps.length > 0;
                }
              }, {
                target: 'off'
              }]
            },
            on: {},
            off: {},
            changeUncommitted: {
              on: _defineProperty(_defineProperty({}, ACTION_TYPES.CHANGE_COMMIT, {
                target: 'unknown',
                actions: 'commitSelectedItems'
              }), ACTION_TYPES.CHANGE_COMMIT_ABORT, {
                target: 'unknown',
                actions: 'uncommitSelectedItems'
              })
            },
            incorrectSelection: {
              always: {
                target: 'off',
                actions: 'resetSelection'
              }
            }
          }
        },
        uncontrolled: {
          initial: 'unknown',
          on: _defineProperty(_defineProperty(_defineProperty({}, ACTION_TYPES.SELECT_ITEM, {
            target: '.changeUncommitted',
            actions: 'updateUncommittedItems',
            cond: function cond(_, e) {
              return e.payload && !e.payload.disabled;
            }
          }), ACTION_TYPES.SELECT_FOCUSED_ITEM, {
            target: '.unknown',
            actions: 'sendSelectOrDeselectVisibleFocusedOption'
          }), ACTION_TYPES.DESELECT_ITEM, {
            target: '.changeUncommitted',
            actions: 'updateUncommittedItems',
            cond: function cond(ctx) {
              return !!ctx.multiselect;
            }
          }),
          states: {
            unknown: {
              always: [{
                target: 'incorrectSelection',
                cond: function cond(ctx) {
                  return ctx.selectedItems.some(function (x) {
                    return !includesOption(ctx.options, x);
                  });
                }
              }, {
                target: 'on',
                cond: function cond(ctx) {
                  return ctx.selectedItems.length > 0;
                }
              }, {
                target: 'off'
              }]
            },
            on: {},
            off: {},
            changeUncommitted: {
              on: _defineProperty(_defineProperty({}, ACTION_TYPES.CHANGE_COMMIT, {
                target: 'unknown',
                actions: 'commitSelectedItems'
              }), ACTION_TYPES.CHANGE_COMMIT_ABORT, {
                target: 'unknown',
                actions: 'uncommitSelectedItems'
              })
            },
            incorrectSelection: {
              always: {
                target: 'off',
                actions: 'resetSelection'
              }
            }
          }
        }
      }
    },
    correctness: {
      initial: 'unknown',
      states: {
        unknown: {
          always: [{
            target: 'error',
            cond: function cond(ctx) {
              return ctx.error !== '';
            }
          }, {
            target: 'success',
            cond: function cond(ctx) {
              return ctx.success;
            }
          }, {
            target: 'neutral'
          }]
        },
        error: {},
        success: {},
        neutral: {}
      }
    },
    interaction: {
      initial: 'unknown',
      states: {
        unknown: {
          always: [{
            target: 'disabled',
            cond: function cond(ctx) {
              return ctx.disabled;
            }
          }, {
            target: 'disabled',
            cond: function cond(ctx) {
              return ctx.options.length === 0 && ctx.actions.length === 0;
            }
          }, {
            target: 'enabled'
          }]
        },
        disabled: {},
        enabled: {
          on: _defineProperty(_defineProperty(_defineProperty(_defineProperty({}, ACTION_TYPES.BLUR, '.idle'), ACTION_TYPES.FOCUS, '.active.focus.unknown'), ACTION_TYPES.OPEN, '.active.focus.unknown'), ACTION_TYPES.ITEM_CLICK, {
            actions: 'selectOrDeselect'
          }),
          initial: 'unknown',
          states: {
            unknown: {
              always: [{
                target: 'active',
                cond: function cond(ctx) {
                  return Boolean(ctx.open);
                }
              }, {
                target: 'idle'
              }]
            },
            idle: {
              on: _defineProperty({}, ACTION_TYPES.FOCUS, 'active.focus.unknown')
            },
            active: {
              type: 'parallel',
              on: _defineProperty({}, ACTION_TYPES.BLUR, 'idle'),
              states: {
                search: {
                  initial: 'unknown',
                  states: {
                    unknown: {
                      always: [{
                        target: 'explicit',
                        cond: function cond(ctx) {
                          return Boolean(ctx.showSearch);
                        }
                      }, {
                        target: 'implicit'
                      }]
                    },
                    explicit: {
                      on: _defineProperty({}, ACTION_TYPES.SEARCH_QUERY_UPDATE, {
                        actions: ['updateSearch', 'updateVisibleOptions', 'restoreFocusOrFocusFirst']
                      })
                    },
                    implicit: {
                      initial: 'idle',
                      states: {
                        idle: {
                          onEntry: 'cleanSearch',
                          on: _defineProperty({}, ACTION_TYPES.SEARCH_QUERY_UPDATE, {
                            target: 'processInput',
                            actions: 'updateSearch'
                          })
                        },
                        resetTimeout: {
                          always: 'processInput'
                        },
                        processInput: {
                          after: {
                            200: 'search'
                          },
                          on: _defineProperty({}, ACTION_TYPES.SEARCH_QUERY_UPDATE, {
                            target: 'resetTimeout',
                            actions: 'updateSearch'
                          })
                        },
                        search: {
                          always: {
                            target: 'idle',
                            actions: 'setFocusToSearchedOption'
                          }
                        }
                      }
                    }
                  }
                },
                navigation: {
                  on: _defineProperty({}, ACTION_TYPES.CLOSE, {
                    actions: 'setNavTypeKeyboard',
                    target: '.keyboard'
                  }),
                  initial: 'unknown',
                  states: {
                    unknown: {
                      always: [{
                        target: 'mouse',
                        cond: function cond(ctx) {
                          return ctx.lastNavigationType === 'mouse';
                        }
                      }, {
                        target: 'keyboard'
                      }]
                    },
                    keyboard: {
                      on: _defineProperty({}, ACTION_TYPES.MOUSE_MOVE, {
                        target: 'mouse',
                        actions: 'setNavTypeMouse'
                      })
                    },
                    mouse: {
                      on: _defineProperty({}, ACTION_TYPES.KEY_PRESS, {
                        target: 'keyboard',
                        actions: 'setNavTypeKeyboard'
                      })
                    }
                  }
                },
                focus: {
                  initial: 'unknown',
                  on: _defineProperty({}, ACTION_TYPES.CLOSE, {
                    target: '.button'
                  }),
                  states: {
                    unknown: {
                      always: [{
                        target: 'button',
                        in: '#inputSelect.open.off'
                      }, {
                        target: 'listItem',
                        cond: function cond(ctx) {
                          return ctx.itemFocusIdx !== null;
                        }
                      }]
                    },
                    button: {},
                    listItem: {
                      on: _defineProperty(_defineProperty({}, ACTION_TYPES.FOCUS_NEXT_ITEM, {
                        actions: 'setNextFocusedItem'
                      }), ACTION_TYPES.FOCUS_PREV_ITEM, {
                        actions: 'setPrevFocusedItem'
                      })
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}, {
  actions: {
    open: assign(function () {
      return {
        open: true
      };
    }),
    close: assign(function () {
      return {
        open: false
      };
    }),
    updateSearch: assign({
      searchQuery: function searchQuery(_, e) {
        return e.payload;
      }
    }),
    cleanSearch: assign({
      searchQuery: '',
      visibleOptions: function visibleOptions(ctx) {
        return ctx.options;
      }
    }),
    syncProps: assign(function (ctx, e) {
      return _objectSpread(_objectSpread(_objectSpread({}, ctx), e.payload), {}, {
        valueFromProps: e.payload.valueFromProps,
        visibleOptions: e.payload.options !== ctx.options ? e.payload.options : ctx.visibleOptions
      });
    }),
    restoreFocusOrFocusFirst: assign({
      itemFocusIdx: function itemFocusIdx(ctx) {
        return ctx.selectedItems.length > 0 ? ctx.visibleOptions.findIndex(function (x) {
          return isEqualOptions(x, ctx.selectedItems[0]);
        }) : 0;
      }
    }),
    setFocusToSearchedOption: assign({
      itemFocusIdx: function itemFocusIdx(ctx) {
        var newIdx = ctx.options.findIndex(function (x) {
          return x.label.toLowerCase().startsWith(ctx.searchQuery.toLowerCase());
        });
        return newIdx !== -1 && !ctx.options[newIdx].disabled ? newIdx : ctx.itemFocusIdx;
      }
    }),
    setNextFocusedItem: assign({
      itemFocusIdx: function itemFocusIdx(ctx) {
        var MAX_IDX = ctx.visibleOptions.length + ctx.actions.length;
        return ctx.itemFocusIdx !== null ? (ctx.itemFocusIdx + 1) % MAX_IDX : 0;
      }
    }),
    setPrevFocusedItem: assign({
      itemFocusIdx: function itemFocusIdx(ctx) {
        var MAX_IDX = ctx.visibleOptions.length + ctx.actions.length;
        return ctx.itemFocusIdx !== null && ctx.itemFocusIdx - 1 >= 0 ? ctx.itemFocusIdx - 1 : MAX_IDX - 1;
      }
    }),
    setNavTypeKeyboard: assign({
      lastNavigationType: 'keyboard'
    }),
    setNavTypeMouse: assign({
      lastNavigationType: 'mouse'
    }),
    selectOrDeselect: send(function (ctx, event) {
      var isSelected = includesOption(ctx.selectedItems, event.payload);
      var type = isSelected ? ACTION_TYPES.DESELECT_ITEM : ACTION_TYPES.SELECT_ITEM;
      return {
        type: type,
        payload: event.payload
      };
    }),
    sendSelectOrDeselectVisibleFocusedOption: send(function (ctx) {
      if (ctx.itemFocusIdx === null) return '';
      return {
        type: includesOption(ctx.selectedItems, ctx.visibleOptions[ctx.itemFocusIdx]) ? ACTION_TYPES.DESELECT_ITEM : ACTION_TYPES.SELECT_ITEM,
        payload: [].concat(_toConsumableArray(ctx.visibleOptions), _toConsumableArray(ctx.actions))[ctx.itemFocusIdx]
      };
    }),
    resetSelection: assign({
      selectedItems: []
    }),
    deselectOption: assign({
      selectedItems: function selectedItems(ctx, _ref) {
        var payload = _ref.payload;
        if (payload[SYMBOL_ALL]) {
          return [];
        }
        var predicate = function predicate(x) {
          return !isEqualOptions(x, payload);
        };
        if (ctx.options.some(function (x) {
          return x[SYMBOL_ALL];
        })) {
          predicate = function predicate(x) {
            return !x[SYMBOL_ALL] && !isEqualOptions(x, payload);
          };
        }
        return ctx.selectedItems.filter(predicate);
      }
    }),
    updateVisibleOptions: assign({
      visibleOptions: function visibleOptions(ctx, e) {
        return ctx.options.filter(function (x) {
          return x.label.toLowerCase().includes(e.payload.toLowerCase());
        });
      }
    }),
    updateUncommittedItems: assign({
      uncommittedSelectedItems: function uncommittedSelectedItems(ctx, e) {
        if (ctx.multiselect) {
          if (e.type === ACTION_TYPES.SELECT_ITEM) {
            var activeOptions = ctx.options.filter(function (x) {
              return !x.options && !x.disabled;
            });
            if (e.payload[SYMBOL_ALL]) {
              return activeOptions;
            }
            var newSelectedItems = ctx.selectedItems.concat(e.payload);
            var selectAllOption = ctx.options.find(function (x) {
              return x[SYMBOL_ALL];
            });
            if (selectAllOption && newSelectedItems.length === activeOptions.length - 1) {
              newSelectedItems = newSelectedItems.concat(selectAllOption);
            }
            return newSelectedItems;
          } else if (e.type === ACTION_TYPES.DESELECT_ITEM) {
            if (e.payload[SYMBOL_ALL]) {
              return [];
            }
            var predicate = function predicate(x) {
              return !isEqualOptions(x, e.payload);
            };
            if (ctx.options.some(function (x) {
              return x[SYMBOL_ALL];
            })) {
              predicate = function predicate(x) {
                return !x[SYMBOL_ALL] && !isEqualOptions(x, e.payload);
              };
            }
            return ctx.selectedItems.filter(predicate);
          }
        }
        return [e.payload];
      }
    }),
    commitSelectedItems: assign({
      selectedItems: function selectedItems(ctx) {
        return ctx.uncommittedSelectedItems;
      },
      uncommittedSelectedItems: []
    }),
    uncommitSelectedItems: assign({
      uncommittedSelectedItems: []
    }),
    forceValueFromProps: assign({
      selectedItems: function selectedItems(ctx) {
        return ctx.valueFromProps;
      }
    })
  }
});