diff --git a/playbook/app/pb_kits/playbook/pb_text_input/docs/_text_input_mask.jsx b/playbook/app/pb_kits/playbook/pb_text_input/docs/_text_input_mask.jsx index 3af05e3036..887fdd9176 100755 --- a/playbook/app/pb_kits/playbook/pb_text_input/docs/_text_input_mask.jsx +++ b/playbook/app/pb_kits/playbook/pb_text_input/docs/_text_input_mask.jsx @@ -16,6 +16,8 @@ const TextInputMask = (props) => { zipCode: '', postalCode: '', ssn: '', + creditCard: '', + cvv: '' }) const handleOnChangeFormField = ({ target }) => { @@ -57,6 +59,22 @@ const TextInputMask = (props) => { value={formFields.ssn} {...props} /> + +

diff --git a/playbook/app/pb_kits/playbook/pb_text_input/inputMask.ts b/playbook/app/pb_kits/playbook/pb_text_input/inputMask.ts index 3b80cbb262..db7088fa23 100644 --- a/playbook/app/pb_kits/playbook/pb_text_input/inputMask.ts +++ b/playbook/app/pb_kits/playbook/pb_text_input/inputMask.ts @@ -6,7 +6,7 @@ type InputMask = { } type InputMaskDictionary = { - [key in 'currency' | 'zipCode' | 'postalCode' | 'ssn']: InputMask + [key in 'currency' | 'zipCode' | 'postalCode' | 'ssn' | 'creditCard' | 'cvv']: InputMask } const formatCurrencyDefaultValue = (value: string): string => { @@ -58,6 +58,15 @@ const formatSSN = (value: string): string => { .replace(/(\d{3})(?=\d)/, '$1-') } +const formatCreditCard = (value: string): string => { + const cleaned = value.replace(/\D/g, '').slice(0, 16) + return cleaned.replace(/(\d{4})(?=\d)/g, '$1 ') +} + +const formatCVV = (value: string): string => { + return value.replace(/\D/g, '').slice(0, 4) +} + export const INPUTMASKS: InputMaskDictionary = { currency: { format: formatCurrency, @@ -84,4 +93,16 @@ export const INPUTMASKS: InputMaskDictionary = { pattern: '\\d{3}-\\d{2}-\\d{4}', placeholder: '123-45-6789', }, + creditCard: { + format: formatCreditCard, + formatDefaultValue: formatCreditCard, + pattern: '\\d{4} \\d{4} \\d{4} \\d{4}', + placeholder: '1234 5678 9012 3456', + }, + cvv: { + format: formatCVV, + formatDefaultValue: formatCVV, + pattern: '\\d{3,4}', + placeholder: '123', + }, } diff --git a/playbook/app/pb_kits/playbook/pb_text_input/text_input.test.js b/playbook/app/pb_kits/playbook/pb_text_input/text_input.test.js index d901dd55f5..8f678a9311 100644 --- a/playbook/app/pb_kits/playbook/pb_text_input/text_input.test.js +++ b/playbook/app/pb_kits/playbook/pb_text_input/text_input.test.js @@ -226,3 +226,83 @@ test('returns masked ssn value', () => { expect(input.value).toBe('123-45-6789') }) + +const TextInputCreditCardMask = (props) => { + const [creditCard, setValue] = useState('') + const handleOnChange = ({ target }) => { + setValue(target.value) + } + + return ( + + ) +} + +test('returns masked credit card value', () => { + render( + + ) + + const kit = screen.getByTestId(testId) + + const input = within(kit).getByRole('textbox') + + fireEvent.change(input, { target: { value: '1234567890123456' } }) + + expect(input.value).toBe('1234 5678 9012 3456') + + fireEvent.change(input, { target: { value: '1234' } }) + + expect(input.value).toBe('1234') + + fireEvent.change(input, { target: { value: '' } }) + + expect(input.value).toBe('') +}) + +const TextInputCVVMask = (props) => { + const [cvv, setValue] = useState('') + const handleOnChange = ({ target }) => { + setValue(target.value) + } + + return ( + + ) +} + +test('returns masked CVV value', () => { + render( + + ) + + const kit = screen.getByTestId(testId) + + const input = within(kit).getByRole('textbox') + + fireEvent.change(input, { target: { value: '1234' } }) + + expect(input.value).toBe('1234') + + fireEvent.change(input, { target: { value: '123' } }) + + expect(input.value).toBe('123') + + fireEvent.change(input, { target: { value: '' } }) + + expect(input.value).toBe('') +})