@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.
@@ -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
@@ -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"}
@@ -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
 
@@ -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,3 @@
1
+ import { FC } from 'react';
2
+ export declare const PhoneNumberInputA2Example: FC;
3
+ //# sourceMappingURL=phone-number-input-a2.d.ts.map
@@ -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"}
@@ -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":";;yBAegB,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"}
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,2 +1,3 @@
1
1
  export * from './phone-number-input';
2
+ export * from './phone-number-input-a2';
2
3
  //# sourceMappingURL=index.d.ts.map
@@ -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,3 +1,4 @@
1
1
  export * from './phone-number-input';
2
+ export * from './phone-number-input-a2';
2
3
 
3
4
  //# sourceMappingURL=index.js.map
@@ -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.2.0",
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/confirm": "^38.2.0",
21
- "@servicetitan/culture": "^38.2.0",
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.2.0",
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/confirm": "^38.2.0",
43
- "@servicetitan/culture": "^38.2.0",
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.2.0",
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": "b013c9f39c05c44f888a5bca5ff6aadb89cd7a6f"
77
+ "gitHead": "1792c3dadb5fef82bb6263ade086b9c3b13c86fb"
71
78
  }
package/src/demo/index.ts CHANGED
@@ -3,5 +3,6 @@ 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';
@@ -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
+ });
@@ -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 />;
@@ -1 +1,2 @@
1
1
  export * from './phone-number-input';
2
+ export * from './phone-number-input-a2';
@@ -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
+ };