Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@cmsgov/design-system-core

Package Overview
Dependencies
Maintainers
1
Versions
81
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@cmsgov/design-system-core - npm Package Compare versions

Comparing version 1.25.0 to 1.26.0

yarn-error.log

145

dist/components/TextField/Mask.js

@@ -20,2 +20,4 @@ 'use strict';

var _reactLifecyclesCompat = require('react-lifecycles-compat');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

@@ -88,3 +90,3 @@

/**
* Remove all non-digits
* Remove everything that isn't a digit or asterisk
* @param {String} value

@@ -98,2 +100,11 @@ * @returns {String}

/**
* Remove all non-digits
* @param {String} value
* @returns {String}
*/
function toDigits(value) {
return value.replace(/[^\d]/g, '');
}
/**
* Convert string into a number (positive or negative float or integer)

@@ -105,10 +116,46 @@ * @param {String} value

if (typeof value !== 'string') return value;
if (!value.match(/\d/)) return undefined;
// 0 = number, 1 = decimals
var sign = value.charAt(0) === '-' ? -1 : 1;
var parts = value.split('.');
var digitsRegex = /^-|\d/g; // include a check for a beginning "-" for negative numbers
var a = parts[0].match(digitsRegex).join('');
var b = parts.length >= 2 && parts[1].match(digitsRegex).join('');
// This assumes if the user adds a "." it should be a float. If we want it to
// evaluate as an integer if there are no digits beyond the decimal, then we
// can change it.
var hasDecimal = parts[1] !== undefined;
if (hasDecimal) {
var a = toDigits(parts[0]);
var b = toDigits(parts[1]);
return sign * parseFloat(a + '.' + b);
} else {
return sign * parseInt(toDigits(parts[0]));
}
}
return b ? parseFloat(a + '.' + b) : parseInt(a);
/**
* Returns the value with additional masking characters
* @param {String} value
* @returns {String}
*/
function maskValue() {
var value = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
var mask = arguments[1];
if (value && typeof value === 'string') {
value = value.trim();
if (mask === 'currency') {
// Format number with commas. If the number includes a decimal,
// ensure it includes two decimal points
var number = toNumber(value);
if (number === undefined) {
value = '';
} else {
value = stringWithFixedDigits(number.toLocaleString('en-US'));
}
} else if (Object.keys(deliminatedMaskRegex).includes(mask)) {
value = deliminateRegexGroups(value, deliminatedMaskRegex[mask]);
}
}
return value;
}

@@ -136,12 +183,34 @@

var Mask = exports.Mask = function (_React$PureComponent) {
_inherits(Mask, _React$PureComponent);
var _Mask = function (_React$PureComponent) {
_inherits(_Mask, _React$PureComponent);
function Mask(props) {
_classCallCheck(this, Mask);
_createClass(_Mask, null, [{
key: 'getDerivedStateFromProps',
value: function getDerivedStateFromProps(props, state) {
var fieldProps = _react2.default.Children.only(props.children).props;
var isControlled = fieldProps.value !== undefined;
if (isControlled) {
var mask = props.mask;
var _this = _possibleConstructorReturn(this, (Mask.__proto__ || Object.getPrototypeOf(Mask)).call(this, props));
if (unmask(fieldProps.value, mask) !== unmask(state.value, mask)) {
return {
value: maskValue(fieldProps.value || '', mask)
};
}
}
return null;
}
}]);
function _Mask(props) {
_classCallCheck(this, _Mask);
var _this = _possibleConstructorReturn(this, (_Mask.__proto__ || Object.getPrototypeOf(_Mask)).call(this, props));
var field = _this.field();
var initialValue = field.props.value || field.props.defaultValue;
// console.log('initial value', initialValue, maskValue(initialValue, props.mask), props.mask)
_this.state = {
value: _this.maskedValue(_this.initialValue())
value: maskValue(initialValue, props.mask)
};

@@ -151,3 +220,3 @@ return _this;

_createClass(Mask, [{
_createClass(_Mask, [{
key: 'componentDidUpdate',

@@ -174,30 +243,2 @@ value: function componentDidUpdate() {

/**
* Returns the value with additional masking characters
* @param {String} value
* @returns {String}
*/
}, {
key: 'maskedValue',
value: function maskedValue() {
var value = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
if (value && typeof value === 'string') {
var mask = this.props.mask;
value = value.trim();
if (mask === 'currency') {
// Format number with commas. If the number includes a decimal,
// ensure it includes two decimal points
value = stringWithFixedDigits(toNumber(value).toLocaleString('en-US'));
} else if (Object.keys(deliminatedMaskRegex).includes(mask)) {
value = deliminateRegexGroups(value, deliminatedMaskRegex[mask]);
}
}
return value;
}
/**
* To avoid a jarring experience for screen readers, we only

@@ -213,3 +254,3 @@ * add/remove characters after the field has been blurred,

value: function handleBlur(evt, field) {
var value = this.maskedValue(evt.target.value);
var value = maskValue(evt.target.value, this.props.mask);

@@ -256,8 +297,2 @@ // We only debounce the onBlur when we know for sure that

}, {
key: 'initialValue',
value: function initialValue() {
var field = this.field();
return field.props.value || field.props.defaultValue;
}
}, {
key: 'render',

@@ -282,6 +317,6 @@ value: function render() {

return Mask;
return _Mask;
}(_react2.default.PureComponent);
Mask.propTypes = {
_Mask.propTypes = {
/** Pass the input as the child */

@@ -305,3 +340,8 @@ children: _propTypes2.default.node.isRequired,

// Preserve only digits, decimal point, or negative symbol
value = value.match(/^-|[\d.]/g).join('');
var matches = value.match(/^-|[\d.]/g);
if (matches) {
value = matches.join('');
} else {
value = '';
}
} else if (Object.keys(deliminatedMaskRegex).includes(mask)) {

@@ -317,2 +357,5 @@ // Remove the deliminators and revert to single ungrouped string

var Mask = (0, _reactLifecyclesCompat.polyfill)(_Mask);
exports.Mask = Mask;
exports.default = Mask;
{
"name": "@cmsgov/design-system-core",
"version": "1.25.0",
"version": "1.26.0",
"publishConfig": {

@@ -12,3 +12,3 @@ "access": "public"

"dependencies": {
"@cmsgov/design-system-support": "^1.25.0",
"@cmsgov/design-system-support": "^1.26.0",
"classnames": "^2.2.5",

@@ -19,3 +19,4 @@ "core-js": "^2.5.3",

"lodash.uniqueid": "^4.0.1",
"react-aria-modal": "^2.11.1"
"react-aria-modal": "^2.11.1",
"react-lifecycles-compat": "^3.0.4"
},

@@ -22,0 +23,0 @@ "peerDependencies": {

@@ -19,3 +19,3 @@ import TextField, { unmaskValue } from './TextField';

onBlur={evt => handleBlur(evt, 'currency')}
value="2500"
defaultValue="2500"
/>

@@ -29,3 +29,3 @@

type="tel"
value="1234567890"
defaultValue="1234567890"
/>

@@ -38,3 +38,3 @@

onBlur={evt => handleBlur(evt, 'ssn')}
value="123456789"
defaultValue="123456789"
/>

@@ -47,3 +47,3 @@

onBlur={evt => handleBlur(evt, 'zip')}
value="123456789"
defaultValue="123456789"
/>

@@ -50,0 +50,0 @@ </div>

@@ -11,2 +11,3 @@ /*

import React from 'react';
import { polyfill } from 'react-lifecycles-compat';

@@ -64,3 +65,3 @@ // Deliminate chunks of integers

/**
* Remove all non-digits
* Remove everything that isn't a digit or asterisk
* @param {String} value

@@ -74,2 +75,11 @@ * @returns {String}

/**
* Remove all non-digits
* @param {String} value
* @returns {String}
*/
function toDigits(value) {
return value.replace(/[^\d]/g, '');
}
/**
* Convert string into a number (positive or negative float or integer)

@@ -81,10 +91,43 @@ * @param {String} value

if (typeof value !== 'string') return value;
if (!value.match(/\d/)) return undefined;
// 0 = number, 1 = decimals
const sign = value.charAt(0) === '-' ? -1 : 1;
const parts = value.split('.');
const digitsRegex = /^-|\d/g; // include a check for a beginning "-" for negative numbers
const a = parts[0].match(digitsRegex).join('');
const b = parts.length >= 2 && parts[1].match(digitsRegex).join('');
// This assumes if the user adds a "." it should be a float. If we want it to
// evaluate as an integer if there are no digits beyond the decimal, then we
// can change it.
const hasDecimal = parts[1] !== undefined;
if (hasDecimal) {
const a = toDigits(parts[0]);
const b = toDigits(parts[1]);
return sign * parseFloat(`${a}.${b}`);
} else {
return sign * parseInt(toDigits(parts[0]));
}
}
return b ? parseFloat(`${a}.${b}`) : parseInt(a);
/**
* Returns the value with additional masking characters
* @param {String} value
* @returns {String}
*/
function maskValue(value = '', mask) {
if (value && typeof value === 'string') {
value = value.trim();
if (mask === 'currency') {
// Format number with commas. If the number includes a decimal,
// ensure it includes two decimal points
const number = toNumber(value);
if (number === undefined) {
value = '';
} else {
value = stringWithFixedDigits(number.toLocaleString('en-US'));
}
} else if (Object.keys(deliminatedMaskRegex).includes(mask)) {
value = deliminateRegexGroups(value, deliminatedMaskRegex[mask]);
}
}
return value;
}

@@ -111,8 +154,26 @@

*/
export class Mask extends React.PureComponent {
class _Mask extends React.PureComponent {
static getDerivedStateFromProps(props, state) {
const fieldProps = React.Children.only(props.children).props;
const isControlled = fieldProps.value !== undefined;
if (isControlled) {
const { mask } = props;
if (unmask(fieldProps.value, mask) !== unmask(state.value, mask)) {
return {
value: maskValue(fieldProps.value || '', mask)
};
}
}
return null;
}
constructor(props) {
super(props);
const field = this.field();
const initialValue = field.props.value || field.props.defaultValue;
// console.log('initial value', initialValue, maskValue(initialValue, props.mask), props.mask)
this.state = {
value: this.maskedValue(this.initialValue())
value: maskValue(initialValue, props.mask)
};

@@ -138,24 +199,2 @@ }

/**
* Returns the value with additional masking characters
* @param {String} value
* @returns {String}
*/
maskedValue(value = '') {
if (value && typeof value === 'string') {
const { mask } = this.props;
value = value.trim();
if (mask === 'currency') {
// Format number with commas. If the number includes a decimal,
// ensure it includes two decimal points
value = stringWithFixedDigits(toNumber(value).toLocaleString('en-US'));
} else if (Object.keys(deliminatedMaskRegex).includes(mask)) {
value = deliminateRegexGroups(value, deliminatedMaskRegex[mask]);
}
}
return value;
}
/**
* To avoid a jarring experience for screen readers, we only

@@ -168,3 +207,3 @@ * add/remove characters after the field has been blurred,

handleBlur(evt, field) {
const value = this.maskedValue(evt.target.value);
const value = maskValue(evt.target.value, this.props.mask);

@@ -209,7 +248,2 @@ // We only debounce the onBlur when we know for sure that

initialValue() {
const field = this.field();
return field.props.value || field.props.defaultValue;
}
render() {

@@ -227,3 +261,3 @@ const field = this.field();

Mask.propTypes = {
_Mask.propTypes = {
/** Pass the input as the child */

@@ -247,3 +281,8 @@ children: PropTypes.node.isRequired,

// Preserve only digits, decimal point, or negative symbol
value = value.match(/^-|[\d.]/g).join('');
const matches = value.match(/^-|[\d.]/g);
if (matches) {
value = matches.join('');
} else {
value = '';
}
} else if (Object.keys(deliminatedMaskRegex).includes(mask)) {

@@ -259,2 +298,5 @@ // Remove the deliminators and revert to single ungrouped string

const Mask = polyfill(_Mask);
export { Mask };
export default Mask;

@@ -93,2 +93,38 @@ import Mask, { unmask } from './Mask';

describe('Controlled component behavior', () => {
it('will not cause masking until blur when value prop still matches unmasked input', () => {
const { wrapper } = render({ mask: 'currency' }, { value: '1000' }, true);
const input = () => wrapper.find('input');
expect(input().prop('value')).toBe('1,000');
// Simulate user typing input and the component calling onChange, and that
// cascading back down to a new prop for the input.
input()
.props()
.onChange({ target: { value: '1,0000' } });
wrapper.setProps({
children: <input name="foo" type="text" value="10000" />
});
expect(input().prop('value')).toBe('1,0000');
input().simulate('blur', {
target: { value: '1,0000' },
persist: jest.fn()
});
expect(input().prop('value')).toBe('10,000');
});
it('will change the value of the input when value prop changes (beyond unmasked/masked differences)', () => {
const { wrapper } = render({ mask: 'currency' }, { value: '1000' }, true);
const input = () => wrapper.find('input');
expect(input().prop('value')).toBe('1,000');
// Make sure we can change the value
wrapper.setProps({
children: <input name="foo" type="text" value="2000" />
});
expect(input().prop('value')).toBe('2,000');
});
});
describe('Currency', () => {

@@ -302,2 +338,22 @@ it('accepts already masked value', () => {

it('returns empty string when there are no numeric characters in the value', () => {
expect(unmask('banana', 'currency')).toBe('');
expect(unmask('banana', 'zip')).toBe('');
expect(unmask('banana', 'ssn')).toBe('');
expect(unmask('banana', 'phone')).toBe('');
});
it('returns just the numbers when there is other garbage mixed in', () => {
expect(unmask('b4n4n4', 'currency')).toBe('444');
expect(unmask('b4n4n4', 'zip')).toBe('444');
expect(unmask('b4n4n4', 'ssn')).toBe('444');
expect(unmask('b4n4n4', 'phone')).toBe('444');
expect(unmask('a1.b2c3', 'currency')).toBe('1.23');
expect(unmask('1,,00.b', 'currency')).toBe('100.');
expect(unmask('1-1-1-2-3-4', 'zip')).toBe('111234');
expect(unmask('4---31', 'ssn')).toBe('431');
expect(unmask('--2-3444', 'phone')).toBe('23444');
});
it('removes mask from currency value', () => {

@@ -304,0 +360,0 @@ const name = 'currency';

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc