react-elegant-ui
Version:
Elegant UI components, made by BEM best practices for react
168 lines • 5.46 kB
JavaScript
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]);
};