Skip to content

Commit

Permalink
Fix #673
Browse files Browse the repository at this point in the history
  • Loading branch information
s-yadav committed Sep 25, 2022
1 parent f1d6696 commit 9afc266
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 29 deletions.
26 changes: 2 additions & 24 deletions src/number_format_base.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ import {
geInputCaretPosition,
setCaretPosition,
getCaretPosition,
clamp,
charIsNumber,
useInternalValues,
noop,
caretUnknownFormatBoundary,
getCaretPosInBoundary,
} from './utils';

function defaultRemoveFormatting(value: string) {
Expand Down Expand Up @@ -136,29 +136,7 @@ export default function NumberFormatBase<BaseType = InputAttributes>(

/* This keeps the caret within typing area so people can't type in between prefix or suffix */
const correctCaretPosition = (value: string, caretPos: number, direction?: string) => {
const valLn = value.length;

// clamp caret position to [0, value.length]
caretPos = clamp(caretPos, 0, valLn);

const boundary = getCaretBoundary(value);

if (direction === 'left') {
while (caretPos >= 0 && !boundary[caretPos]) caretPos--;

// if we don't find any suitable caret position on left, set it on first allowed position
if (caretPos === -1) caretPos = boundary.indexOf(true);
} else {
while (caretPos <= valLn && !boundary[caretPos]) caretPos++;

// if we don't find any suitable caret position on right, set it on last allowed position
if (caretPos > valLn) caretPos = boundary.lastIndexOf(true);
}

// if we still don't find caret position, set it at the end of value
if (caretPos === -1) caretPos = valLn;

return caretPos;
return getCaretPosInBoundary(value, caretPos, getCaretBoundary(value), direction);
};

const getNewCaretPosition = (inputValue: string, formattedValue: string, caretPos: number) => {
Expand Down
22 changes: 18 additions & 4 deletions src/pattern_format.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import React from 'react';
import { PatternFormatProps, InputAttributes, ChangeMeta, InternalNumberFormatBase } from './types';
import { getDefaultChangeMeta, getMaskAtIndex, noop, setCaretPosition } from './utils';
import {
getCaretPosInBoundary,
getDefaultChangeMeta,
getMaskAtIndex,
noop,
setCaretPosition,
} from './utils';
import NumberFormatBase from './number_format_base';

export function format<BaseType = InputAttributes>(
Expand Down Expand Up @@ -147,10 +153,14 @@ export function usePatternFormat<BaseType = InputAttributes>(props: PatternForma
// validate props
validateProps(props);

const _getCaretBoundary = (formattedValue: string) => {
return getCaretBoundary(formattedValue, props);
};

const _onKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
const { key } = e;
const el = e.target as HTMLInputElement;
const { selectionStart, selectionEnd } = el;
const { selectionStart, selectionEnd, value } = el;

// if multiple characters are selected and user hits backspace, no need to handle anything manually
if (selectionStart !== selectionEnd || !selectionStart) {
Expand All @@ -164,18 +174,22 @@ export function usePatternFormat<BaseType = InputAttributes>(props: PatternForma
// bring the cursor to closest numeric section
let index = selectionStart;

let direction: string;

if (key === 'Backspace') {
while (index > 0 && formatProp[index - 1] !== patternChar) {
index--;
}
direction = 'left';
} else {
const formatLn = formatProp.length;
while (index < formatLn && formatProp[index] !== patternChar) {
index++;
}
direction = 'right';
}

if (index !== selectionStart) {
index = getCaretPosInBoundary(value, index, _getCaretBoundary(value), direction);
setCaretPosition(el, index);
}
}
Expand All @@ -188,7 +202,7 @@ export function usePatternFormat<BaseType = InputAttributes>(props: PatternForma
format: (numStr: string) => format(numStr, props),
removeFormatting: (inputValue: string, changeMeta: ChangeMeta) =>
removeFormatting(inputValue, changeMeta, props),
getCaretBoundary: (formattedValue: string) => getCaretBoundary(formattedValue, props),
getCaretBoundary: _getCaretBoundary,
onKeyDown: _onKeyDown,
};
}
Expand Down
32 changes: 31 additions & 1 deletion src/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ export function getCaretPosition(formattedValue: string, curValue: string, curCa
const endIndex = pos === curValLn || indexMap[pos] === -1 ? formattedValueLn : indexMap[pos];

pos = curCaretPos - 1;
while (pos > 0 && (indexMap[pos] === -1 || !charIsNumber(curValue[pos]))) pos--;
while (pos > 0 && indexMap[pos] === -1) pos--;
const startIndex = pos === -1 || indexMap[pos] === -1 ? 0 : indexMap[pos] + 1;

/**
Expand All @@ -352,6 +352,36 @@ export function getCaretPosition(formattedValue: string, curValue: string, curCa
return curCaretPos - startIndex < endIndex - curCaretPos ? startIndex : endIndex;
}

/* This keeps the caret within typing area so people can't type in between prefix or suffix or format characters */
export function getCaretPosInBoundary(
value: string,
caretPos: number,
boundary: boolean[],
direction?: string,
) {
const valLn = value.length;

// clamp caret position to [0, value.length]
caretPos = clamp(caretPos, 0, valLn);

if (direction === 'left') {
while (caretPos >= 0 && !boundary[caretPos]) caretPos--;

// if we don't find any suitable caret position on left, set it on first allowed position
if (caretPos === -1) caretPos = boundary.indexOf(true);
} else {
while (caretPos <= valLn && !boundary[caretPos]) caretPos++;

// if we don't find any suitable caret position on right, set it on last allowed position
if (caretPos > valLn) caretPos = boundary.lastIndexOf(true);
}

// if we still don't find caret position, set it at the end of value
if (caretPos === -1) caretPos = valLn;

return caretPos;
}

export function caretUnknownFormatBoundary(formattedValue: string) {
const boundaryAry = Array.from({ length: formattedValue.length + 1 }).map(() => true);

Expand Down
22 changes: 22 additions & 0 deletions test/library/keypress_and_caret.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,28 @@ describe('Test keypress and caret position changes', () => {
expect(getInputValue(wrapper)).toEqual('123 999 845');
expect(caretPos).toEqual(7);
});

it('after typing decimal cursor position should go after the . when suffix is provided. #673', () => {
let caretPos;
const setSelectionRange = (pos) => {
caretPos = pos;
};

const wrapper = mount(
<NumericFormat
type="text"
allowNegative={false}
valueIsNumericString={true}
decimalScale={8}
placeholder="Enter Amount"
defaultValue="123"
suffix=" USD"
/>,
);
simulateKeyInput(wrapper.find('input'), '.', 3, 3, setSelectionRange);

expect(caretPos).toEqual(4);
});
});

describe('Test delete/backspace with format pattern', async () => {
Expand Down

0 comments on commit 9afc266

Please sign in to comment.