react-autocomplete-hint
Advanced tools
Comparing version 1.0.1 to 1.1.0
@@ -1,6 +0,8 @@ | ||
import React from 'react'; | ||
import React, { ReactElement } from 'react'; | ||
export interface IHintProps { | ||
options: Array<string>; | ||
disableHint?: boolean; | ||
children: ReactElement; | ||
allowTabFill?: boolean; | ||
} | ||
export declare const Hint: React.FC<IHintProps>; |
@@ -37,7 +37,11 @@ "use strict"; | ||
exports.Hint = function (props) { | ||
var options = props.options, child = props.children, disableHint = props.disableHint; | ||
var child = react_1.default.Children.only(props.children); | ||
var options = props.options, disableHint = props.disableHint, allowTabFill = props.allowTabFill; | ||
var childProps = child.props; | ||
var mainInputRef = react_1.useRef(null); | ||
var hintWrapperRef = react_1.useRef(null); | ||
var hintRef = react_1.useRef(null); | ||
var _a = react_1.useState(''), hint = _a[0], setHint = _a[1]; | ||
var _a = react_1.useState(''), text = _a[0], setText = _a[1]; | ||
var _b = react_1.useState(''), hint = _b[0], setHint = _b[1]; | ||
var _c = react_1.useState(), changeEvent = _c[0], setChangeEvent = _c[1]; | ||
react_1.useEffect(function () { | ||
@@ -48,3 +52,3 @@ if (disableHint) { | ||
var inputStyle = mainInputRef.current && window.getComputedStyle(mainInputRef.current); | ||
inputStyle && styleHint(hintRef, inputStyle); | ||
inputStyle && styleHint(hintWrapperRef, hintRef, inputStyle); | ||
}); | ||
@@ -58,34 +62,57 @@ var getHint = function (text) { | ||
.sort()[0]; | ||
// While Text matching is case-insensitive, the casing entered by the user so far should be | ||
// preserved in the hint for UX benefits and also without the preservation, the hint won't | ||
// overlap well if user types a different case from the selected option. | ||
return match | ||
? text + match.slice(text.length) | ||
? match.slice(text.length) | ||
: ''; | ||
}; | ||
var styleHint = function (hintRef, inputStyle) { | ||
var _a; | ||
if ((_a = hintRef === null || hintRef === void 0 ? void 0 : hintRef.current) === null || _a === void 0 ? void 0 : _a.style) { | ||
var setAvailableHint = function () { | ||
if (hint !== '') { | ||
if (changeEvent) { | ||
changeEvent.target.value = text + hint; | ||
childProps.onChange && childProps.onChange(changeEvent); | ||
setHint(''); | ||
} | ||
} | ||
}; | ||
var styleHint = function (hintWrapperRef, hintRef, inputStyle) { | ||
var _a, _b; | ||
if ((_a = hintWrapperRef === null || hintWrapperRef === void 0 ? void 0 : hintWrapperRef.current) === null || _a === void 0 ? void 0 : _a.style) { | ||
hintWrapperRef.current.style.fontFamily = inputStyle.fontFamily; | ||
hintWrapperRef.current.style.fontSize = inputStyle.fontSize; | ||
hintWrapperRef.current.style.width = inputStyle.width; | ||
hintWrapperRef.current.style.height = inputStyle.height; | ||
hintWrapperRef.current.style.lineHeight = inputStyle.lineHeight; | ||
hintWrapperRef.current.style.boxSizing = inputStyle.boxSizing; | ||
hintWrapperRef.current.style.margin = utils_1.interpolateStyle(inputStyle, 'margin'); | ||
hintWrapperRef.current.style.padding = utils_1.interpolateStyle(inputStyle, 'padding'); | ||
hintWrapperRef.current.style.borderStyle = utils_1.interpolateStyle(inputStyle, 'border', 'style'); | ||
hintWrapperRef.current.style.borderWidth = utils_1.interpolateStyle(inputStyle, 'border', 'width'); | ||
} | ||
if ((_b = hintRef === null || hintRef === void 0 ? void 0 : hintRef.current) === null || _b === void 0 ? void 0 : _b.style) { | ||
hintRef.current.style.fontFamily = inputStyle.fontFamily; | ||
hintRef.current.style.fontSize = inputStyle.fontSize; | ||
hintRef.current.style.width = inputStyle.width; | ||
hintRef.current.style.height = inputStyle.height; | ||
hintRef.current.style.lineHeight = inputStyle.lineHeight; | ||
hintRef.current.style.boxSizing = inputStyle.boxSizing; | ||
hintRef.current.style.margin = utils_1.interpolateStyle(inputStyle, 'margin'); | ||
hintRef.current.style.padding = utils_1.interpolateStyle(inputStyle, 'padding'); | ||
hintRef.current.style.borderStyle = utils_1.interpolateStyle(inputStyle, 'border', 'style'); | ||
hintRef.current.style.borderWidth = utils_1.interpolateStyle(inputStyle, 'border', 'width'); | ||
} | ||
}; | ||
var onChange = function (e) { | ||
setChangeEvent(e); | ||
e.persist(); | ||
setText(e.target.value); | ||
setHint(getHint(e.target.value)); | ||
childProps.onChange && childProps.onChange(e); | ||
}; | ||
var onFocus = function (e) { | ||
setHint(getHint(e.target.value)); | ||
childProps.onFocus && childProps.onFocus(e); | ||
}; | ||
var onBlur = function (e) { | ||
setHint(''); | ||
childProps.onBlur && childProps.onBlur(e); | ||
//Only blur it if the new focus isn't the the hint input | ||
if ((hintRef === null || hintRef === void 0 ? void 0 : hintRef.current) !== e.relatedTarget) { | ||
setHint(''); | ||
childProps.onBlur && childProps.onBlur(e); | ||
} | ||
}; | ||
var RIGHT = 39; | ||
var ARROWRIGHT = 'ArrowRight'; | ||
var TAB = 'Tab'; | ||
var onKeyDown = function (e) { | ||
if (e.keyCode === RIGHT) { | ||
var caretIsAtTextEnd = (function () { | ||
// For selectable input types ("text", "search"), only select the hint if | ||
@@ -95,16 +122,43 @@ // it's at the end of the input value. For non-selectable types ("email", | ||
var isNonSelectableType = e.currentTarget.selectionEnd == null; | ||
var cursorIsAtTextEnd = isNonSelectableType | ||
var caretIsAtTextEnd = isNonSelectableType | ||
? true | ||
: e.currentTarget.selectionEnd === e.currentTarget.value.length; | ||
if (cursorIsAtTextEnd && hint !== '' && e.currentTarget.value !== hint) { | ||
e.currentTarget.value = hint; | ||
childProps.onChange(e); | ||
setHint(''); | ||
} | ||
return caretIsAtTextEnd; | ||
})(); | ||
if (caretIsAtTextEnd && e.key === ARROWRIGHT) { | ||
setAvailableHint(); | ||
} | ||
else if (caretIsAtTextEnd && allowTabFill && e.key === TAB && hint !== '') { | ||
e.preventDefault(); | ||
setAvailableHint(); | ||
} | ||
childProps.onKeyDown && childProps.onKeyDown(e); | ||
}; | ||
var mainInput = react_1.cloneElement(child, __assign(__assign({}, childProps), { onChange: onChange, | ||
var onHintClick = function (e) { | ||
var _a; | ||
var hintCaretPosition = e.currentTarget.selectionEnd || 0; | ||
// If user clicks the position before the first character of the hint, | ||
// move focus to the end of the mainInput text | ||
if (hintCaretPosition === 0) { | ||
(_a = mainInputRef.current) === null || _a === void 0 ? void 0 : _a.focus(); | ||
return; | ||
} | ||
if (!!hint && hint !== '') { | ||
setAvailableHint(); | ||
setTimeout(function () { | ||
var _a, _b; | ||
(_a = mainInputRef.current) === null || _a === void 0 ? void 0 : _a.focus(); | ||
var caretPosition = text.length + hintCaretPosition; | ||
(_b = mainInputRef.current) === null || _b === void 0 ? void 0 : _b.setSelectionRange(caretPosition, caretPosition); | ||
}, 0); | ||
} | ||
}; | ||
var mainInput = react_1.cloneElement(child, __assign(__assign({}, childProps), { style: { | ||
boxSizing: 'border-box' | ||
}, onChange: onChange, | ||
onBlur: onBlur, | ||
onKeyDown: onKeyDown, ref: utils_1.mergeRefs(childProps.ref, mainInputRef) })); | ||
onFocus: onFocus, | ||
onKeyDown: onKeyDown, ref: childProps.ref && typeof childProps.ref !== 'string' | ||
? utils_1.mergeRefs(childProps.ref, mainInputRef) | ||
: mainInputRef })); | ||
return (react_1.default.createElement("div", { className: "rah-input-wrapper", style: { | ||
@@ -117,12 +171,30 @@ position: 'relative', | ||
mainInput, | ||
react_1.default.createElement("input", { className: "rah-input-hint", defaultValue: hint, ref: hintRef, style: { | ||
react_1.default.createElement("span", { className: "rah-hint-wrapper", ref: hintWrapperRef, style: { | ||
display: 'flex', | ||
pointerEvents: 'none', | ||
backgroundColor: 'transparent', | ||
borderColor: 'transparent', | ||
boxSizing: 'border-box', | ||
boxShadow: 'none', | ||
color: 'rgba(0, 0, 0, 0.35)', | ||
pointerEvents: 'none', | ||
position: 'absolute', | ||
top: 0, | ||
left: 0 | ||
}, tabIndex: -1 }))))); | ||
left: 0, | ||
} }, | ||
react_1.default.createElement("span", { style: { | ||
visibility: 'hidden', | ||
pointerEvents: 'none' | ||
} }, text), | ||
react_1.default.createElement("input", { className: "rah-hint", ref: hintRef, onClick: onHintClick, style: { | ||
pointerEvents: !hint || hint === '' ? 'none' : 'visible', | ||
background: 'transparent', | ||
width: '100%', | ||
outline: 'none', | ||
border: 'none', | ||
boxShadow: 'none', | ||
padding: 0, | ||
margin: 0, | ||
color: 'rgba(0, 0, 0, 0.35)', | ||
caretColor: 'transparent' | ||
}, value: hint, onChange: function () { return null; }, tabIndex: -1 })))))); | ||
}; |
{ | ||
"name": "react-autocomplete-hint", | ||
"version": "1.0.1", | ||
"version": "1.1.0", | ||
"description": "A React component for Autocomplete hint", | ||
@@ -16,3 +16,4 @@ "main": "dist/src/index.js", | ||
"start": "npm run build && npm run start:dev", | ||
"test": "echo \"Error: no test specified\" && exit 1", | ||
"jest": "./node_modules/jest/bin/jest.js", | ||
"test": "jest --watch", | ||
"prepublishOnly": "tsc" | ||
@@ -31,13 +32,20 @@ }, | ||
"devDependencies": { | ||
"@types/react": "^16.9.43", | ||
"@testing-library/dom": "^7.26.3", | ||
"@testing-library/jest-dom": "^5.11.4", | ||
"@testing-library/react": "^11.0.4", | ||
"@testing-library/user-event": "^12.1.10", | ||
"@types/jest": "^26.0.14", | ||
"@types/react": "^16.9.51", | ||
"@types/react-dom": "^16.9.8", | ||
"css-loader": "^3.6.0", | ||
"jest": "^26.5.2", | ||
"react": "^16.13.1", | ||
"react-dom": "^16.13.1", | ||
"sass": "^1.26.10", | ||
"sass-loader": "^9.0.2", | ||
"style-loader": "^1.2.1", | ||
"ts-loader": "^8.0.1", | ||
"sass": "^1.27.0", | ||
"sass-loader": "^9.0.3", | ||
"style-loader": "^1.3.0", | ||
"ts-jest": "^26.4.1", | ||
"ts-loader": "^8.0.4", | ||
"typescript": "^3.9.7", | ||
"webpack": "^4.44.0", | ||
"webpack": "^4.44.2", | ||
"webpack-cli": "^3.3.12", | ||
@@ -44,0 +52,0 @@ "webpack-dev-server": "^3.11.0" |
@@ -31,5 +31,6 @@ # react-autocomplete-hint | ||
</Hint> | ||
``` | ||
Use your keyboard **Right key** to fill your input with the suggested hint. | ||
Click on the hint or use your keyboard **Right** key or **Tab** key(if `allowTabFill` is set to true) to fill your input with the suggested hint. | ||
@@ -41,8 +42,10 @@ | ||
List of options for autocomplete. | ||
#### disableHint (optional): `Boolean` | ||
#### allowTabFill (optional):`Boolean` | ||
## License | ||
[MIT](LICENSE) | ||
[MIT](LICENSE) | ||
Inspired by [React Bootstrap Typeahead](https://github.com/ericgio/react-bootstrap-typeahead). |
No tests
QualityPackage does not have any tests. This is a strong signal of a poorly maintained or low quality package.
Found 1 instance in 1 package
14820
244
0
50
20