@servicetitan/form 38.2.0 → 38.3.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/dist/demo/index.d.ts +1 -0
- package/dist/demo/index.d.ts.map +1 -1
- package/dist/demo/index.js +1 -0
- package/dist/demo/index.js.map +1 -1
- package/dist/demo/phone-number-input-a2.d.ts +3 -0
- package/dist/demo/phone-number-input-a2.d.ts.map +1 -0
- package/dist/demo/phone-number-input-a2.js +99 -0
- package/dist/demo/phone-number-input-a2.js.map +1 -0
- package/dist/form.stories.d.ts +1 -0
- package/dist/form.stories.d.ts.map +1 -1
- package/dist/phone-number-input/index.d.ts +1 -0
- package/dist/phone-number-input/index.d.ts.map +1 -1
- package/dist/phone-number-input/index.js +1 -0
- package/dist/phone-number-input/index.js.map +1 -1
- package/dist/phone-number-input/phone-number-input-a2.d.ts +10 -0
- package/dist/phone-number-input/phone-number-input-a2.d.ts.map +1 -0
- package/dist/phone-number-input/phone-number-input-a2.js +64 -0
- package/dist/phone-number-input/phone-number-input-a2.js.map +1 -0
- package/package.json +15 -8
- package/src/demo/index.ts +1 -0
- package/src/demo/phone-number-input-a2.tsx +89 -0
- package/src/form.stories.tsx +2 -0
- package/src/phone-number-input/index.ts +1 -0
- package/src/phone-number-input/phone-number-input-a2.tsx +73 -0
package/dist/demo/index.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export * from './date-range-picker';
|
|
|
3
3
|
export * from './file-uploader';
|
|
4
4
|
export * from './number-input';
|
|
5
5
|
export * from './phone-number-input';
|
|
6
|
+
export * from './phone-number-input-a2';
|
|
6
7
|
export * from './original-number-input';
|
|
7
8
|
export * from './input-date-mask';
|
|
8
9
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/demo/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/demo/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/demo/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AACxC,cAAc,mBAAmB,CAAC"}
|
package/dist/demo/index.js
CHANGED
|
@@ -3,6 +3,7 @@ export * from './date-range-picker';
|
|
|
3
3
|
export * from './file-uploader';
|
|
4
4
|
export * from './number-input';
|
|
5
5
|
export * from './phone-number-input';
|
|
6
|
+
export * from './phone-number-input-a2';
|
|
6
7
|
export * from './original-number-input';
|
|
7
8
|
export * from './input-date-mask';
|
|
8
9
|
|
package/dist/demo/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/demo/index.ts"],"sourcesContent":["export * from './color-picker';\nexport * from './date-range-picker';\nexport * from './file-uploader';\nexport * from './number-input';\nexport * from './phone-number-input';\nexport * from './original-number-input';\nexport * from './input-date-mask';\n"],"names":[],"mappings":"AAAA,cAAc,iBAAiB;AAC/B,cAAc,sBAAsB;AACpC,cAAc,kBAAkB;AAChC,cAAc,iBAAiB;AAC/B,cAAc,uBAAuB;AACrC,cAAc,0BAA0B;AACxC,cAAc,oBAAoB"}
|
|
1
|
+
{"version":3,"sources":["../../src/demo/index.ts"],"sourcesContent":["export * from './color-picker';\nexport * from './date-range-picker';\nexport * from './file-uploader';\nexport * from './number-input';\nexport * from './phone-number-input';\nexport * from './phone-number-input-a2';\nexport * from './original-number-input';\nexport * from './input-date-mask';\n"],"names":[],"mappings":"AAAA,cAAc,iBAAiB;AAC/B,cAAc,sBAAsB;AACpC,cAAc,kBAAkB;AAChC,cAAc,iBAAiB;AAC/B,cAAc,uBAAuB;AACrC,cAAc,0BAA0B;AACxC,cAAc,0BAA0B;AACxC,cAAc,oBAAoB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"phone-number-input-a2.d.ts","sourceRoot":"","sources":["../../src/demo/phone-number-input-a2.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAe,EAAE,EAAY,MAAM,OAAO,CAAC;AAyBlD,eAAO,MAAM,yBAAyB,EAAE,EA+DtC,CAAC"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { observer } from 'mobx-react';
|
|
4
|
+
import { PhoneNumberInputA2 } from '..';
|
|
5
|
+
const cultures = {
|
|
6
|
+
nanp: {
|
|
7
|
+
PhoneFormat: {
|
|
8
|
+
SimplePhoneMask: '(999) 999-9999?',
|
|
9
|
+
SimplePhonePlaceholder: '(___) ___-____'
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
au: {
|
|
13
|
+
PhoneFormat: {
|
|
14
|
+
SimplePhoneMask: '99 9999 9999',
|
|
15
|
+
SimplePhonePlaceholder: '__ ____ ____'
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
export const PhoneNumberInputA2Example = observer(()=>{
|
|
20
|
+
const [value, setValue] = useState('');
|
|
21
|
+
const [cultureKey, setCultureKey] = useState('nanp');
|
|
22
|
+
const [sip, setSip] = useState(false);
|
|
23
|
+
const handleChange = (e)=>{
|
|
24
|
+
setValue(e.target.value);
|
|
25
|
+
};
|
|
26
|
+
const handleCultureChange = (e)=>{
|
|
27
|
+
setCultureKey(e.target.value);
|
|
28
|
+
setValue('');
|
|
29
|
+
};
|
|
30
|
+
return /*#__PURE__*/ _jsxs("div", {
|
|
31
|
+
children: [
|
|
32
|
+
/*#__PURE__*/ _jsxs("fieldset", {
|
|
33
|
+
children: [
|
|
34
|
+
/*#__PURE__*/ _jsx("legend", {
|
|
35
|
+
children: "Region"
|
|
36
|
+
}),
|
|
37
|
+
/*#__PURE__*/ _jsxs("label", {
|
|
38
|
+
children: [
|
|
39
|
+
/*#__PURE__*/ _jsx("input", {
|
|
40
|
+
type: "radio",
|
|
41
|
+
name: "culture",
|
|
42
|
+
value: "nanp",
|
|
43
|
+
checked: cultureKey === 'nanp',
|
|
44
|
+
onChange: handleCultureChange
|
|
45
|
+
}),
|
|
46
|
+
"US/Canada (NANP)"
|
|
47
|
+
]
|
|
48
|
+
}),
|
|
49
|
+
/*#__PURE__*/ _jsxs("label", {
|
|
50
|
+
style: {
|
|
51
|
+
marginLeft: 16
|
|
52
|
+
},
|
|
53
|
+
children: [
|
|
54
|
+
/*#__PURE__*/ _jsx("input", {
|
|
55
|
+
type: "radio",
|
|
56
|
+
name: "culture",
|
|
57
|
+
value: "au",
|
|
58
|
+
checked: cultureKey === 'au',
|
|
59
|
+
onChange: handleCultureChange
|
|
60
|
+
}),
|
|
61
|
+
"Australia"
|
|
62
|
+
]
|
|
63
|
+
})
|
|
64
|
+
]
|
|
65
|
+
}),
|
|
66
|
+
/*#__PURE__*/ _jsx("br", {}),
|
|
67
|
+
/*#__PURE__*/ _jsxs("label", {
|
|
68
|
+
children: [
|
|
69
|
+
/*#__PURE__*/ _jsx("input", {
|
|
70
|
+
type: "checkbox",
|
|
71
|
+
checked: sip,
|
|
72
|
+
onChange: (e)=>{
|
|
73
|
+
setSip(e.target.checked);
|
|
74
|
+
setValue('');
|
|
75
|
+
}
|
|
76
|
+
}),
|
|
77
|
+
"SIP"
|
|
78
|
+
]
|
|
79
|
+
}),
|
|
80
|
+
/*#__PURE__*/ _jsx("br", {}),
|
|
81
|
+
/*#__PURE__*/ _jsx("br", {}),
|
|
82
|
+
/*#__PURE__*/ _jsx(PhoneNumberInputA2, {
|
|
83
|
+
culture: cultures[cultureKey],
|
|
84
|
+
label: "Phone",
|
|
85
|
+
value: value,
|
|
86
|
+
onChange: handleChange,
|
|
87
|
+
sip: sip
|
|
88
|
+
}),
|
|
89
|
+
/*#__PURE__*/ _jsxs("p", {
|
|
90
|
+
children: [
|
|
91
|
+
"Returned value: ",
|
|
92
|
+
value
|
|
93
|
+
]
|
|
94
|
+
})
|
|
95
|
+
]
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
//# sourceMappingURL=phone-number-input-a2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/demo/phone-number-input-a2.tsx"],"sourcesContent":["import { ChangeEvent, FC, useState } from 'react';\n\nimport { observer } from 'mobx-react';\n\nimport { Culture } from '@servicetitan/culture';\n\nimport { PhoneNumberInputA2 } from '..';\n\ntype CultureKey = 'nanp' | 'au';\n\nconst cultures: Record<CultureKey, Culture> = {\n nanp: {\n PhoneFormat: {\n SimplePhoneMask: '(999) 999-9999?',\n SimplePhonePlaceholder: '(___) ___-____',\n },\n } as Culture,\n au: {\n PhoneFormat: {\n SimplePhoneMask: '99 9999 9999',\n SimplePhonePlaceholder: '__ ____ ____',\n },\n } as Culture,\n};\n\nexport const PhoneNumberInputA2Example: FC = observer(() => {\n const [value, setValue] = useState('');\n const [cultureKey, setCultureKey] = useState<CultureKey>('nanp');\n const [sip, setSip] = useState(false);\n\n const handleChange = (e: ChangeEvent<HTMLInputElement>) => {\n setValue(e.target.value);\n };\n\n const handleCultureChange = (e: ChangeEvent<HTMLInputElement>) => {\n setCultureKey(e.target.value as CultureKey);\n setValue('');\n };\n\n return (\n <div>\n <fieldset>\n <legend>Region</legend>\n <label>\n <input\n type=\"radio\"\n name=\"culture\"\n value=\"nanp\"\n checked={cultureKey === 'nanp'}\n onChange={handleCultureChange}\n />\n US/Canada (NANP)\n </label>\n <label style={{ marginLeft: 16 }}>\n <input\n type=\"radio\"\n name=\"culture\"\n value=\"au\"\n checked={cultureKey === 'au'}\n onChange={handleCultureChange}\n />\n Australia\n </label>\n </fieldset>\n <br />\n <label>\n <input\n type=\"checkbox\"\n checked={sip}\n onChange={e => {\n setSip(e.target.checked);\n setValue('');\n }}\n />\n SIP\n </label>\n <br />\n <br />\n <PhoneNumberInputA2\n culture={cultures[cultureKey]}\n label=\"Phone\"\n value={value}\n onChange={handleChange}\n sip={sip}\n />\n <p>Returned value: {value}</p>\n </div>\n );\n});\n"],"names":["useState","observer","PhoneNumberInputA2","cultures","nanp","PhoneFormat","SimplePhoneMask","SimplePhonePlaceholder","au","PhoneNumberInputA2Example","value","setValue","cultureKey","setCultureKey","sip","setSip","handleChange","e","target","handleCultureChange","div","fieldset","legend","label","input","type","name","checked","onChange","style","marginLeft","br","culture","p"],"mappings":";AAAA,SAA0BA,QAAQ,QAAQ,QAAQ;AAElD,SAASC,QAAQ,QAAQ,aAAa;AAItC,SAASC,kBAAkB,QAAQ,KAAK;AAIxC,MAAMC,WAAwC;IAC1CC,MAAM;QACFC,aAAa;YACTC,iBAAiB;YACjBC,wBAAwB;QAC5B;IACJ;IACAC,IAAI;QACAH,aAAa;YACTC,iBAAiB;YACjBC,wBAAwB;QAC5B;IACJ;AACJ;AAEA,OAAO,MAAME,4BAAgCR,SAAS;IAClD,MAAM,CAACS,OAAOC,SAAS,GAAGX,SAAS;IACnC,MAAM,CAACY,YAAYC,cAAc,GAAGb,SAAqB;IACzD,MAAM,CAACc,KAAKC,OAAO,GAAGf,SAAS;IAE/B,MAAMgB,eAAe,CAACC;QAClBN,SAASM,EAAEC,MAAM,CAACR,KAAK;IAC3B;IAEA,MAAMS,sBAAsB,CAACF;QACzBJ,cAAcI,EAAEC,MAAM,CAACR,KAAK;QAC5BC,SAAS;IACb;IAEA,qBACI,MAACS;;0BACG,MAACC;;kCACG,KAACC;kCAAO;;kCACR,MAACC;;0CACG,KAACC;gCACGC,MAAK;gCACLC,MAAK;gCACLhB,OAAM;gCACNiB,SAASf,eAAe;gCACxBgB,UAAUT;;4BACZ;;;kCAGN,MAACI;wBAAMM,OAAO;4BAAEC,YAAY;wBAAG;;0CAC3B,KAACN;gCACGC,MAAK;gCACLC,MAAK;gCACLhB,OAAM;gCACNiB,SAASf,eAAe;gCACxBgB,UAAUT;;4BACZ;;;;;0BAIV,KAACY;0BACD,MAACR;;kCACG,KAACC;wBACGC,MAAK;wBACLE,SAASb;wBACTc,UAAUX,CAAAA;4BACNF,OAAOE,EAAEC,MAAM,CAACS,OAAO;4BACvBhB,SAAS;wBACb;;oBACF;;;0BAGN,KAACoB;0BACD,KAACA;0BACD,KAAC7B;gBACG8B,SAAS7B,QAAQ,CAACS,WAAW;gBAC7BW,OAAM;gBACNb,OAAOA;gBACPkB,UAAUZ;gBACVF,KAAKA;;0BAET,MAACmB;;oBAAE;oBAAiBvB;;;;;AAGhC,GAAG"}
|
package/dist/form.stories.d.ts
CHANGED
|
@@ -10,4 +10,5 @@ export declare const InputDateMask: () => import("react/jsx-runtime").JSX.Elemen
|
|
|
10
10
|
export declare const NumberInput: () => import("react/jsx-runtime").JSX.Element;
|
|
11
11
|
export declare const OrdinalNumberInput: () => import("react/jsx-runtime").JSX.Element;
|
|
12
12
|
export declare const PhoneNumberInput: () => import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
export declare const PhoneNumberInputA2: () => import("react/jsx-runtime").JSX.Element;
|
|
13
14
|
//# sourceMappingURL=form.stories.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"form.stories.d.ts","sourceRoot":"","sources":["../src/form.stories.tsx"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"form.stories.d.ts","sourceRoot":"","sources":["../src/form.stories.tsx"],"names":[],"mappings":";;yBAgBgB,GAAG;;AAHnB,wBAaE;AAEF,eAAO,MAAM,WAAW,+CAA+B,CAAC;AACxD,eAAO,MAAM,eAAe,+CAAmC,CAAC;AAChE,eAAO,MAAM,YAAY,+CAAgC,CAAC;AAC1D,eAAO,MAAM,aAAa,+CAAiC,CAAC;AAC5D,eAAO,MAAM,WAAW,+CAA+B,CAAC;AACxD,eAAO,MAAM,kBAAkB,+CAAsC,CAAC;AACtE,eAAO,MAAM,gBAAgB,+CAAoC,CAAC;AAClE,eAAO,MAAM,kBAAkB,+CAAsC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/phone-number-input/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/phone-number-input/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/phone-number-input/index.ts"],"sourcesContent":["export * from './phone-number-input';\n"],"names":[],"mappings":"AAAA,cAAc,uBAAuB"}
|
|
1
|
+
{"version":3,"sources":["../../src/phone-number-input/index.ts"],"sourcesContent":["export * from './phone-number-input';\nexport * from './phone-number-input-a2';\n"],"names":[],"mappings":"AAAA,cAAc,uBAAuB;AACrC,cAAc,0BAA0B"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { FC } from 'react';
|
|
2
|
+
import { TextFieldProps } from '@servicetitan/anvil2';
|
|
3
|
+
import { Culture } from '@servicetitan/culture';
|
|
4
|
+
type PhoneNumberInputA2Props = TextFieldProps & {
|
|
5
|
+
sip?: boolean;
|
|
6
|
+
culture?: Culture;
|
|
7
|
+
};
|
|
8
|
+
export declare const PhoneNumberInputA2: FC<PhoneNumberInputA2Props>;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=phone-number-input-a2.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"phone-number-input-a2.d.ts","sourceRoot":"","sources":["../../src/phone-number-input/phone-number-input-a2.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAe,EAAE,EAAe,MAAM,OAAO,CAAC;AAGrD,OAAO,EAAa,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,EAAE,OAAO,EAAiB,MAAM,uBAAuB,CAAC;AAG/D,KAAK,uBAAuB,GAAG,cAAc,GAAG;IAC5C,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,EAAE,CAAC,uBAAuB,CA4D1D,CAAC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback } from 'react';
|
|
3
|
+
import ReactInputMask from 'react-input-mask';
|
|
4
|
+
import { TextField } from '@servicetitan/anvil2';
|
|
5
|
+
import { CULTURE_TOKEN } from '@servicetitan/culture';
|
|
6
|
+
import { useOptionalDependencies } from '@servicetitan/react-ioc';
|
|
7
|
+
export const PhoneNumberInputA2 = (props)=>{
|
|
8
|
+
var _ref;
|
|
9
|
+
const { value, onChange, placeholder: propPlaceholder, culture: propCulture, sip, ...restProps } = props;
|
|
10
|
+
const [injectedCulture] = useOptionalDependencies(CULTURE_TOKEN);
|
|
11
|
+
const culture = propCulture !== null && propCulture !== void 0 ? propCulture : injectedCulture;
|
|
12
|
+
const { SimplePhoneMask = '?9999999999', SimplePhonePlaceholder = '' } = (_ref = culture === null || culture === void 0 ? void 0 : culture.PhoneFormat) !== null && _ref !== void 0 ? _ref : {};
|
|
13
|
+
const mask = SimplePhoneMask.replace(/\?/g, '');
|
|
14
|
+
const placeholder = propPlaceholder !== null && propPlaceholder !== void 0 ? propPlaceholder : SimplePhonePlaceholder;
|
|
15
|
+
const displayValue = String(value !== null && value !== void 0 ? value : '').replace(/\D/g, '');
|
|
16
|
+
// Transform output value to digits-only (unmasked)
|
|
17
|
+
const handleChange = useCallback((event)=>{
|
|
18
|
+
if (onChange) {
|
|
19
|
+
const digitsOnly = event.target.value.replace(/\D/g, '');
|
|
20
|
+
const unmaskedEvent = {
|
|
21
|
+
...event,
|
|
22
|
+
target: {
|
|
23
|
+
...event.target,
|
|
24
|
+
value: digitsOnly
|
|
25
|
+
},
|
|
26
|
+
currentTarget: {
|
|
27
|
+
...event.currentTarget,
|
|
28
|
+
value: digitsOnly
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
onChange(unmaskedEvent);
|
|
32
|
+
}
|
|
33
|
+
}, [
|
|
34
|
+
onChange
|
|
35
|
+
]);
|
|
36
|
+
if (sip) {
|
|
37
|
+
return /*#__PURE__*/ _jsx(TextField, {
|
|
38
|
+
...restProps,
|
|
39
|
+
value: displayValue,
|
|
40
|
+
onChange: handleChange,
|
|
41
|
+
type: "tel",
|
|
42
|
+
placeholder: placeholder
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
const renderTextField = (inputProps)=>{
|
|
46
|
+
// Exclude 'size' as it conflicts with TextField's size prop type
|
|
47
|
+
const { size: UNUSED_SIZE, ...filteredProps } = inputProps;
|
|
48
|
+
return /*#__PURE__*/ _jsx(TextField, {
|
|
49
|
+
...filteredProps,
|
|
50
|
+
...restProps,
|
|
51
|
+
type: "tel",
|
|
52
|
+
placeholder: placeholder
|
|
53
|
+
});
|
|
54
|
+
};
|
|
55
|
+
return /*#__PURE__*/ _jsx(ReactInputMask, {
|
|
56
|
+
value: displayValue,
|
|
57
|
+
onChange: handleChange,
|
|
58
|
+
mask: mask,
|
|
59
|
+
maskChar: null,
|
|
60
|
+
children: renderTextField
|
|
61
|
+
});
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
//# sourceMappingURL=phone-number-input-a2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/phone-number-input/phone-number-input-a2.tsx"],"sourcesContent":["import { ChangeEvent, FC, useCallback } from 'react';\nimport ReactInputMask from 'react-input-mask';\n\nimport { TextField, TextFieldProps } from '@servicetitan/anvil2';\nimport { Culture, CULTURE_TOKEN } from '@servicetitan/culture';\nimport { useOptionalDependencies } from '@servicetitan/react-ioc';\n\ntype PhoneNumberInputA2Props = TextFieldProps & {\n sip?: boolean;\n culture?: Culture;\n};\n\nexport const PhoneNumberInputA2: FC<PhoneNumberInputA2Props> = props => {\n const {\n value,\n onChange,\n placeholder: propPlaceholder,\n culture: propCulture,\n sip,\n ...restProps\n } = props;\n\n const [injectedCulture] = useOptionalDependencies(CULTURE_TOKEN);\n const culture = propCulture ?? injectedCulture;\n const { SimplePhoneMask = '?9999999999', SimplePhonePlaceholder = '' } =\n culture?.PhoneFormat ?? {};\n\n const mask = SimplePhoneMask.replace(/\\?/g, '');\n const placeholder = propPlaceholder ?? SimplePhonePlaceholder;\n const displayValue = String(value ?? '').replace(/\\D/g, '');\n\n // Transform output value to digits-only (unmasked)\n const handleChange = useCallback(\n (event: ChangeEvent<HTMLInputElement>) => {\n if (onChange) {\n const digitsOnly = event.target.value.replace(/\\D/g, '');\n\n const unmaskedEvent = {\n ...event,\n target: { ...event.target, value: digitsOnly },\n currentTarget: { ...event.currentTarget, value: digitsOnly },\n } as ChangeEvent<HTMLInputElement>;\n\n onChange(unmaskedEvent);\n }\n },\n [onChange]\n );\n\n if (sip) {\n return (\n <TextField\n {...restProps}\n value={displayValue}\n onChange={handleChange}\n type=\"tel\"\n placeholder={placeholder}\n />\n );\n }\n\n const renderTextField = (inputProps: Record<string, unknown>) => {\n // Exclude 'size' as it conflicts with TextField's size prop type\n const { size: UNUSED_SIZE, ...filteredProps } = inputProps;\n return <TextField {...filteredProps} {...restProps} type=\"tel\" placeholder={placeholder} />;\n };\n\n return (\n <ReactInputMask value={displayValue} onChange={handleChange} mask={mask} maskChar={null}>\n {renderTextField as any}\n </ReactInputMask>\n );\n};\n"],"names":["useCallback","ReactInputMask","TextField","CULTURE_TOKEN","useOptionalDependencies","PhoneNumberInputA2","props","value","onChange","placeholder","propPlaceholder","culture","propCulture","sip","restProps","injectedCulture","SimplePhoneMask","SimplePhonePlaceholder","PhoneFormat","mask","replace","displayValue","String","handleChange","event","digitsOnly","target","unmaskedEvent","currentTarget","type","renderTextField","inputProps","size","UNUSED_SIZE","filteredProps","maskChar"],"mappings":";AAAA,SAA0BA,WAAW,QAAQ,QAAQ;AACrD,OAAOC,oBAAoB,mBAAmB;AAE9C,SAASC,SAAS,QAAwB,uBAAuB;AACjE,SAAkBC,aAAa,QAAQ,wBAAwB;AAC/D,SAASC,uBAAuB,QAAQ,0BAA0B;AAOlE,OAAO,MAAMC,qBAAkDC,CAAAA;;IAC3D,MAAM,EACFC,KAAK,EACLC,QAAQ,EACRC,aAAaC,eAAe,EAC5BC,SAASC,WAAW,EACpBC,GAAG,EACH,GAAGC,WACN,GAAGR;IAEJ,MAAM,CAACS,gBAAgB,GAAGX,wBAAwBD;IAClD,MAAMQ,UAAUC,wBAAAA,yBAAAA,cAAeG;IAC/B,MAAM,EAAEC,kBAAkB,aAAa,EAAEC,yBAAyB,EAAE,EAAE,WAClEN,oBAAAA,8BAAAA,QAASO,WAAW,uCAAI,CAAC;IAE7B,MAAMC,OAAOH,gBAAgBI,OAAO,CAAC,OAAO;IAC5C,MAAMX,cAAcC,4BAAAA,6BAAAA,kBAAmBO;IACvC,MAAMI,eAAeC,OAAOf,kBAAAA,mBAAAA,QAAS,IAAIa,OAAO,CAAC,OAAO;IAExD,mDAAmD;IACnD,MAAMG,eAAevB,YACjB,CAACwB;QACG,IAAIhB,UAAU;YACV,MAAMiB,aAAaD,MAAME,MAAM,CAACnB,KAAK,CAACa,OAAO,CAAC,OAAO;YAErD,MAAMO,gBAAgB;gBAClB,GAAGH,KAAK;gBACRE,QAAQ;oBAAE,GAAGF,MAAME,MAAM;oBAAEnB,OAAOkB;gBAAW;gBAC7CG,eAAe;oBAAE,GAAGJ,MAAMI,aAAa;oBAAErB,OAAOkB;gBAAW;YAC/D;YAEAjB,SAASmB;QACb;IACJ,GACA;QAACnB;KAAS;IAGd,IAAIK,KAAK;QACL,qBACI,KAACX;YACI,GAAGY,SAAS;YACbP,OAAOc;YACPb,UAAUe;YACVM,MAAK;YACLpB,aAAaA;;IAGzB;IAEA,MAAMqB,kBAAkB,CAACC;QACrB,iEAAiE;QACjE,MAAM,EAAEC,MAAMC,WAAW,EAAE,GAAGC,eAAe,GAAGH;QAChD,qBAAO,KAAC7B;YAAW,GAAGgC,aAAa;YAAG,GAAGpB,SAAS;YAAEe,MAAK;YAAMpB,aAAaA;;IAChF;IAEA,qBACI,KAACR;QAAeM,OAAOc;QAAcb,UAAUe;QAAcJ,MAAMA;QAAMgB,UAAU;kBAC9EL;;AAGb,EAAE"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@servicetitan/form",
|
|
3
|
-
"version": "38.
|
|
3
|
+
"version": "38.3.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"homepage": "https://docs.st.dev/docs/frontend/form",
|
|
6
6
|
"repository": {
|
|
@@ -17,10 +17,11 @@
|
|
|
17
17
|
],
|
|
18
18
|
"devDependencies": {
|
|
19
19
|
"@progress/kendo-react-dateinputs": "~5.5.0",
|
|
20
|
-
"@servicetitan/
|
|
21
|
-
"@servicetitan/
|
|
20
|
+
"@servicetitan/anvil2": "^2.0.1",
|
|
21
|
+
"@servicetitan/confirm": "^38.3.0",
|
|
22
|
+
"@servicetitan/culture": "^38.3.0",
|
|
22
23
|
"@servicetitan/design-system": "~14.5.1",
|
|
23
|
-
"@servicetitan/form-state": "^38.
|
|
24
|
+
"@servicetitan/form-state": "^38.3.0",
|
|
24
25
|
"@servicetitan/hash-browser-router": "^34.0.1",
|
|
25
26
|
"@servicetitan/react-ioc": "^34.0.1",
|
|
26
27
|
"@servicetitan/tokens": ">=12.2.1",
|
|
@@ -37,12 +38,18 @@
|
|
|
37
38
|
"react": "^18.2.0",
|
|
38
39
|
"resumablejs": "~1.0.2"
|
|
39
40
|
},
|
|
41
|
+
"peerDependenciesMeta": {
|
|
42
|
+
"@servicetitan/anvil2": {
|
|
43
|
+
"optional": true
|
|
44
|
+
}
|
|
45
|
+
},
|
|
40
46
|
"peerDependencies": {
|
|
41
47
|
"@progress/kendo-react-dateinputs": "~5.5.0",
|
|
42
|
-
"@servicetitan/
|
|
43
|
-
"@servicetitan/
|
|
48
|
+
"@servicetitan/anvil2": "^2.0.1",
|
|
49
|
+
"@servicetitan/confirm": "^38.3.0",
|
|
50
|
+
"@servicetitan/culture": "^38.3.0",
|
|
44
51
|
"@servicetitan/design-system": ">=13.2.1",
|
|
45
|
-
"@servicetitan/form-state": "^38.
|
|
52
|
+
"@servicetitan/form-state": "^38.3.0",
|
|
46
53
|
"@servicetitan/react-ioc": ">21.0.0",
|
|
47
54
|
"@servicetitan/tokens": ">=12.2.1",
|
|
48
55
|
"accounting": "~0.4.1",
|
|
@@ -67,5 +74,5 @@
|
|
|
67
74
|
"less": true,
|
|
68
75
|
"webpack": false
|
|
69
76
|
},
|
|
70
|
-
"gitHead": "
|
|
77
|
+
"gitHead": "1792c3dadb5fef82bb6263ade086b9c3b13c86fb"
|
|
71
78
|
}
|
package/src/demo/index.ts
CHANGED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { ChangeEvent, FC, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
import { observer } from 'mobx-react';
|
|
4
|
+
|
|
5
|
+
import { Culture } from '@servicetitan/culture';
|
|
6
|
+
|
|
7
|
+
import { PhoneNumberInputA2 } from '..';
|
|
8
|
+
|
|
9
|
+
type CultureKey = 'nanp' | 'au';
|
|
10
|
+
|
|
11
|
+
const cultures: Record<CultureKey, Culture> = {
|
|
12
|
+
nanp: {
|
|
13
|
+
PhoneFormat: {
|
|
14
|
+
SimplePhoneMask: '(999) 999-9999?',
|
|
15
|
+
SimplePhonePlaceholder: '(___) ___-____',
|
|
16
|
+
},
|
|
17
|
+
} as Culture,
|
|
18
|
+
au: {
|
|
19
|
+
PhoneFormat: {
|
|
20
|
+
SimplePhoneMask: '99 9999 9999',
|
|
21
|
+
SimplePhonePlaceholder: '__ ____ ____',
|
|
22
|
+
},
|
|
23
|
+
} as Culture,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const PhoneNumberInputA2Example: FC = observer(() => {
|
|
27
|
+
const [value, setValue] = useState('');
|
|
28
|
+
const [cultureKey, setCultureKey] = useState<CultureKey>('nanp');
|
|
29
|
+
const [sip, setSip] = useState(false);
|
|
30
|
+
|
|
31
|
+
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
|
|
32
|
+
setValue(e.target.value);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const handleCultureChange = (e: ChangeEvent<HTMLInputElement>) => {
|
|
36
|
+
setCultureKey(e.target.value as CultureKey);
|
|
37
|
+
setValue('');
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<div>
|
|
42
|
+
<fieldset>
|
|
43
|
+
<legend>Region</legend>
|
|
44
|
+
<label>
|
|
45
|
+
<input
|
|
46
|
+
type="radio"
|
|
47
|
+
name="culture"
|
|
48
|
+
value="nanp"
|
|
49
|
+
checked={cultureKey === 'nanp'}
|
|
50
|
+
onChange={handleCultureChange}
|
|
51
|
+
/>
|
|
52
|
+
US/Canada (NANP)
|
|
53
|
+
</label>
|
|
54
|
+
<label style={{ marginLeft: 16 }}>
|
|
55
|
+
<input
|
|
56
|
+
type="radio"
|
|
57
|
+
name="culture"
|
|
58
|
+
value="au"
|
|
59
|
+
checked={cultureKey === 'au'}
|
|
60
|
+
onChange={handleCultureChange}
|
|
61
|
+
/>
|
|
62
|
+
Australia
|
|
63
|
+
</label>
|
|
64
|
+
</fieldset>
|
|
65
|
+
<br />
|
|
66
|
+
<label>
|
|
67
|
+
<input
|
|
68
|
+
type="checkbox"
|
|
69
|
+
checked={sip}
|
|
70
|
+
onChange={e => {
|
|
71
|
+
setSip(e.target.checked);
|
|
72
|
+
setValue('');
|
|
73
|
+
}}
|
|
74
|
+
/>
|
|
75
|
+
SIP
|
|
76
|
+
</label>
|
|
77
|
+
<br />
|
|
78
|
+
<br />
|
|
79
|
+
<PhoneNumberInputA2
|
|
80
|
+
culture={cultures[cultureKey]}
|
|
81
|
+
label="Phone"
|
|
82
|
+
value={value}
|
|
83
|
+
onChange={handleChange}
|
|
84
|
+
sip={sip}
|
|
85
|
+
/>
|
|
86
|
+
<p>Returned value: {value}</p>
|
|
87
|
+
</div>
|
|
88
|
+
);
|
|
89
|
+
});
|
package/src/form.stories.tsx
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
InputDateMaskExample,
|
|
8
8
|
NumberInputExample,
|
|
9
9
|
OrdinalNumberInputExample,
|
|
10
|
+
PhoneNumberInputA2Example,
|
|
10
11
|
PhoneNumberInputExample,
|
|
11
12
|
} from './demo';
|
|
12
13
|
|
|
@@ -32,3 +33,4 @@ export const InputDateMask = () => <InputDateMaskExample />;
|
|
|
32
33
|
export const NumberInput = () => <NumberInputExample />;
|
|
33
34
|
export const OrdinalNumberInput = () => <OrdinalNumberInputExample />;
|
|
34
35
|
export const PhoneNumberInput = () => <PhoneNumberInputExample />;
|
|
36
|
+
export const PhoneNumberInputA2 = () => <PhoneNumberInputA2Example />;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { ChangeEvent, FC, useCallback } from 'react';
|
|
2
|
+
import ReactInputMask from 'react-input-mask';
|
|
3
|
+
|
|
4
|
+
import { TextField, TextFieldProps } from '@servicetitan/anvil2';
|
|
5
|
+
import { Culture, CULTURE_TOKEN } from '@servicetitan/culture';
|
|
6
|
+
import { useOptionalDependencies } from '@servicetitan/react-ioc';
|
|
7
|
+
|
|
8
|
+
type PhoneNumberInputA2Props = TextFieldProps & {
|
|
9
|
+
sip?: boolean;
|
|
10
|
+
culture?: Culture;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const PhoneNumberInputA2: FC<PhoneNumberInputA2Props> = props => {
|
|
14
|
+
const {
|
|
15
|
+
value,
|
|
16
|
+
onChange,
|
|
17
|
+
placeholder: propPlaceholder,
|
|
18
|
+
culture: propCulture,
|
|
19
|
+
sip,
|
|
20
|
+
...restProps
|
|
21
|
+
} = props;
|
|
22
|
+
|
|
23
|
+
const [injectedCulture] = useOptionalDependencies(CULTURE_TOKEN);
|
|
24
|
+
const culture = propCulture ?? injectedCulture;
|
|
25
|
+
const { SimplePhoneMask = '?9999999999', SimplePhonePlaceholder = '' } =
|
|
26
|
+
culture?.PhoneFormat ?? {};
|
|
27
|
+
|
|
28
|
+
const mask = SimplePhoneMask.replace(/\?/g, '');
|
|
29
|
+
const placeholder = propPlaceholder ?? SimplePhonePlaceholder;
|
|
30
|
+
const displayValue = String(value ?? '').replace(/\D/g, '');
|
|
31
|
+
|
|
32
|
+
// Transform output value to digits-only (unmasked)
|
|
33
|
+
const handleChange = useCallback(
|
|
34
|
+
(event: ChangeEvent<HTMLInputElement>) => {
|
|
35
|
+
if (onChange) {
|
|
36
|
+
const digitsOnly = event.target.value.replace(/\D/g, '');
|
|
37
|
+
|
|
38
|
+
const unmaskedEvent = {
|
|
39
|
+
...event,
|
|
40
|
+
target: { ...event.target, value: digitsOnly },
|
|
41
|
+
currentTarget: { ...event.currentTarget, value: digitsOnly },
|
|
42
|
+
} as ChangeEvent<HTMLInputElement>;
|
|
43
|
+
|
|
44
|
+
onChange(unmaskedEvent);
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
[onChange]
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
if (sip) {
|
|
51
|
+
return (
|
|
52
|
+
<TextField
|
|
53
|
+
{...restProps}
|
|
54
|
+
value={displayValue}
|
|
55
|
+
onChange={handleChange}
|
|
56
|
+
type="tel"
|
|
57
|
+
placeholder={placeholder}
|
|
58
|
+
/>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const renderTextField = (inputProps: Record<string, unknown>) => {
|
|
63
|
+
// Exclude 'size' as it conflicts with TextField's size prop type
|
|
64
|
+
const { size: UNUSED_SIZE, ...filteredProps } = inputProps;
|
|
65
|
+
return <TextField {...filteredProps} {...restProps} type="tel" placeholder={placeholder} />;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<ReactInputMask value={displayValue} onChange={handleChange} mask={mask} maskChar={null}>
|
|
70
|
+
{renderTextField as any}
|
|
71
|
+
</ReactInputMask>
|
|
72
|
+
);
|
|
73
|
+
};
|