UNPKG

react-elegant-ui

Version:

Elegant UI components, made by BEM best practices for react

168 lines 5.46 kB
var __read = this && this.__read || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; }; import { useCallback, useEffect, useRef } from 'react'; import { findIndexLoop } from '../../lib/findIndexLoop'; import { isKeyCode, Keys } from '../../lib/keyboard'; import { useDelayCallback } from '../useDelayCallback'; import { useImmutableCallback } from '../useImmutableCallback'; /** * Default predicate for match text with object * * This function check property from interface `KeyboardSearchItem`, then * if your object is not have property `text` it will return `false` always */ export var defaultPredicate = function (searchText, item) { var itemText = item.text; // Skip items which not contain text if (itemText === undefined) return false; var substr = itemText.slice(0, searchText.length); return substr.toLowerCase() === searchText.toLowerCase(); }; /** * Global hook which implement inline search from keyboard * * It useful when u want fast navigate in items by input it names */ export var useInlineKeyboardSearch = function (_a) { var enabled = _a.enabled, items = _a.items, cursor = _a.cursor, setCursor = _a.setCursor, predicate = _a.predicate, resetByEsc = _a.resetByEsc, _b = _a.resetDelay, resetDelay = _b === void 0 ? 500 : _b, _c = _a.searchDirection, searchDirection = _c === void 0 ? 1 : _c, _d = _a.loop, loop = _d === void 0 ? true : _d, _e = _a.eventCapture, eventCapture = _e === void 0 ? true : _e; var _f = __read(useDelayCallback(), 2), setCallback = _f[0], resetCallback = _f[1]; // Input control var inputText = useRef(''); var resetInput = useCallback(function () { resetCallback(); inputText.current = ''; }, [resetCallback, inputText]); var pushInput = useCallback(function (data) { setCallback(resetInput, resetDelay); inputText.current += data; return inputText.current; }, [setCallback, resetInput, resetDelay]); var actualPredicate = predicate !== null && predicate !== void 0 ? predicate : defaultPredicate; // Search wrapper which iterate items and call predicate var findItem = useCallback(function (_a) { var currentCursor = _a.currentCursor, searchText = _a.searchText, _b = _a.checkCurrentCursor, checkCurrentCursor = _b === void 0 ? false : _b, _c = _a.direction, direction = _c === void 0 ? searchDirection : _c; // Set cursor var findCursor = checkCurrentCursor ? currentCursor : currentCursor + direction; // Fix cursor if (findCursor >= items.length) { findCursor = 0; } else if (findCursor < 0) { findCursor = items.length - 1; } // Find match item return findIndexLoop(items, function (item) { return actualPredicate(searchText, item); }, findCursor, direction, loop); }, [searchDirection, loop, items, actualPredicate]); // Handler var handleInput = useImmutableCallback(function (inputChar) { var currentCursor = cursor !== null && cursor !== void 0 ? cursor : -1; var newCursor = -1; // Search with previous input var inputWithPrev = pushInput(inputChar); if (inputWithPrev.length > inputChar.length) { newCursor = findItem({ currentCursor: currentCursor, searchText: inputWithPrev, // Check current item, cuz user may continue input even while match checkCurrentCursor: true }); } // Search current input if (newCursor === -1) { resetInput(); var currentInput = pushInput(inputChar); newCursor = findItem({ currentCursor: currentCursor, searchText: currentInput, checkCurrentCursor: false }); } // Fix cursor when current cursor exist but next item is not found // Should not reset cursor due to this, but setter should be called if (newCursor === -1) { newCursor = currentCursor; } if (setCursor !== undefined) { setCursor(newCursor); } }, [cursor, setCursor, findItem, pushInput, resetInput]); // Input handler useEffect(function () { if (!enabled) return; var handler = function (evt) { // Handle input if (evt.key.length === 1) { handleInput(evt.key); } }; document.addEventListener('keydown', handler, { capture: eventCapture }); return function () { return document.removeEventListener('keydown', handler, { capture: eventCapture }); }; }, [enabled, eventCapture, handleInput]); // Control handler useEffect(function () { if (!resetByEsc || !enabled) return; var handler = function (evt) { // Reset input if (isKeyCode(evt.key, [Keys.ESC])) { evt.preventDefault(); evt.stopPropagation(); resetInput(); } }; document.addEventListener('keydown', handler, { capture: eventCapture }); return function () { return document.removeEventListener('keydown', handler, { capture: eventCapture }); }; }, [resetByEsc, enabled, resetInput, eventCapture]); };