UNPKG

react-dadata

Version:

React-компонент для подсказок адресов, организаций и банков с помощью сервиса DaData.ru

322 lines (321 loc) 15.3 kB
var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; import { debounce } from 'debounce'; import { nanoid } from 'nanoid'; import React from 'react'; import shallowEqual from 'shallowequal'; import { DefaultHttpCache, HttpCache } from './http-cache'; import { makeRequest } from './request'; var BaseSuggestions = /** @class */ (function (_super) { __extends(BaseSuggestions, _super); function BaseSuggestions(props) { var _this = _super.call(this, props) || this; /** * URL для загрузки подсказок, переопределяется в конкретном компоненте */ _this.loadSuggestionsUrl = ''; _this.dontPerformBlurHandler = false; _this.getSuggestionsUrl = function () { var url = _this.props.url; return url || _this.loadSuggestionsUrl; }; _this.setupDebounce = function (delay) { if (typeof delay === 'number' && delay > 0) { _this.fetchSuggestions = debounce(_this.performFetchSuggestions, delay); } else { _this.fetchSuggestions = _this.performFetchSuggestions; } }; _this.fetchSuggestions = function () { // }; _this.handleInputFocus = function (event) { _this.setState({ isFocused: true }); var suggestions = _this.state.suggestions; if (suggestions.length === 0) { _this.fetchSuggestions(); } var inputProps = _this.props.inputProps; if (inputProps === null || inputProps === void 0 ? void 0 : inputProps.onFocus) { inputProps.onFocus(event); } }; _this.handleInputBlur = function (event) { var _a = _this.state, suggestions = _a.suggestions, suggestionIndex = _a.suggestionIndex; var _b = _this.props, selectOnBlur = _b.selectOnBlur, inputProps = _b.inputProps; _this.setState({ isFocused: false }); if (suggestions.length === 0) { _this.fetchSuggestions(); } if (selectOnBlur && !_this.dontPerformBlurHandler) { if (suggestions.length > 0) { var suggestionIndexToSelect = suggestionIndex >= 0 && suggestionIndex < suggestions.length ? suggestionIndex : 0; _this.selectSuggestion(suggestionIndexToSelect, true); } } _this.dontPerformBlurHandler = false; if (inputProps === null || inputProps === void 0 ? void 0 : inputProps.onBlur) { inputProps.onBlur(event); } }; _this.handleInputChange = function (event) { var value = event.target.value; var inputProps = _this.props.inputProps; if (_this.didMount) { _this.setState({ query: value, inputQuery: value, displaySuggestions: !!value }, function () { _this.fetchSuggestions(); }); } if (inputProps === null || inputProps === void 0 ? void 0 : inputProps.onChange) { inputProps.onChange(event); } }; _this.handleInputKeyDown = function (event) { _this.handleKeyboard(event); var inputProps = _this.props.inputProps; if (inputProps === null || inputProps === void 0 ? void 0 : inputProps.onKeyDown) { inputProps.onKeyDown(event); } }; _this.handleInputKeyPress = function (event) { _this.handleKeyboard(event); var inputProps = _this.props.inputProps; if (inputProps === null || inputProps === void 0 ? void 0 : inputProps.onKeyPress) { inputProps.onKeyPress(event); } }; _this.handleKeyboard = function (event) { var _a = _this.state, suggestions = _a.suggestions, suggestionIndex = _a.suggestionIndex, inputQuery = _a.inputQuery; if (event.key === 'ArrowDown') { // Arrow down event.preventDefault(); if (suggestionIndex < suggestions.length - 1) { var newSuggestionIndex = suggestionIndex + 1; var newInputQuery = suggestions[newSuggestionIndex].value; if (_this.didMount) { _this.setState({ suggestionIndex: newSuggestionIndex, query: newInputQuery, }); } } } else if (event.key === 'ArrowUp') { // Arrow up event.preventDefault(); if (suggestionIndex >= 0) { var newSuggestionIndex = suggestionIndex - 1; var newInputQuery = newSuggestionIndex === -1 ? inputQuery : suggestions[newSuggestionIndex].value; if (_this.didMount) { _this.setState({ suggestionIndex: newSuggestionIndex, query: newInputQuery, }); } } } else if (event.key === 'Enter') { // Enter event.preventDefault(); if (suggestionIndex >= 0) { _this.selectSuggestion(suggestionIndex); } } }; _this.performFetchSuggestions = function () { var _a = _this.props, minChars = _a.minChars, token = _a.token; var query = _this.state.query; // Проверяем на минимальное количество символов для отправки if (typeof minChars === 'number' && minChars > 0 && query.length < minChars) { _this.setState({ suggestions: [], suggestionIndex: -1 }); return; } makeRequest('POST', _this.getSuggestionsUrl(), { headers: { Accept: 'application/json', Authorization: "Token ".concat(token), 'Content-Type': 'application/json', }, json: _this.getLoadSuggestionsData(), }, _this.httpCache, function (suggestions) { if (_this.didMount) { _this.setState({ suggestions: suggestions, suggestionIndex: -1 }); } }); }; _this.onSuggestionClick = function (index, event) { event.stopPropagation(); _this.selectSuggestion(index); }; _this.selectSuggestion = function (index, isSilent) { if (isSilent === void 0) { isSilent = false; } var suggestions = _this.state.suggestions; var _a = _this.props, selectOnBlur = _a.selectOnBlur, onChange = _a.onChange; if (suggestions.length >= index - 1) { var suggestion = suggestions[index]; if (selectOnBlur) { _this.dontPerformBlurHandler = true; } _this.setState({ query: suggestion.value, inputQuery: suggestion.value, displaySuggestions: false, }, function () { if (!isSilent) { _this.fetchSuggestions(); setTimeout(function () { return _this.setCursorToEnd(_this.textInput); }); } }); if (onChange) { onChange(suggestion); } } }; _this.setCursorToEnd = function (element) { if (element) { var valueLength = element.value.length; if (element.selectionStart || element.selectionStart === 0) { element.selectionStart = valueLength; element.selectionEnd = valueLength; element.focus(); } } }; _this.getHighlightWords = function () { var inputQuery = _this.state.inputQuery; var wordsToPass = ['г', 'респ', 'ул', 'р-н', 'село', 'деревня', 'поселок', 'пр-д', 'пл', 'к', 'кв', 'обл', 'д']; var words = inputQuery.replace(',', '').split(' '); words = words.filter(function (word) { return wordsToPass.indexOf(word) < 0; }); return words; }; /** * Функция, которая вернет уникальный key для списка React * @param suggestion */ _this.getSuggestionKey = function (suggestion) { return suggestion.value; }; _this.focus = function () { if (_this.textInput) { _this.textInput.focus(); } }; _this.setInputValue = function (value) { _this.setState({ query: value || '', inputQuery: value || '' }); }; _this.didMount = false; var _a = _this.props, defaultQuery = _a.defaultQuery, value = _a.value, delay = _a.delay; var valueQuery = value ? value.value : undefined; _this.setupDebounce(delay); _this.state = { query: defaultQuery || valueQuery || '', inputQuery: defaultQuery || valueQuery || '', isFocused: false, displaySuggestions: true, suggestions: [], suggestionIndex: -1, }; return _this; } BaseSuggestions.prototype.componentDidMount = function () { this.didMount = true; }; BaseSuggestions.prototype.componentDidUpdate = function (prevProps) { var _a = this.props, value = _a.value, delay = _a.delay; var _b = this.state, query = _b.query, inputQuery = _b.inputQuery; if (!shallowEqual(prevProps.value, value)) { var newQuery = value ? value.value : ''; if (query !== newQuery || inputQuery !== newQuery) { this.setState({ query: newQuery, inputQuery: newQuery }); } } if (delay !== prevProps.delay) { this.setupDebounce(delay); } }; BaseSuggestions.prototype.componentWillUnmount = function () { this.didMount = false; }; Object.defineProperty(BaseSuggestions.prototype, "uid", { get: function () { if (this.props.uid) { return this.props.uid; } if (!this._uid) { this._uid = nanoid(); } return this._uid; }, enumerable: false, configurable: true }); Object.defineProperty(BaseSuggestions.prototype, "httpCache", { get: function () { var _a = this.props, cacheProp = _a.httpCache, ttl = _a.httpCacheTtl; if (!cacheProp) { return null; } if (cacheProp instanceof HttpCache) { return cacheProp; } var cache = DefaultHttpCache.shared; if (typeof ttl === 'number') { cache.ttl = ttl; } return cache; }, enumerable: false, configurable: true }); BaseSuggestions.prototype.render = function () { var _this = this; var _a = this.props, inputProps = _a.inputProps, hintText = _a.hintText, containerClassName = _a.containerClassName, hintClassName = _a.hintClassName, suggestionsClassName = _a.suggestionsClassName, suggestionClassName = _a.suggestionClassName, currentSuggestionClassName = _a.currentSuggestionClassName, customInput = _a.customInput, children = _a.children; var _b = this.state, query = _b.query, isFocused = _b.isFocused, suggestions = _b.suggestions, suggestionIndex = _b.suggestionIndex, displaySuggestions = _b.displaySuggestions; var Component = typeof customInput !== 'undefined' ? customInput : 'input'; var optionsExpanded = isFocused && suggestions && displaySuggestions && suggestions.length > 0; return (React.createElement("div", { role: "combobox", "aria-expanded": optionsExpanded ? 'true' : 'false', "aria-owns": this.uid, "aria-controls": this.uid, "aria-haspopup": "listbox", className: containerClassName || 'react-dadata react-dadata__container' }, React.createElement("div", null, React.createElement(Component, __assign({ autoComplete: "off", className: "react-dadata__input" }, inputProps, { value: query, ref: function (input) { _this.textInput = input; }, onChange: this.handleInputChange, onKeyPress: this.handleInputKeyPress, onKeyDown: this.handleInputKeyDown, onFocus: this.handleInputFocus, onBlur: this.handleInputBlur }))), optionsExpanded && (React.createElement("ul", { id: this.uid, "aria-expanded": true, // biome-ignore lint/a11y/noNoninteractiveElementToInteractiveRole: <explanation> role: "listbox", className: suggestionsClassName || 'react-dadata__suggestions' }, typeof hintText !== 'undefined' && (React.createElement("div", { className: hintClassName || 'react-dadata__suggestion-note' }, hintText)), suggestions.map(function (suggestion, index) { var suggestionClass = suggestionClassName || 'react-dadata__suggestion'; if (index === suggestionIndex) { suggestionClass += " ".concat(currentSuggestionClassName || 'react-dadata__suggestion--current'); } return (React.createElement("button", { role: "option", type: "button", "aria-selected": index === suggestionIndex ? 'true' : 'false', key: _this.getSuggestionKey(suggestion), onMouseDown: _this.onSuggestionClick.bind(_this, index), className: suggestionClass }, _this.renderOption(suggestion))); }))), children)); }; return BaseSuggestions; }(React.PureComponent)); export { BaseSuggestions };