diff --git a/README.md b/README.md index e2f632a5..7d3304ce 100755 --- a/README.md +++ b/README.md @@ -2,16 +2,20 @@ # react-number-format -React Number format is a input formatter library with a sophisticated and lightweight caret engine. +React Number Format is an input-formatter library with a sophisticated and light weight caret engine. It ensures that a user can only enter text that meets specific numeric or string patterns, and formats the input value for display. ### Features -1. Prefix, suffix and thousand separator. -2. Custom pattern formatting. -3. Masking. -4. Custom formatting handler. -5. Format number in an input or format as a simple text. -6. Fully customizable +1. Prefix, suffix and thousands separator. +1. Input Masking. +1. Format number in an input or format as a simple text. +1. Custom pattern formatting. +1. Custom formatting handler. +1. Fully customizable + +### Demos + +See the many DEMO sections in [the documentation](https://s-yadav.github.io/react-number-format/docs/props). ### Install diff --git a/documentation/v5/docs/intro.md b/documentation/v5/docs/intro.md index 579e465f..45dc9a92 100644 --- a/documentation/v5/docs/intro.md +++ b/documentation/v5/docs/intro.md @@ -4,16 +4,20 @@ sidebar_position: 1 # Getting started -React Number format is a input formatter library with a sohpisticated and light weight caret engine. +React Number Format is an input-formatter library with a sophisticated and light weight caret engine. It ensures that a user can only enter text that meets specific numeric or string patterns, and formats the input value for display. ### Features -1. Prefix, suffix and thousand separator. -2. Custom pattern formatting. -3. Masking. -4. Custom formatting handler. -5. Format number in an input or format as a simple text. -6. Fully customizable +1. Prefix, suffix and thousands separator. +1. Input Masking. +1. Format number in an input or format as a simple text. +1. Custom pattern formatting. +1. Custom formatting handler. +1. Fully customizable + +### Demos + +See the many DEMO sections in [the documentation](https://s-yadav.github.io/react-number-format/docs/props). ### Install diff --git a/documentation/v5/docs/migration.md b/documentation/v5/docs/migration.md index 4dbe7254..4e6c4693 100644 --- a/documentation/v5/docs/migration.md +++ b/documentation/v5/docs/migration.md @@ -36,6 +36,14 @@ Number format modules need to know if the passed value is a formatting string or isNumericString prop was confusing and wasn't explaining what is numeric string. The prop is now renamed to more verbose name `valueIsNumericString`. +### Function values for format and removeFormatting are handled in NumberFormatBase. + +The ability to use a custom formatting function has been extracted to a base customizable module. [**NumberFormatBase**](/docs/customization) for custom formatter based formatting. + +```js +import { NumberFormatBase} from "react-number-format"; +``` + ### customNumerals `Array` :::caution Removed diff --git a/documentation/v5/docusaurus.config.js b/documentation/v5/docusaurus.config.js index d7c9b4fa..46e92805 100644 --- a/documentation/v5/docusaurus.config.js +++ b/documentation/v5/docusaurus.config.js @@ -26,7 +26,7 @@ const config = { sidebarPath: require.resolve('./sidebars.js'), // Please change this to your repo. editUrl: - 'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/', + 'https://github.com/s-yadav/react-number-format', }, theme: { diff --git a/package.json b/package.json index d142ad20..092f1f27 100755 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "react-number-format", "description": "React component to format number in an input or as a text.", - "version": "5.2.1", + "version": "5.2.3", "main": "dist/react-number-format.cjs.js", "module": "dist/react-number-format.es.js", "types": "types/index.d.ts", @@ -78,8 +78,8 @@ "pascal-case": "3.1.2", "prettier": "^2.2.1", "prism-react-renderer": "^1.3.1", - "react": "^18.0.0", - "react-dom": "^18.0.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", "react-transform-hmr": "^1.0.4", "rollup": "^1.22.0", "rollup-plugin-babel": "^4.3.3", diff --git a/src/number_format_base.tsx b/src/number_format_base.tsx index dacb00d2..235c2a57 100644 --- a/src/number_format_base.tsx +++ b/src/number_format_base.tsx @@ -229,7 +229,10 @@ export default function NumberFormatBase( ? geInputCaretPosition(focusedElm.current) : undefined; - useLayoutEffect(() => { + // needed to prevent warning with useLayoutEffect on server + const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect + + useIsomorphicLayoutEffect(() => { const input = focusedElm.current; if (formattedValue !== lastUpdatedValue.current.formattedValue && input) { const caretPos = getNewCaretPosition( diff --git a/src/utils.tsx b/src/utils.tsx index 4142d882..6d14fee1 100644 --- a/src/utils.tsx +++ b/src/utils.tsx @@ -1,4 +1,4 @@ -import { useRef, useState } from 'react'; +import { useMemo, useRef, useState } from 'react'; import { NumberFormatBaseProps, FormatInputValueFunction, OnValueChange } from './types'; // basic noop function @@ -457,7 +457,6 @@ export function useInternalValues( const [values, setValues] = useState(() => { return getValues(isNil(value) ? defaultValue : value, valueIsNumericString); }); - const lastPropBasedValue = useRef(values); const _onValueChange: typeof onValueChange = (newValues, sourceInfo) => { if (newValues.formattedValue !== values.formattedValue) { @@ -481,10 +480,9 @@ export function useInternalValues( const newValues = getValues(_value, _valueIsNumericString); - if (newValues.formattedValue !== lastPropBasedValue.current.formattedValue) { - lastPropBasedValue.current = newValues; + useMemo(() => { setValues(newValues); - } + }, [newValues.formattedValue]); return [values, _onValueChange]; } diff --git a/test/library/input.spec.jsx b/test/library/input.spec.jsx index ef643f94..1fa4f731 100644 --- a/test/library/input.spec.jsx +++ b/test/library/input.spec.jsx @@ -1,4 +1,4 @@ -import React, { useState, useRef, useEffect, useMemo } from 'react'; +import React, { useState, useRef, useEffect, useMemo, StrictMode } from 'react'; import { vi } from 'vitest'; import { render as rtlRender, screen, renderHook, fireEvent } from '@testing-library/react'; @@ -867,6 +867,38 @@ const onValueChangeFn = expect(input).toHaveValue('Rs. 1,234'); }); + it('should handle prop updates on StrictMode', async () => { + function Test() { + const [val, setVal] = React.useState('2'); + + return ( +
+ Controlled value: {val} +
+ { + setVal(values.value); + }} + /> + +
+ ); + } + + const { input, view } = await render( + + + , + ); + expect(input.value).toEqual('2'); + const button = view.getByRole('button'); + fireEvent.click(button); + expect(input.value).toEqual('321'); + }); + describe('Test masking', () => { it('should allow mask as string', async () => { const { input, user } = await render(); diff --git a/yarn.lock b/yarn.lock index ac7a4907..9d7398e6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8313,7 +8313,7 @@ react-dev-utils@^12.0.0: strip-ansi "^6.0.1" text-table "^0.2.0" -react-dom@^18.0.0: +react-dom@^18.2.0: version "18.2.0" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d" integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g== @@ -8460,7 +8460,7 @@ react-transition-group@^1.2.1: prop-types "^15.5.6" warning "^3.0.0" -react@^18.0.0: +react@^18.2.0: version "18.2.0" resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5" integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==