@availity/phone 2.2.6 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/README.md +6 -0
- package/dist/index.js +90 -0
- package/index.js +2 -2
- package/package.json +19 -7
- package/project.json +16 -4
- package/tests/Phone.test.jsx +154 -0
- package/vitest.config.ts +17 -0
- package/jest.config.js +0 -7
- package/tsconfig.spec.json +0 -10
- /package/src/{Phone.js → Phone.jsx} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
|
|
4
4
|
|
|
5
|
+
# [3.0.0](https://github.com/Availity/availity-react/compare/@availity/phone@2.2.6...@availity/phone@3.0.0) (2026-06-12)
|
|
6
|
+
|
|
7
|
+
### Dependency Updates
|
|
8
|
+
|
|
9
|
+
* `@availity/form` updated to version `2.2.6`
|
|
10
|
+
|
|
11
|
+
* feat(phone)!: migrate to ESM exports and vitest ([8542c94](https://github.com/Availity/availity-react/commit/8542c94d7322c8ec81baa1fc332cb1265d53bdcf))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### BREAKING CHANGES
|
|
15
|
+
|
|
16
|
+
* Package now uses ESM exports field. CJS require() is no longer supported.
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
5
20
|
## [2.2.6](https://github.com/Availity/availity-react/compare/@availity/phone@2.2.5...@availity/phone@2.2.6) (2025-12-03)
|
|
6
21
|
|
|
7
22
|
|
package/README.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @availity/phone
|
|
2
2
|
|
|
3
|
+
## ⚠️ Deprecated
|
|
4
|
+
|
|
5
|
+
This package is deprecated and no longer actively maintained. Future updates are not guaranteed. We recommend migrating to [`@availity/element`](https://availity.github.io/element).
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
3
9
|
> Availity Phone component using Formik and Yup
|
|
4
10
|
|
|
5
11
|
[](https://www.npmjs.com/package/@availity/phone)
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// src/Phone.jsx
|
|
2
|
+
import React, { useEffect } from "react";
|
|
3
|
+
import PropTypes from "prop-types";
|
|
4
|
+
import { Field } from "@availity/form";
|
|
5
|
+
import { useFormikContext } from "formik";
|
|
6
|
+
import { AsYouType } from "libphonenumber-js";
|
|
7
|
+
import { Row, Col } from "reactstrap";
|
|
8
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
+
var Phone = ({
|
|
10
|
+
name,
|
|
11
|
+
label,
|
|
12
|
+
country = "US",
|
|
13
|
+
showExtension = false,
|
|
14
|
+
extProps,
|
|
15
|
+
phoneColProps,
|
|
16
|
+
formatInitialValue,
|
|
17
|
+
...restPhoneProps
|
|
18
|
+
}) => {
|
|
19
|
+
const { setFieldValue, setFieldTouched, values } = useFormikContext();
|
|
20
|
+
let ext = null;
|
|
21
|
+
if (showExtension) {
|
|
22
|
+
const { name: name2, label: label2, extColProps, ...restExtProps } = extProps;
|
|
23
|
+
ext = /* @__PURE__ */ jsx(Col, { ...extColProps, children: /* @__PURE__ */ jsx(Field, { name: name2, label: label2, ...restExtProps }) });
|
|
24
|
+
}
|
|
25
|
+
const asYouFormat = (phoneString) => {
|
|
26
|
+
const asYouType = new AsYouType(country);
|
|
27
|
+
asYouType.input(phoneString);
|
|
28
|
+
return asYouType.formattedOutput;
|
|
29
|
+
};
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
if (formatInitialValue) {
|
|
32
|
+
setFieldValue(name, asYouFormat(values[name]), false);
|
|
33
|
+
}
|
|
34
|
+
}, []);
|
|
35
|
+
const formatPhoneOnBlur = ({ target: { value } }) => {
|
|
36
|
+
setFieldValue(name, asYouFormat(value), true);
|
|
37
|
+
setFieldTouched(name, true, true);
|
|
38
|
+
};
|
|
39
|
+
return /* @__PURE__ */ jsxs(Row, { children: [
|
|
40
|
+
/* @__PURE__ */ jsx(Col, { xs: showExtension ? 10 : 12, ...phoneColProps, children: /* @__PURE__ */ jsx(Field, { name, label, onBlur: formatPhoneOnBlur, ...restPhoneProps }) }),
|
|
41
|
+
ext
|
|
42
|
+
] });
|
|
43
|
+
};
|
|
44
|
+
Phone.propTypes = {
|
|
45
|
+
/** Identifies the field and matches the validation schema. */
|
|
46
|
+
name: PropTypes.string.isRequired,
|
|
47
|
+
/** Used to pass props to the extension field when it is enabled. */
|
|
48
|
+
extProps: PropTypes.shape({
|
|
49
|
+
name: PropTypes.string.isRequired,
|
|
50
|
+
label: PropTypes.string,
|
|
51
|
+
/** Used to control props on `<Col />` for the extension field, if needed. The extension column has no default size value, so it's default will effectively be size: { 12 - phoneColSize } unless otherwise specified. */
|
|
52
|
+
extColProps: PropTypes.object
|
|
53
|
+
}),
|
|
54
|
+
/** Displays a Reactstrap `<Label />` for the field. */
|
|
55
|
+
label: PropTypes.string,
|
|
56
|
+
/** Enable the phone extension field. */
|
|
57
|
+
showExtension: PropTypes.bool,
|
|
58
|
+
/** Default country for parsing national numbers. [This is the two letter ISO country code](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2). */
|
|
59
|
+
country: PropTypes.string,
|
|
60
|
+
/** Used to control props on the `<Col />` for the phone field, if needed. The phone column defaults to xs: { size: 12 } when not rendering an extension field, and defaults to xs: { size: 10 } when rendering an extension field. */
|
|
61
|
+
phoneColProps: PropTypes.object,
|
|
62
|
+
/** When true, when the field is first rendered, it will trigger the formatter to update the value. */
|
|
63
|
+
formatInitialValue: PropTypes.bool
|
|
64
|
+
};
|
|
65
|
+
var Phone_default = Phone;
|
|
66
|
+
|
|
67
|
+
// src/validatePhone.js
|
|
68
|
+
import { addMethod, string } from "yup";
|
|
69
|
+
import { AsYouType as AsYouType2 } from "libphonenumber-js";
|
|
70
|
+
function validatePhone(msg, strict = false, country = "US") {
|
|
71
|
+
return this.test({
|
|
72
|
+
name: "validatePhone",
|
|
73
|
+
exclusive: true,
|
|
74
|
+
message: msg || "This field is invalid.",
|
|
75
|
+
test(phoneValue) {
|
|
76
|
+
if (!phoneValue) return true;
|
|
77
|
+
const asYouType = new AsYouType2(country);
|
|
78
|
+
asYouType.input(phoneValue);
|
|
79
|
+
if (strict) {
|
|
80
|
+
return asYouType.getNumber() && asYouType.getNumber().isValid();
|
|
81
|
+
}
|
|
82
|
+
return asYouType.getNumber() && asYouType.getNumber().isPossible();
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
addMethod(string, "validatePhone", validatePhone);
|
|
87
|
+
export {
|
|
88
|
+
Phone_default as Phone,
|
|
89
|
+
validatePhone
|
|
90
|
+
};
|
package/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { default as Phone } from './src/Phone';
|
|
2
|
-
export { default as validatePhone } from './src/validatePhone';
|
|
1
|
+
export { default as Phone } from './src/Phone.jsx';
|
|
2
|
+
export { default as validatePhone } from './src/validatePhone.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@availity/phone",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "Availity Phone component using Formik and Yup",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"availity",
|
|
@@ -17,27 +17,30 @@
|
|
|
17
17
|
"directory": "packages/phone"
|
|
18
18
|
},
|
|
19
19
|
"license": "MIT",
|
|
20
|
+
"type": "module",
|
|
20
21
|
"author": "Christopher Havekost <Christopher.Havekost@availity.com>",
|
|
21
|
-
"main": "index.js",
|
|
22
|
-
"types": "index.d.ts",
|
|
23
22
|
"scripts": {
|
|
23
|
+
"build": "tsup index.js --format esm --clean --dts",
|
|
24
|
+
"dev": "tsup index.js --format esm --watch --dts",
|
|
25
|
+
"clean": "rm -rf dist",
|
|
24
26
|
"publish": "yarn npm publish --tolerate-republish --access public",
|
|
25
27
|
"publish:canary": "yarn npm publish --access public --tag canary"
|
|
26
28
|
},
|
|
27
29
|
"dependencies": {
|
|
28
|
-
"libphonenumber-js": "^1.
|
|
30
|
+
"libphonenumber-js": "^1.13.6",
|
|
29
31
|
"prop-types": "^15.8.1"
|
|
30
32
|
},
|
|
31
33
|
"devDependencies": {
|
|
32
|
-
"@availity/form": "
|
|
33
|
-
"formik": "^2.4.
|
|
34
|
+
"@availity/form": "2.0.0",
|
|
35
|
+
"formik": "^2.4.9",
|
|
34
36
|
"react": "^18.3.1",
|
|
35
37
|
"react-dom": "^18.3.1",
|
|
36
38
|
"reactstrap": "^8.10.1",
|
|
39
|
+
"tsup": "^8.5.1",
|
|
37
40
|
"yup": "^0.32.11"
|
|
38
41
|
},
|
|
39
42
|
"peerDependencies": {
|
|
40
|
-
"@availity/form": "
|
|
43
|
+
"@availity/form": "2.0.0",
|
|
41
44
|
"formik": "^2.4.6",
|
|
42
45
|
"react": "^18.0.0",
|
|
43
46
|
"reactstrap": "^8.10.1",
|
|
@@ -45,5 +48,14 @@
|
|
|
45
48
|
},
|
|
46
49
|
"publishConfig": {
|
|
47
50
|
"access": "public"
|
|
51
|
+
},
|
|
52
|
+
"exports": {
|
|
53
|
+
".": {
|
|
54
|
+
"source": "./index.js",
|
|
55
|
+
"import": {
|
|
56
|
+
"types": "./index.d.ts",
|
|
57
|
+
"default": "./dist/index.js"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
48
60
|
}
|
|
49
61
|
}
|
package/project.json
CHANGED
|
@@ -4,10 +4,15 @@
|
|
|
4
4
|
"projectType": "library",
|
|
5
5
|
"targets": {
|
|
6
6
|
"test": {
|
|
7
|
-
"executor": "
|
|
8
|
-
"outputs": ["{workspaceRoot}/coverage/phone"],
|
|
7
|
+
"executor": "nx:run-commands",
|
|
9
8
|
"options": {
|
|
10
|
-
"
|
|
9
|
+
"command": "vitest run --project=phone",
|
|
10
|
+
"cwd": "."
|
|
11
|
+
},
|
|
12
|
+
"configurations": {
|
|
13
|
+
"ci": {
|
|
14
|
+
"command": "vitest run --project=phone --coverage"
|
|
15
|
+
}
|
|
11
16
|
}
|
|
12
17
|
},
|
|
13
18
|
"version": {
|
|
@@ -16,7 +21,8 @@
|
|
|
16
21
|
"preset": "angular",
|
|
17
22
|
"commitMessageFormat": "chore({projectName}): release version ${version} [skip ci]",
|
|
18
23
|
"tagPrefix": "{projectName}@",
|
|
19
|
-
"baseBranch": "master"
|
|
24
|
+
"baseBranch": "master",
|
|
25
|
+
"trackDeps": true
|
|
20
26
|
}
|
|
21
27
|
},
|
|
22
28
|
"lint": {
|
|
@@ -33,6 +39,12 @@
|
|
|
33
39
|
"hasTypeAwareRules": true,
|
|
34
40
|
"cacheStrategy": "metadata"
|
|
35
41
|
}
|
|
42
|
+
},
|
|
43
|
+
"build": {
|
|
44
|
+
"command": "tsup index.js --format esm",
|
|
45
|
+
"options": {
|
|
46
|
+
"cwd": "packages/phone"
|
|
47
|
+
}
|
|
36
48
|
}
|
|
37
49
|
}
|
|
38
50
|
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import * as yup from 'yup';
|
|
3
|
+
import '../src/validatePhone';
|
|
4
|
+
import { render, fireEvent, waitFor, cleanup } from '@testing-library/react';
|
|
5
|
+
import { Form } from '@availity/form';
|
|
6
|
+
import { Phone } from '../index.js';
|
|
7
|
+
|
|
8
|
+
const phoneProps = {
|
|
9
|
+
name: 'test_phone',
|
|
10
|
+
id: 'test_phone',
|
|
11
|
+
title: 'Please enter number in the following format: 201-555-0123',
|
|
12
|
+
label: 'AvPhone',
|
|
13
|
+
// showExtension: true,
|
|
14
|
+
phoneColProps: {
|
|
15
|
+
xs: { size: 9 },
|
|
16
|
+
},
|
|
17
|
+
extProps: {
|
|
18
|
+
name: 'test-ext',
|
|
19
|
+
id: 'test-ext',
|
|
20
|
+
label: 'Ext.',
|
|
21
|
+
extColProps: {
|
|
22
|
+
xs: { size: 3 },
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const renderPhone = (props, strictValidation = false, initialPhoneValue = '201') => {
|
|
28
|
+
const Component = () => (
|
|
29
|
+
<Form
|
|
30
|
+
initialValues={{
|
|
31
|
+
test_phone: initialPhoneValue,
|
|
32
|
+
}}
|
|
33
|
+
onSubmit={() => {}}
|
|
34
|
+
validationSchema={yup.object().shape({
|
|
35
|
+
test_phone: yup.string().validatePhone('This field is invalid', strictValidation),
|
|
36
|
+
})}
|
|
37
|
+
>
|
|
38
|
+
<Phone name="test_phone" {...props} />
|
|
39
|
+
</Form>
|
|
40
|
+
);
|
|
41
|
+
return render(<Component />);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
describe('Phone', () => {
|
|
45
|
+
afterEach(() => {
|
|
46
|
+
cleanup();
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test('Should render extension field', async () => {
|
|
50
|
+
const { getByText } = renderPhone({
|
|
51
|
+
...phoneProps,
|
|
52
|
+
showExtension: true,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
await expect(getByText('Ext.')).toBeDefined();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test('Should format valid phone number when it initializes', async () => {
|
|
59
|
+
const { getByDisplayValue } = renderPhone({ ...phoneProps, formatInitialValue: true }, false, '2015550123');
|
|
60
|
+
|
|
61
|
+
await expect(getByDisplayValue('(201) 555-0123')).toBeDefined();
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test('Should format valid phone number', async () => {
|
|
65
|
+
const { getByDisplayValue } = renderPhone(phoneProps);
|
|
66
|
+
const testPhoneInput = getByDisplayValue('201');
|
|
67
|
+
|
|
68
|
+
// Set value
|
|
69
|
+
await fireEvent.change(testPhoneInput, {
|
|
70
|
+
target: {
|
|
71
|
+
name: 'test_phone',
|
|
72
|
+
value: '2015550123',
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// Formatter runs onBlur for screen reader friendliness
|
|
77
|
+
await fireEvent.blur(testPhoneInput);
|
|
78
|
+
|
|
79
|
+
await expect(getByDisplayValue('(201) 555-0123')).toBeDefined();
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test('Should format partial phone number', async () => {
|
|
83
|
+
const { getByDisplayValue } = renderPhone(phoneProps);
|
|
84
|
+
const testPhoneInput = getByDisplayValue('201');
|
|
85
|
+
|
|
86
|
+
await fireEvent.change(testPhoneInput, {
|
|
87
|
+
target: {
|
|
88
|
+
name: 'test_phone',
|
|
89
|
+
value: '20155501',
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
await fireEvent.blur(testPhoneInput);
|
|
94
|
+
|
|
95
|
+
await expect(getByDisplayValue('(201) 555-01')).toBeDefined();
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
test('Should not format invalid phone number', async () => {
|
|
99
|
+
const { getByDisplayValue } = renderPhone(phoneProps);
|
|
100
|
+
const testPhoneInput = getByDisplayValue('201');
|
|
101
|
+
|
|
102
|
+
await fireEvent.change(testPhoneInput, {
|
|
103
|
+
target: {
|
|
104
|
+
name: 'test_phone',
|
|
105
|
+
value: '22233344445',
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
await fireEvent.blur(testPhoneInput);
|
|
110
|
+
|
|
111
|
+
await expect(getByDisplayValue('22233344445')).toBeDefined();
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
test('Should render error message with strict validation', async () => {
|
|
115
|
+
const { getByDisplayValue, getByText } = renderPhone(phoneProps, true);
|
|
116
|
+
const testPhoneInput = getByDisplayValue('201');
|
|
117
|
+
|
|
118
|
+
await fireEvent.change(testPhoneInput, {
|
|
119
|
+
target: {
|
|
120
|
+
name: 'test_phone',
|
|
121
|
+
value: '2223334444',
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
await fireEvent.blur(testPhoneInput);
|
|
126
|
+
|
|
127
|
+
await waitFor(() => {
|
|
128
|
+
expect(testPhoneInput.className).toContain('is-touched');
|
|
129
|
+
expect(testPhoneInput.className).toContain('is-invalid');
|
|
130
|
+
expect(getByDisplayValue('(222) 333-4444')).toBeDefined();
|
|
131
|
+
expect(getByText('This field is invalid')).toBeDefined();
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test('Should not render error message with default lax validation', async () => {
|
|
136
|
+
const { getByDisplayValue } = renderPhone(phoneProps);
|
|
137
|
+
const testPhoneInput = getByDisplayValue('201');
|
|
138
|
+
|
|
139
|
+
await fireEvent.change(testPhoneInput, {
|
|
140
|
+
target: {
|
|
141
|
+
name: 'test_phone',
|
|
142
|
+
value: '2223334444',
|
|
143
|
+
},
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
await fireEvent.blur(testPhoneInput);
|
|
147
|
+
|
|
148
|
+
await waitFor(() => {
|
|
149
|
+
expect(testPhoneInput.className).toContain('is-touched');
|
|
150
|
+
expect(testPhoneInput.className).toContain('av-valid');
|
|
151
|
+
expect(getByDisplayValue('(222) 333-4444')).toBeDefined();
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
});
|
package/vitest.config.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { defineProject } from 'vitest/config';
|
|
2
|
+
|
|
3
|
+
export default defineProject({
|
|
4
|
+
test: {
|
|
5
|
+
name: 'phone',
|
|
6
|
+
globals: true,
|
|
7
|
+
environment: 'jsdom',
|
|
8
|
+
setupFiles: ['../../vitest.setup.ts'],
|
|
9
|
+
include: ['src/**/*.test.{ts,tsx,js,jsx}', 'tests/**/*.test.{ts,tsx,js,jsx}'],
|
|
10
|
+
env: { TZ: 'UTC' },
|
|
11
|
+
server: {
|
|
12
|
+
deps: {
|
|
13
|
+
inline: [/lodash/, /@availity\/yup/],
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
});
|
package/jest.config.js
DELETED
package/tsconfig.spec.json
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "./tsconfig.json",
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"outDir": "../../dist/out-tsc",
|
|
5
|
-
"module": "commonjs",
|
|
6
|
-
"types": ["jest", "node", "@testing-library/jest-dom"],
|
|
7
|
-
"allowJs": true
|
|
8
|
-
},
|
|
9
|
-
"include": ["**/*.test.js", "**/*.test.ts", "**/*.test.tsx", "**/*.d.ts"]
|
|
10
|
-
}
|
|
File without changes
|