Launch Week Day 5: Introducing Reachability for PHP.Learn More
Socket
Book a DemoSign in
Socket

@wojtekmaj/predict-input-value

Package Overview
Dependencies
Maintainers
1
Versions
9
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@wojtekmaj/predict-input-value - npm Package Compare versions

Comparing version
1.1.0
to
1.2.0
+7
dist/cjs/index.d.ts
/**
* Predicts what the value will be after the next keyup given keydown event.
*
* @param {KeyboardEvent} event Keydown event
* @returns {string} Predicted input value
*/
export default function predictInputValue(event: KeyboardEvent): string | null;
"use strict";
exports.__esModule = true;
var excludeList = [
'Alt',
'ArrowDown',
'ArrowLeft',
'ArrowRight',
'ArrowUp',
'Enter',
'Escape',
'Shift',
'Tab',
];
/**
* Predicts what the value will be after the next keyup given keydown event.
*
* @param {KeyboardEvent} event Keydown event
* @returns {string} Predicted input value
*/
function predictInputValue(event) {
// Support only keydown and keypress event
if (event.type !== 'keydown' && event.type !== 'keypress') {
return null;
}
// Skip Cmd+A and other key combinations
if (event.metaKey) {
return null;
}
if (excludeList.includes(event.key)) {
return null;
}
var element = event.target;
// Only support input and textarea elements
if (!(element instanceof HTMLInputElement) && !(element instanceof HTMLTextAreaElement)) {
return null;
}
// We can’t predict values in number inputs
if (element.type === 'number') {
return null;
}
var selectionStart = element.selectionStart;
var selectionEnd = element.selectionEnd;
if (selectionStart === null || selectionEnd === null) {
return null;
}
var nextValueArr = element.value.split('');
var replaceWith = event.key;
if (event.key === 'Backspace') {
if (selectionStart && selectionStart === selectionEnd) {
/**
* There’s no text selected, so pressing backspace will remove the character before the caret.
* That’s equal to one character before the caret being selected when Backspace is pressed.
*/
selectionStart -= 1;
}
replaceWith = '';
}
/**
* If we’re going to add another character, check if we’re not going over the limit set by
* maxLength. If so, entering the next character will fail, and thus, nextValue will be equal to
* value.
*/
if (!replaceWith || element.maxLength < 0 || nextValueArr.length < element.maxLength) {
nextValueArr.splice(selectionStart, selectionEnd - selectionStart, replaceWith);
}
return nextValueArr.join('');
}
exports["default"] = predictInputValue;
/**
* Predicts what the value will be after the next keyup given keydown event.
*
* @param {KeyboardEvent} event Keydown event
* @returns {string} Predicted input value
*/
export default function predictInputValue(event: KeyboardEvent): string | null;
import predictInputValue from './index';
describe('predictInputValue()', () => {
const eventTarget = document.createElement('input');
eventTarget.value = 'hello';
eventTarget.selectionStart = 0;
eventTarget.selectionEnd = 0;
const targetWithCaretAfterThirdLetter = document.createElement('input');
targetWithCaretAfterThirdLetter.value = 'hello';
targetWithCaretAfterThirdLetter.selectionStart = 3;
targetWithCaretAfterThirdLetter.selectionEnd = 3;
const targetWithSecondLetterSelected = document.createElement('input');
targetWithSecondLetterSelected.value = 'hello';
targetWithSecondLetterSelected.selectionStart = 1;
targetWithSecondLetterSelected.selectionEnd = 2;
const targetWithCaretAfterLastLetter = document.createElement('input');
targetWithCaretAfterLastLetter.value = 'hello';
targetWithCaretAfterLastLetter.selectionStart = 5;
targetWithCaretAfterLastLetter.selectionEnd = 5;
it('returns null for unsupported events', () => {
const event = new KeyboardEvent('keyup');
expect(predictInputValue(event)).toBe(null);
});
it('returns null for meta keys', () => {
const event = new KeyboardEvent('keydown', {
metaKey: true,
});
expect(predictInputValue(event)).toBe(null);
});
it('returns null for meta keys in keydown events', () => {
const event = new KeyboardEvent('keydown', {
metaKey: false,
key: 'ArrowLeft',
});
expect(predictInputValue(event)).toBe(null);
});
it('returns null for input type = "number"', () => {
const eventTarget = document.createElement('input');
eventTarget.type = 'number';
const event = new KeyboardEvent('keydown');
eventTarget.dispatchEvent(event);
expect(predictInputValue(event)).toBe(null);
});
describe('predicts value properly', () => {
it('predicts value if Backspace is pressed at the beginning of the field', () => {
const event = new KeyboardEvent('keydown', {
key: 'Backspace',
});
eventTarget.dispatchEvent(event);
expect(predictInputValue(event)).toBe('hello');
});
it('predicts value if Backspace is pressed in the middle of the field', () => {
const event = new KeyboardEvent('keydown', {
key: 'Backspace',
});
targetWithCaretAfterThirdLetter.dispatchEvent(event);
expect(predictInputValue(event)).toBe('helo');
});
it('predicts value if Backspace is pressed at the end of the field', () => {
const event = new KeyboardEvent('keydown', {
key: 'Backspace',
});
targetWithCaretAfterLastLetter.dispatchEvent(event);
expect(predictInputValue(event)).toBe('hell');
});
it('predicts value if Backspace is pressed when text is selected', () => {
const event = new KeyboardEvent('keydown', {
key: 'Backspace',
});
targetWithSecondLetterSelected.dispatchEvent(event);
expect(predictInputValue(event)).toBe('hllo');
});
it('predicts value if a letter is typed at the beginning of the field', () => {
const event = new KeyboardEvent('keydown', {
key: 'a',
});
eventTarget.dispatchEvent(event);
expect(predictInputValue(event)).toBe('ahello');
});
it('predicts value if a letter is typed in the middle of the field', () => {
const event = new KeyboardEvent('keydown', {
key: 'a',
});
targetWithCaretAfterThirdLetter.dispatchEvent(event);
expect(predictInputValue(event)).toBe('helalo');
});
it('predicts value if a letter is typed at the end of the field', () => {
const event = new KeyboardEvent('keydown', {
key: 'a',
});
targetWithCaretAfterLastLetter.dispatchEvent(event);
expect(predictInputValue(event)).toBe('helloa');
});
it('predicts value if a letter is typed when text is selected', () => {
const event = new KeyboardEvent('keydown', {
key: 'a',
});
targetWithSecondLetterSelected.dispatchEvent(event);
expect(predictInputValue(event)).toBe('hallo');
});
it('predicts value if a letter is typed, but maxLength has been reached', () => {
targetWithCaretAfterLastLetter.maxLength = 5;
const event = new KeyboardEvent('keydown', {
key: 'a',
});
targetWithCaretAfterLastLetter.dispatchEvent(event);
expect(predictInputValue(event)).toBe('hello');
});
});
});
const excludeList = [
'Alt',
'ArrowDown',
'ArrowLeft',
'ArrowRight',
'ArrowUp',
'Enter',
'Escape',
'Shift',
'Tab',
];
/**
* Predicts what the value will be after the next keyup given keydown event.
*
* @param {KeyboardEvent} event Keydown event
* @returns {string} Predicted input value
*/
export default function predictInputValue(event: KeyboardEvent): string | null {
// Support only keydown and keypress event
if (event.type !== 'keydown' && event.type !== 'keypress') {
return null;
}
// Skip Cmd+A and other key combinations
if (event.metaKey) {
return null;
}
if (excludeList.includes(event.key)) {
return null;
}
const { target: element } = event;
// Only support input and textarea elements
if (!(element instanceof HTMLInputElement) && !(element instanceof HTMLTextAreaElement)) {
return null;
}
// We can’t predict values in number inputs
if (element.type === 'number') {
return null;
}
let { selectionStart } = element;
const { selectionEnd } = element;
if (selectionStart === null || selectionEnd === null) {
return null;
}
const nextValueArr = element.value.split('');
let { key: replaceWith } = event;
if (event.key === 'Backspace') {
if (selectionStart && selectionStart === selectionEnd) {
/**
* There’s no text selected, so pressing backspace will remove the character before the caret.
* That’s equal to one character before the caret being selected when Backspace is pressed.
*/
selectionStart -= 1;
}
replaceWith = '';
}
/**
* If we’re going to add another character, check if we’re not going over the limit set by
* maxLength. If so, entering the next character will fail, and thus, nextValue will be equal to
* value.
*/
if (!replaceWith || element.maxLength < 0 || nextValueArr.length < element.maxLength) {
nextValueArr.splice(selectionStart, selectionEnd - selectionStart, replaceWith);
}
return nextValueArr.join('');
}
+57
-44

@@ -0,1 +1,12 @@

var excludeList = [
'Alt',
'ArrowDown',
'ArrowLeft',
'ArrowRight',
'ArrowUp',
'Enter',
'Escape',
'Shift',
'Tab',
];
/**

@@ -8,46 +19,48 @@ * Predicts what the value will be after the next keyup given keydown event.

export default function predictInputValue(event) {
// Support only keydown and keypress event
if (event.type !== 'keydown' && event.type !== 'keypress') {
return null;
} // Skip Cmd+A and other key combinations
if (event.metaKey) {
return null;
}
var element = event.target; // We can’t predict values in number inputs
if (element.type === 'number') {
return null;
}
var selectionStart = element.selectionStart;
var selectionEnd = element.selectionEnd;
var nextValueArr = element.value.split('');
var replaceWith = event.key;
if (event.key === 'Backspace') {
if (selectionStart && selectionStart === selectionEnd) {
/**
* There’s no text selected, so pressing backspace will remove the character before the caret.
* That’s equal to one character before the caret being selected when Backspace is pressed.
*/
selectionStart -= 1;
// Support only keydown and keypress event
if (event.type !== 'keydown' && event.type !== 'keypress') {
return null;
}
replaceWith = '';
}
/**
* If we’re going to add another character, check if we’re not going over the limit set by
* maxLength. If so, entering the next character will fail, and thus, nextValue will be equal to
* value.
*/
if (!replaceWith || element.maxLength < 0 || nextValueArr.length < element.maxLength) {
nextValueArr.splice(selectionStart, selectionEnd - selectionStart, replaceWith);
}
return nextValueArr.join('');
}
// Skip Cmd+A and other key combinations
if (event.metaKey) {
return null;
}
if (excludeList.includes(event.key)) {
return null;
}
var element = event.target;
// Only support input and textarea elements
if (!(element instanceof HTMLInputElement) && !(element instanceof HTMLTextAreaElement)) {
return null;
}
// We can’t predict values in number inputs
if (element.type === 'number') {
return null;
}
var selectionStart = element.selectionStart;
var selectionEnd = element.selectionEnd;
if (selectionStart === null || selectionEnd === null) {
return null;
}
var nextValueArr = element.value.split('');
var replaceWith = event.key;
if (event.key === 'Backspace') {
if (selectionStart && selectionStart === selectionEnd) {
/**
* There’s no text selected, so pressing backspace will remove the character before the caret.
* That’s equal to one character before the caret being selected when Backspace is pressed.
*/
selectionStart -= 1;
}
replaceWith = '';
}
/**
* If we’re going to add another character, check if we’re not going over the limit set by
* maxLength. If so, entering the next character will fail, and thus, nextValue will be equal to
* value.
*/
if (!replaceWith || element.maxLength < 0 || nextValueArr.length < element.maxLength) {
nextValueArr.splice(selectionStart, selectionEnd - selectionStart, replaceWith);
}
return nextValueArr.join('');
}
MIT License
Copyright (c) 2020 Wojciech Maj
Copyright (c) 2020–2023 Wojciech Maj

@@ -5,0 +5,0 @@ Permission is hereby granted, free of charge, to any person obtaining a copy

{
"name": "@wojtekmaj/predict-input-value",
"version": "1.1.0",
"version": "1.2.0",
"description": "Predicts the input value during KeyDown or KeyPress events, before the input is actually changed",
"main": "dist/umd/index.js",
"main": "dist/cjs/index.js",
"module": "dist/esm/index.js",
"source": "src/index.js",
"source": "src/index.ts",
"types": "src/index.ts",
"sideEffects": false,
"scripts": {
"build": "yarn build-esm && yarn build-umd",
"build-esm": "cross-env BABEL_ENV=production-esm babel src -d dist/esm --ignore **/*.spec.js",
"build-umd": "cross-env BABEL_ENV=production-umd babel src -d dist/umd --ignore **/*.spec.js",
"build": "yarn build-esm && yarn build-cjs",
"build-esm": "tsc --project tsconfig.build.json --outDir dist/esm --module esnext",
"build-cjs": "tsc --project tsconfig.build.json --outDir dist/cjs --module commonjs",
"clean": "rimraf dist",
"jest": "jest",
"lint": "eslint src/ --ext .jsx,.js",
"prepublishOnly": "yarn clean && yarn build",
"test": "yarn lint && yarn jest"
"lint": "eslint src",
"prepack": "yarn clean && yarn build",
"prettier": "prettier --check . --cache",
"test": "yarn lint && yarn tsc && yarn prettier && yarn jest",
"tsc": "tsc --noEmit"
},

@@ -29,18 +32,34 @@ "keywords": [

"devDependencies": {
"@babel/cli": "^7.4.0",
"@babel/core": "^7.4.0",
"@babel/preset-env": "^7.4.0",
"cross-env": "^7.0.0",
"eslint": "^6.8.0",
"eslint-config-airbnb-base": "^14.1.0",
"eslint-plugin-import": "^2.20.0",
"jest": "^26.0.0"
"@babel/core": "^7.15.0",
"@babel/preset-env": "^7.15.0",
"@babel/preset-typescript": "^7.18.6",
"@types/jest": "^29.0.0",
"@typescript-eslint/eslint-plugin": "^5.41.0",
"@typescript-eslint/parser": "^5.44.0",
"eslint": "^8.26.0",
"eslint-config-wojtekmaj": "^0.7.1",
"husky": "^8.0.0",
"jest": "^29.0.0",
"jest-environment-jsdom": "^29.0.0",
"prettier": "^2.7.0",
"pretty-quick": "^3.1.0",
"rimraf": "^3.0.0",
"typescript": "^4.9.4"
},
"resolutions": {
"semver@7.0.0": "^7.0.0"
},
"publishConfig": {
"access": "public"
},
"files": [
"LICENSE",
"README.md",
"dist/",
"src/"
"dist",
"src"
],
"repository": "https://github.com/wojtekmaj/predict-input-value.git"
}
"repository": {
"type": "git",
"url": "https://github.com/wojtekmaj/predict-input-value.git"
},
"funding": "https://github.com/wojtekmaj/predict-input-value?sponsor=1",
"packageManager": "yarn@3.1.0"
}
+11
-10

@@ -1,11 +0,13 @@

[![npm](https://img.shields.io/npm/v/predict-input-value.svg)](https://www.npmjs.com/package/predict-input-value) ![downloads](https://img.shields.io/npm/dt/predict-input-value.svg) [![tested with jest](https://img.shields.io/badge/tested_with-jest-99424f.svg)](https://github.com/facebook/jest)
[![npm](https://img.shields.io/npm/v/@wojtekmaj/predict-input-value.svg)](https://www.npmjs.com/package/@wojtekmaj/predict-input-value) ![downloads](https://img.shields.io/npm/dt/@wojtekmaj/predict-input-value.svg) [![CI](https://github.com/wojtekmaj/predict-input-value/workflows/CI/badge.svg)](https://github.com/wojtekmaj/predict-input-value/actions) [![tested with jest](https://img.shields.io/badge/tested_with-jest-99424f.svg)](https://github.com/facebook/jest)
# predict-input-value
# Predict-Input-Value
Predicts the input value during KeyDown or KeyPress events, before the input is actually changed.
## tl;dr
* Install by executing `npm install @wojtekmaj/predict-input-value` or `yarn add @wojtekmaj/predict-input-value`.
* Import by adding `import predictInputValue from '@wojtekmaj/predict-input-value'`.
* Use it by writing `const nextValue = predictInputValue(event)`.
- Install by executing `npm install @wojtekmaj/predict-input-value` or `yarn add @wojtekmaj/predict-input-value`.
- Import by adding `import predictInputValue from '@wojtekmaj/predict-input-value'`.
- Use it by writing `const nextValue = predictInputValue(event)`.
## Example

@@ -15,5 +17,5 @@

* Input: value `"hello"`
* Selected text: `"ello"`
* Key pressed: `i`
- Input: value `"hello"`
- Selected text: `"ello"`
- Key pressed: `i`

@@ -26,3 +28,2 @@ ```js

## License

@@ -42,5 +43,5 @@

<a href="mailto:kontakt@wojtekmaj.pl">kontakt@wojtekmaj.pl</a><br />
<a href="http://wojtekmaj.pl">http://wojtekmaj.pl</a>
<a href="https://wojtekmaj.pl">https://wojtekmaj.pl</a>
</td>
</tr>
</table>
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = predictInputValue;
/**
* Predicts what the value will be after the next keyup given keydown event.
*
* @param {KeyboardEvent} event Keydown event
* @returns {string} Predicted input value
*/
function predictInputValue(event) {
// Support only keydown and keypress event
if (event.type !== 'keydown' && event.type !== 'keypress') {
return null;
} // Skip Cmd+A and other key combinations
if (event.metaKey) {
return null;
}
var element = event.target; // We can’t predict values in number inputs
if (element.type === 'number') {
return null;
}
var selectionStart = element.selectionStart;
var selectionEnd = element.selectionEnd;
var nextValueArr = element.value.split('');
var replaceWith = event.key;
if (event.key === 'Backspace') {
if (selectionStart && selectionStart === selectionEnd) {
/**
* There’s no text selected, so pressing backspace will remove the character before the caret.
* That’s equal to one character before the caret being selected when Backspace is pressed.
*/
selectionStart -= 1;
}
replaceWith = '';
}
/**
* If we’re going to add another character, check if we’re not going over the limit set by
* maxLength. If so, entering the next character will fail, and thus, nextValue will be equal to
* value.
*/
if (!replaceWith || element.maxLength < 0 || nextValueArr.length < element.maxLength) {
nextValueArr.splice(selectionStart, selectionEnd - selectionStart, replaceWith);
}
return nextValueArr.join('');
}
/**
* Predicts what the value will be after the next keyup given keydown event.
*
* @param {KeyboardEvent} event Keydown event
* @returns {string} Predicted input value
*/
export default function predictInputValue(event) {
// Support only keydown and keypress event
if (event.type !== 'keydown' && event.type !== 'keypress') {
return null;
}
// Skip Cmd+A and other key combinations
if (event.metaKey) {
return null;
}
const { target: element } = event;
// We can’t predict values in number inputs
if (element.type === 'number') {
return null;
}
let { selectionStart } = element;
const { selectionEnd } = element;
const nextValueArr = element.value.split('');
let { key: replaceWith } = event;
if (event.key === 'Backspace') {
if (selectionStart && selectionStart === selectionEnd) {
/**
* There’s no text selected, so pressing backspace will remove the character before the caret.
* That’s equal to one character before the caret being selected when Backspace is pressed.
*/
selectionStart -= 1;
}
replaceWith = '';
}
/**
* If we’re going to add another character, check if we’re not going over the limit set by
* maxLength. If so, entering the next character will fail, and thus, nextValue will be equal to
* value.
*/
if (!replaceWith || element.maxLength < 0 || nextValueArr.length < element.maxLength) {
nextValueArr.splice(selectionStart, selectionEnd - selectionStart, replaceWith);
}
return nextValueArr.join('');
}
import predictInputValue from './index';
describe('predictInputValue()', () => {
const defaultEvent = {
key: 'a',
metaKey: false,
target: {
maxLength: -1,
selectionEnd: 0,
selectionStart: 0,
type: 'text',
value: 'hello',
},
type: 'keydown',
};
it('returns null for unsupported events', () => {
const event = {
...defaultEvent,
type: 'keyup',
};
expect(predictInputValue(event)).toBe(null);
});
it('returns null for meta keys', () => {
const event = {
...defaultEvent,
metaKey: true,
};
expect(predictInputValue(event)).toBe(null);
});
it('returns null for input type = "number"', () => {
const event = {
...defaultEvent,
target: {
...defaultEvent.target,
type: 'number',
},
};
expect(predictInputValue(event)).toBe(null);
});
describe('predicts value properly', () => {
it('predicts value if Backspace is pressed at the beginning of the field', () => {
const event = {
...defaultEvent,
key: 'Backspace',
};
expect(predictInputValue(event)).toBe('hello');
});
it('predicts value if Backspace is pressed in the middle of the field', () => {
const event = {
...defaultEvent,
key: 'Backspace',
target: {
...defaultEvent.target,
selectionStart: 1,
selectionEnd: 1,
},
};
expect(predictInputValue(event)).toBe('ello');
});
it('predicts value if Backspace is pressed when text is selected', () => {
const event = {
...defaultEvent,
key: 'Backspace',
target: {
...defaultEvent.target,
selectionStart: 1,
selectionEnd: 2,
},
};
expect(predictInputValue(event)).toBe('hllo');
});
it('predicts value if a letter is typed at the end of the field', () => {
const event = {
...defaultEvent,
key: 'a',
target: {
...defaultEvent.target,
selectionStart: 5,
selectionEnd: 5,
},
};
expect(predictInputValue(event)).toBe('helloa');
});
it('predicts value if a letter is typed in the middle of the field', () => {
const event = {
...defaultEvent,
key: 'a',
target: {
...defaultEvent.target,
selectionStart: 3,
selectionEnd: 3,
},
};
expect(predictInputValue(event)).toBe('helalo');
});
it('predicts value if a letter is typed in the middle of the field', () => {
const event = {
...defaultEvent,
key: 'a',
target: {
...defaultEvent.target,
selectionStart: 3,
selectionEnd: 3,
},
};
expect(predictInputValue(event)).toBe('helalo');
});
it('predicts value if a letter is typed, but maxLength has been reached', () => {
const event = {
...defaultEvent,
key: 'a',
target: {
...defaultEvent.target,
maxLength: 5,
selectionStart: 5,
selectionEnd: 5,
},
};
expect(predictInputValue(event)).toBe('hello');
});
});
});