"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;

function _react() {
  const data = _interopRequireWildcard(require("react"));

  _react = function () {
    return data;
  };

  return data;
}

function _jsxRuntime() {
  const data = require("react/jsx-runtime");

  _jsxRuntime = function () {
    return data;
  };

  return data;
}

function _clsx() {
  const data = _interopRequireDefault(require("clsx"));

  _clsx = function () {
    return data;
  };

  return data;
}

var _loading = _interopRequireDefault(require("../loading"));

var _PickerColumn = _interopRequireDefault(require("./PickerColumn"));

var _useRefs = _interopRequireDefault(require("../hooks/use-refs"));

var _useEventListener = _interopRequireDefault(require("../hooks/use-event-listener"));

var _utils = require("../utils");

var _constant = require("../utils/constant");

var _ConfigProviderContext = _interopRequireDefault(require("../config-provider/ConfigProviderContext"));

var _raf = require("../utils/raf");

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }

function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }

/* eslint-disable no-plusplus */
function PickerInner(props, ref) {
  const {
    prefixCls,
    createNamespace,
    locale
  } = (0, _react().useContext)(_ConfigProviderContext.default);
  const [bem] = createNamespace('picker', prefixCls);
  const [refs, setRefs, resetRefs] = (0, _useRefs.default)();
  const [formattedColumns, setFormattedColumns] = (0, _react().useState)([]);
  const {
    text: textKey,
    values: valuesKey,
    children: childrenKey
  } = (0, _utils.extend)({
    // compatible with valueKey prop
    text: 'text',
    values: 'values',
    children: 'children'
  }, props.columnsFieldNames);
  const wrapper = (0, _react().useRef)(null);
  const itemHeight = (0, _react().useMemo)(() => (0, _utils.unitToPx)(props.itemHeight), [props.itemHeight]);
  const dataType = (0, _react().useMemo)(() => {
    const {
      columns
    } = props;
    const firstColumn = columns[0] || {};

    if (typeof firstColumn === 'object') {
      if (childrenKey in firstColumn) {
        return 'cascade';
      }

      if (valuesKey in firstColumn) {
        return 'object';
      }
    }

    return 'plain'; // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [props.columns]);

  const formatCascade = () => {
    var _a;

    const formatted = [];
    let cursor = {
      [childrenKey]: props.columns
    };

    while (cursor && cursor[childrenKey]) {
      const children = cursor[childrenKey];
      let defaultIndex = (_a = cursor.defaultIndex) !== null && _a !== void 0 ? _a : +props.defaultIndex;

      while (children[defaultIndex] && children[defaultIndex].disabled) {
        if (defaultIndex < children.length - 1) {
          defaultIndex++;
        } else {
          defaultIndex = 0;
          break;
        }
      }

      formatted.push({
        [valuesKey]: cursor[childrenKey],
        className: cursor.className,
        defaultIndex
      });
      cursor = children[defaultIndex];
    }

    setFormattedColumns(formatted);
  };

  const format = () => {
    const {
      columns
    } = props;

    if (dataType === 'plain') {
      setFormattedColumns([{
        [valuesKey]: columns
      }]);
    } else if (dataType === 'cascade') {
      formatCascade();
    } else {
      setFormattedColumns(columns);
    }
  }; // get indexes of all columns


  const getIndexes = () => refs.map(_ref => _ref.state.index); // set options of column by index


  const setColumnValues = (index, options) => {
    const column = refs[index];

    if (column) {
      column.setOptions(options);
    }
  };

  const onCascadeChange = columnIndex => {
    var _a;

    let cursor = {
      [childrenKey]: props.columns
    };
    const indexes = getIndexes();

    for (let i = 0; i <= columnIndex; i += 1) {
      cursor = cursor[childrenKey][indexes[i]];
    }

    if (cursor && cursor[childrenKey]) {
      while (cursor && cursor[childrenKey]) {
        columnIndex += 1;
        setColumnValues(columnIndex, cursor[childrenKey]);
        cursor = (_a = cursor[childrenKey]) === null || _a === void 0 ? void 0 : _a[cursor.defaultIndex || 0];
      }
    } else {
      // Clean unsafe data children value
      // https://github.com/3lang3/react-vant/issues/378
      refs.forEach((column, i) => {
        if (i > columnIndex && columnIndex < refs.length) {
          column.setOptions([]);
        }
      });
    }
  }; // get column instance by index


  const getChild = index => refs[index]; // get column value by index


  const getColumnValue = index => {
    const column = getChild(index);
    return column.getValue();
  }; // set column value by index


  const setColumnValue = (index, value) => {
    const column = getChild(index);

    if (column) {
      column.setValue(value);

      if (dataType === 'cascade') {
        onCascadeChange(index);
      }
    }
  }; // get column option index by column index


  const getColumnIndex = index => {
    const column = getChild(index);
    return column.state.index;
  }; // set column option index by column index


  const setColumnIndex = (columnIndex, optionIndex) => {
    const column = getChild(columnIndex);

    if (column) {
      column.setIndex(optionIndex);

      if (dataType === 'cascade') {
        onCascadeChange(columnIndex);
      }
    }
  }; // get options of column by index


  const getColumnValues = index => {
    const column = getChild(index);
    return column && column.getValue();
  }; // get values of all columns


  const getValues = () => refs.map(_ref => _ref.getValue()); // set values of all columns


  const setValues = values => {
    values.forEach((value, index) => {
      setColumnValue(index, value);
    });
  }; // set indexes of all columns


  const setIndexes = indexes => {
    indexes.forEach((optionIndex, columnIndex) => {
      setColumnIndex(columnIndex, optionIndex);
    });
  };

  const onChange = columnIndex => {
    if (dataType === 'cascade') {
      onCascadeChange(columnIndex);
    }

    if (props.onChange) {
      if (dataType === 'plain') {
        props.onChange(getColumnValue(0), getColumnIndex(0));
      } else {
        props.onChange(getValues(), columnIndex);
      }
    }
  };

  const confirm = () => {
    refs.forEach(_ref => _ref.stopMomentum());

    if (props.onConfirm) {
      (0, _raf.raf)(() => {
        if (dataType === 'plain') {
          props.onConfirm(getColumnValue(0), getColumnIndex(0));
        } else {
          props.onConfirm(getValues(), getIndexes());
        }
      });
    }
  };

  const cancel = () => {
    var _a, _b;

    if (dataType === 'plain') {
      (_a = props.onCancel) === null || _a === void 0 ? void 0 : _a.call(props, getColumnValue(0), getColumnIndex(0));
    } else {
      (_b = props.onCancel) === null || _b === void 0 ? void 0 : _b.call(props, getValues(), getIndexes());
    }
  };

  const renderTitle = () => {
    if (props.title) {
      return (0, _jsxRuntime().jsx)("div", Object.assign({
        className: (0, _clsx().default)(bem('title'), 'rv-ellipsis')
      }, {
        children: props.title
      }));
    }

    return null;
  };

  const renderCancel = () => {
    const text = props.cancelButtonText || locale.cancel;
    return (0, _jsxRuntime().jsx)("button", Object.assign({
      type: "button",
      className: (0, _clsx().default)(bem('cancel')),
      onClick: cancel
    }, {
      children: text
    }));
  };

  const renderConfirm = () => {
    const text = props.confirmButtonText || locale.confirm;
    return (0, _jsxRuntime().jsx)("button", Object.assign({
      type: "button",
      className: (0, _clsx().default)(bem('confirm')),
      onClick: confirm
    }, {
      children: text
    }));
  };

  const renderToolbar = () => {
    if (props.showToolbar) {
      return (0, _jsxRuntime().jsx)("div", Object.assign({
        className: (0, _clsx().default)(bem('toolbar'))
      }, {
        children: props.toolbar || (0, _jsxRuntime().jsxs)(_jsxRuntime().Fragment, {
          children: [renderCancel(), renderTitle(), renderConfirm()]
        })
      }));
    }

    return null;
  };

  const renderColumnItems = () => formattedColumns.map((item, columnIndex) => {
    var _a;

    return (0, _jsxRuntime().jsx)(_PickerColumn.default // eslint-disable-next-line react/no-array-index-key
    , {
      optionRender: props.optionRender,
      ref: setRefs(columnIndex),
      textKey: textKey,
      readonly: props.readonly,
      className: item.className,
      itemHeight: itemHeight,
      defaultIndex: (_a = item.defaultIndex) !== null && _a !== void 0 ? _a : +props.defaultIndex,
      swipeDuration: props.swipeDuration,
      visibleItemCount: props.visibleItemCount,
      initialOptions: item[valuesKey],
      onChange: () => {
        onChange(columnIndex);
      }
    }, columnIndex);
  });

  const renderColumns = () => {
    const wrapHeight = itemHeight * props.visibleItemCount;
    const frameStyle = {
      height: `${itemHeight}px`
    };
    const columnsStyle = {
      height: `${wrapHeight}px`
    };
    const maskStyle = {
      backgroundSize: `100% ${(wrapHeight - itemHeight) / 2}px`
    };
    return (0, _jsxRuntime().jsxs)("div", Object.assign({
      ref: wrapper,
      className: (0, _clsx().default)(bem('columns')),
      style: columnsStyle
    }, {
      children: [renderColumnItems(), (0, _jsxRuntime().jsx)("div", {
        className: (0, _clsx().default)(bem('mask')),
        style: maskStyle
      }), (0, _jsxRuntime().jsx)("div", {
        className: (0, _clsx().default)(_constant.BORDER_UNSET_TOP_BOTTOM, bem('frame')),
        style: frameStyle
      })]
    }));
  };

  (0, _react().useEffect)(() => {
    if (JSON.stringify(props.columns) !== JSON.stringify(formattedColumns)) {
      resetRefs();
      format();
    } // eslint-disable-next-line react-hooks/exhaustive-deps

  }, [props.columns]);
  (0, _useEventListener.default)('touchmove', _utils.preventDefault, {
    target: wrapper.current
  });
  (0, _react().useImperativeHandle)(ref, () => ({
    confirm,
    getValues,
    setValues,
    getIndexes,
    setIndexes,
    getColumnIndex,
    setColumnIndex,
    getColumnValue,
    setColumnValue,
    getColumnValues,
    setColumnValues
  }));
  return (0, _jsxRuntime().jsxs)("div", Object.assign({
    className: (0, _clsx().default)(bem(), props.className)
  }, {
    children: [props.toolbarPosition === 'top' ? renderToolbar() : null, props.loading ? (0, _jsxRuntime().jsx)(_loading.default, {
      className: (0, _clsx().default)(bem('loading'))
    }) : null, props.columnsTop, renderColumns(), props.columnsBottom, props.toolbarPosition === 'bottom' ? renderToolbar() : null]
  }));
}

const Picker = (0, _react().forwardRef)(PickerInner);
Picker.defaultProps = {
  itemHeight: 44,
  visibleItemCount: 5,
  swipeDuration: 1000,
  defaultIndex: 0,
  showToolbar: true,
  toolbarPosition: 'top'
};
var _default = Picker;
exports.default = _default;