playbook_ui 12.5.0 → 12.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/_playbook.scss +2 -0
  3. data/app/pb_kits/playbook/data/menu.yml +2 -1
  4. data/app/pb_kits/playbook/index.js +1 -0
  5. data/app/pb_kits/playbook/pb_button/_button_mixins.scss +2 -2
  6. data/app/pb_kits/playbook/pb_circle_icon_button/_circle_icon_button.scss +1 -1
  7. data/app/pb_kits/playbook/pb_filter/Filter/CurrentFilters.tsx +72 -0
  8. data/app/pb_kits/playbook/pb_filter/Filter/{FilterBackground.jsx → FilterBackground.tsx} +12 -14
  9. data/app/pb_kits/playbook/pb_filter/Filter/{FilterDouble.jsx → FilterDouble.tsx} +7 -8
  10. data/app/pb_kits/playbook/pb_filter/Filter/{FilterSingle.jsx → FilterSingle.tsx} +25 -25
  11. data/app/pb_kits/playbook/pb_filter/Filter/{FiltersPopover.jsx → FiltersPopover.tsx} +13 -11
  12. data/app/pb_kits/playbook/pb_filter/Filter/{ResultsCount.jsx → ResultsCount.tsx} +39 -14
  13. data/app/pb_kits/playbook/pb_filter/Filter/{SortMenu.jsx → SortMenu.tsx} +6 -6
  14. data/app/pb_kits/playbook/pb_filter/Filter/{index.jsx → index.tsx} +17 -10
  15. data/app/pb_kits/playbook/pb_filter/{_filter.jsx → _filter.tsx} +0 -2
  16. data/app/pb_kits/playbook/pb_list/_list.tsx +2 -2
  17. data/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.scss +86 -0
  18. data/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.tsx +81 -0
  19. data/app/pb_kits/playbook/pb_multi_level_select/_multi_select_helper.tsx +30 -0
  20. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_default.jsx +86 -0
  21. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_default.md +3 -0
  22. data/app/pb_kits/playbook/pb_multi_level_select/docs/example.yml +6 -0
  23. data/app/pb_kits/playbook/pb_multi_level_select/docs/index.js +1 -0
  24. data/app/pb_kits/playbook/pb_multi_level_select/helper_functions.ts +60 -0
  25. data/app/pb_kits/playbook/pb_multi_level_select/multi_level_select.test.jsx +40 -0
  26. data/app/pb_kits/playbook/pb_person_contact/{_person_contact.jsx → _person_contact.tsx} +19 -22
  27. data/app/pb_kits/playbook/pb_person_contact/person_contact.test.js +112 -0
  28. data/app/pb_kits/playbook/pb_phone_number_input/_phone_number_input.tsx +61 -47
  29. data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_initial_country.html.erb +3 -0
  30. data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_only_countries.html.erb +4 -0
  31. data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_preferred_countries.html.erb +4 -0
  32. data/app/pb_kits/playbook/pb_phone_number_input/docs/example.yml +4 -1
  33. data/app/pb_kits/playbook/pb_phone_number_input/phone_number_input.html.erb +1 -15
  34. data/app/pb_kits/playbook/pb_popover/_popover.tsx +33 -32
  35. data/app/pb_kits/playbook/playbook-doc.js +2 -0
  36. data/app/pb_kits/playbook/tokens/_animation-curves.scss +30 -30
  37. data/app/pb_kits/playbook/tokens/_border_radius.scss +15 -16
  38. data/app/pb_kits/playbook/tokens/_colors.scss +3 -1
  39. data/app/pb_kits/playbook/tokens/_display.scss +6 -6
  40. data/app/pb_kits/playbook/tokens/_line_height.scss +7 -7
  41. data/app/pb_kits/playbook/tokens/_opacity.scss +10 -10
  42. data/app/pb_kits/playbook/tokens/_positioning.scss +11 -11
  43. data/app/pb_kits/playbook/tokens/_screen_sizes.scss +10 -10
  44. data/app/pb_kits/playbook/tokens/_shadows.scss +4 -4
  45. data/app/pb_kits/playbook/tokens/_spacing.scss +6 -6
  46. data/app/pb_kits/playbook/tokens/_transition.scss +3 -3
  47. data/app/pb_kits/playbook/tokens/_typography.scss +35 -46
  48. data/lib/playbook/version.rb +2 -2
  49. metadata +25 -12
  50. data/app/pb_kits/playbook/pb_filter/Filter/CurrentFilters.jsx +0 -76
@@ -0,0 +1,81 @@
1
+ import React, { useState, useEffect } from "react";
2
+ import classnames from "classnames";
3
+ import { buildAriaProps, buildCss, buildDataProps } from "../utilities/props";
4
+ import { globalProps } from "../utilities/globalProps";
5
+ import { findItemById, checkIt, unCheckIt } from "./helper_functions";
6
+ import MultiSelectHelper from "./_multi_select_helper";
7
+
8
+ type MultiLevelSelectProps = {
9
+ aria?: { [key: string]: string };
10
+ className?: string;
11
+ data?: { [key: string]: string };
12
+ id?: string;
13
+ treeData?: { [key: string]: string }[];
14
+ onChange?: any;
15
+ onSelect?: (SelectedNodes: { [key: string]: any }) => void;
16
+ };
17
+
18
+ const MultiLevelSelect = (props: MultiLevelSelectProps) => {
19
+ const { aria = {}, className, data = {}, id, treeData, onSelect } = props;
20
+
21
+ const ariaProps = buildAriaProps(aria);
22
+ const dataProps = buildDataProps(data);
23
+ const classes = classnames(
24
+ buildCss("pb_multi_level_select"),
25
+ globalProps(props),
26
+ className
27
+ );
28
+
29
+ const [formattedData, setFormattedData] = useState(treeData);
30
+ const [selectedItems, setSelectedItems] = useState([]);
31
+
32
+ const onChange = (currentNode: { [key: string]: any }) => {
33
+ const updatedData = formattedData.map((item: any) => {
34
+ if (item.id === currentNode._id) {
35
+ if (currentNode.checked) {
36
+ checkIt(item, selectedItems, setSelectedItems);
37
+ } else {
38
+ unCheckIt(item, selectedItems, setSelectedItems);
39
+ }
40
+ } else if (item.children) {
41
+ const foundItem = findItemById(item.children, currentNode._id);
42
+ if (foundItem) {
43
+ if (currentNode.checked) {
44
+ checkIt(foundItem, selectedItems, setSelectedItems);
45
+ } else {
46
+ unCheckIt(foundItem, selectedItems, setSelectedItems);
47
+ }
48
+ }
49
+ }
50
+
51
+ return item;
52
+ });
53
+
54
+ setFormattedData(updatedData);
55
+ };
56
+
57
+ useEffect(() => {
58
+ const selected = selectedItems.filter(
59
+ (item: { [key: string]: any }) => item.checked
60
+ );
61
+ //filter to remove duplicate items
62
+ const uniqueSelected = selected.filter(
63
+ (obj, index, self) => index === self.findIndex((t) => t.id === obj.id)
64
+ );
65
+ onSelect(uniqueSelected);
66
+ }, [selectedItems]);
67
+
68
+ return (
69
+ <div {...ariaProps} {...dataProps} className={classes} id={id}>
70
+ <MultiSelectHelper
71
+ treeData={formattedData}
72
+ id={id}
73
+ onChange={onChange}
74
+ onSelect={onSelect}
75
+ {...props}
76
+ />
77
+ </div>
78
+ );
79
+ };
80
+
81
+ export default MultiLevelSelect;
@@ -0,0 +1,30 @@
1
+ import React from "react"
2
+ import DropdownTreeSelect from "react-dropdown-tree-select"
3
+ import "react-dropdown-tree-select/dist/styles.css"
4
+
5
+ type HelperProps = {
6
+ id?: string
7
+ treeData?: { [key: string]: string }[]
8
+ onChange?: () => {}
9
+
10
+ }
11
+
12
+ const MultiSelectHelper = (props: HelperProps) => {
13
+ const { id, treeData, onChange } = props
14
+
15
+
16
+ return (
17
+ <DropdownTreeSelect
18
+ data={treeData}
19
+ id={id}
20
+ keepOpenOnSelect
21
+ keepTreeOnSearch
22
+ keepChildrenOnSearch
23
+ onChange={onChange}
24
+ texts={{ placeholder: "Select..." }}
25
+ mode='hierarchical'
26
+ />
27
+ )
28
+ }
29
+
30
+ export default MultiSelectHelper
@@ -0,0 +1,86 @@
1
+ import React from "react";
2
+ import MultiLevelSelect from "../_multi_level_select";
3
+
4
+ const treeData = [
5
+ {
6
+ label: "Power Home Remodeling",
7
+ value: "Power Home Remodeling",
8
+ id: "powerhome1",
9
+ expanded: true,
10
+ children: [
11
+ {
12
+ label: "People",
13
+ value: "People",
14
+ id: "people1",
15
+ children: [
16
+ {
17
+ label: "Talent Acquisition",
18
+ value: "Talent Acquisition",
19
+ id: "talent1",
20
+ },
21
+ {
22
+ label: "Business Affairs",
23
+ value: "Business Affairs",
24
+ id: "business1",
25
+ children: [
26
+ {
27
+ label: "Initiatives",
28
+ value: "Initiatives",
29
+ id: "initiative1",
30
+ },
31
+ {
32
+ label: "Learning & Development",
33
+ value: "Learning & Development",
34
+ id: "development1",
35
+ },
36
+ ],
37
+ },
38
+ {
39
+ label: "People Experience",
40
+ value: "People Experience",
41
+ id: "experience1",
42
+ },
43
+ ],
44
+ },
45
+ {
46
+ label: "Contact Center",
47
+ value: "Contact Center",
48
+ id: "contact1",
49
+ children: [
50
+ {
51
+ label: "Appointment Management",
52
+ value: "Appointment Management",
53
+ id: "appointment1",
54
+ },
55
+ {
56
+ label: "Customer Service",
57
+ value: "Customer Service",
58
+ id: "customer1",
59
+ },
60
+ {
61
+ label: "Energy",
62
+ value: "Energy",
63
+ id: "energy1",
64
+ },
65
+ ],
66
+ },
67
+ ],
68
+ },
69
+ ];
70
+
71
+ const MultiLevelSelectDefault = (props) => {
72
+ return (
73
+ <div>
74
+ <MultiLevelSelect
75
+ id="multiselect-default"
76
+ onSelect={(selectedNodes) =>
77
+ console.log("Selected Items", selectedNodes)
78
+ }
79
+ treeData={treeData}
80
+ {...props}
81
+ />
82
+ </div>
83
+ );
84
+ };
85
+
86
+ export default MultiLevelSelectDefault;
@@ -0,0 +1,3 @@
1
+ The MultiLevelSelect kit renders a multi leveled select dropdown based on data from the user. `treeData` is a required prop that is expected to contain the data in the form of an array of objects. See code snippet for an example data array.
2
+
3
+ The `onSelect` prop returns an array of all checked items, irrespective of whether it is a parent, child or grandchild. Open the console on this example and check and uncheck checkboxes to see this is action!
@@ -0,0 +1,6 @@
1
+ examples:
2
+
3
+
4
+ react:
5
+ - multi_level_select_default: Default
6
+
@@ -0,0 +1 @@
1
+ export { default as MultiLevelSelectDefault } from './_multi_level_select_default.jsx'
@@ -0,0 +1,60 @@
1
+ export const findItemById = (
2
+ items: { [key: string]: any }[],
3
+ id: string
4
+ ): any => {
5
+ for (const item of items) {
6
+ if (item.id === id) {
7
+ return item;
8
+ }
9
+ if (item.children) {
10
+ const found = findItemById(item.children, id);
11
+ if (found) {
12
+ return found;
13
+ }
14
+ }
15
+ }
16
+ return null;
17
+ };
18
+
19
+ export const checkIt = (
20
+ foundItem: { [key: string]: any },
21
+ selectedItems: any[],
22
+ setSelectedItems: Function
23
+ ) => {
24
+ if (!foundItem) {
25
+ return;
26
+ }
27
+
28
+ foundItem.checked = true;
29
+ foundItem.expanded = true;
30
+ selectedItems.push(foundItem);
31
+
32
+ if (foundItem.children) {
33
+ foundItem.children.map((x: any) => {
34
+ checkIt(x, selectedItems, setSelectedItems);
35
+ });
36
+ }
37
+
38
+ setSelectedItems([...selectedItems]);
39
+ };
40
+
41
+ export const unCheckIt = (
42
+ foundItem: { [key: string]: any },
43
+ selectedItems: any,
44
+ setSelectedItems: any
45
+ ) => {
46
+ if (!foundItem) {
47
+ return;
48
+ }
49
+
50
+ foundItem.checked = false;
51
+ const newSelectedItems = selectedItems.filter(
52
+ (item: any) => item.id !== foundItem.id
53
+ );
54
+ if (foundItem.children) {
55
+ foundItem.children.map((x: any) => {
56
+ unCheckIt(x, selectedItems, setSelectedItems);
57
+ });
58
+ }
59
+ setSelectedItems([...newSelectedItems]);
60
+ };
@@ -0,0 +1,40 @@
1
+ import React from 'react'
2
+ import { render, screen } from '../utilities/test-utils'
3
+
4
+ import { MultiLevelSelect } from '../'
5
+
6
+ const treeData = {
7
+ label: 'search me',
8
+ value: 'searchme',
9
+ id:'default1',
10
+ children: [
11
+ {
12
+ label: 'search me too',
13
+ value: 'searchmetoo',
14
+ id:'default2',
15
+ children: [
16
+ {
17
+ label: 'No one can get me',
18
+ value: 'anonymous',
19
+ id:'default2',
20
+ },
21
+ ],
22
+ },
23
+ ],
24
+ }
25
+
26
+ const testId = "multiselect-test"
27
+ test('should render custom class', () => {
28
+ render(
29
+ <MultiLevelSelect
30
+ className='custom-class'
31
+ data={{ testid: testId}}
32
+ onSelect={()=> console.log("hello")}
33
+ treeData={treeData}
34
+ />
35
+ )
36
+
37
+ const kit = screen.getByTestId(testId)
38
+ expect(kit).toHaveClass('custom-class')
39
+ })
40
+
@@ -1,5 +1,3 @@
1
- /* @flow */
2
-
3
1
  import React from 'react'
4
2
  import classnames from 'classnames'
5
3
 
@@ -17,14 +15,13 @@ type ContactItem = {
17
15
  }
18
16
 
19
17
  type PersonContactProps = {
20
- aria?: object,
21
- className?: string | array<string>,
22
- dark?: boolean,
18
+ aria?: { [key: string]: string },
19
+ className?: string | string[],
23
20
  data?: object,
24
21
  firstName: string,
25
22
  id?: string,
26
23
  lastName: string,
27
- contacts?: array<ContactItem>,
24
+ contacts?: ContactItem[],
28
25
  }
29
26
 
30
27
  const PersonContact = (props: PersonContactProps) => {
@@ -60,34 +57,34 @@ const PersonContact = (props: PersonContactProps) => {
60
57
 
61
58
  return (
62
59
  <div
63
- {...ariaProps}
64
- {...dataProps}
65
- className={classes}
66
- id={id}
60
+ {...ariaProps}
61
+ {...dataProps}
62
+ className={classes}
63
+ id={id}
67
64
  >
68
65
  <Person
69
- firstName={firstName}
70
- lastName={lastName}
66
+ firstName={firstName}
67
+ lastName={lastName}
71
68
  />
72
69
  {validContacts().map((contactObject, index) => (
73
70
  <Contact
74
- contactDetail={contactObject.contactDetail}
75
- contactType={contactObject.contactType}
76
- contactValue={contactObject.contactValue}
77
- key={`valid-contact-${index}`}
71
+ contactDetail={contactObject.contactDetail}
72
+ contactType={contactObject.contactType}
73
+ contactValue={contactObject.contactValue}
74
+ key={`valid-contact-${index}`}
78
75
  />
79
76
  ))}
80
77
  {wrongContacts().map((contactObject, index) => (
81
78
  <div key={`wrong-contact-caption-wrapper-${index}`}>
82
79
  <Caption
83
- className="wrong_numbers"
84
- key={`wrong-contact-caption-${index}`}
85
- text="wrong number"
80
+ className="wrong_numbers"
81
+ key={`wrong-contact-caption-${index}`}
82
+ text="wrong number"
86
83
  />
87
84
  <Contact
88
- contactType={contactObject.contactType}
89
- contactValue={contactObject.contactValue}
90
- key={`wrong-contact-${index}`}
85
+ contactType={contactObject.contactType}
86
+ contactValue={contactObject.contactValue}
87
+ key={`wrong-contact-${index}`}
91
88
  />
92
89
  </div>
93
90
  ))}
@@ -0,0 +1,112 @@
1
+ import React from 'react'
2
+ import { render, screen } from '../utilities/test-utils'
3
+ import PersonContact from './_person_contact'
4
+
5
+ const testId = 'personContact'
6
+ const multipleTestId = 'personContactMultiple'
7
+
8
+ const PersonContactTest = (props) => {
9
+ return (
10
+ <>
11
+ <PersonContact
12
+ aria={{ label: testId }}
13
+ className={'custom-class'}
14
+ contacts={[
15
+ {
16
+ contactType: 'email',
17
+ contactValue: 'email@example.com',
18
+ },
19
+ {
20
+ contactValue: '5555555555',
21
+ contactDetail: 'Home',
22
+ },
23
+ {
24
+ contactType: 'work',
25
+ contactValue: '3245627482',
26
+ contactDetail: 'Work',
27
+ },
28
+ ]}
29
+ data={{ testid: testId }}
30
+ firstName="Jose"
31
+ id={testId}
32
+ lastName="da Silva"
33
+ {...props}
34
+ />
35
+ <PersonContact
36
+ contacts={[
37
+ {
38
+ contactValue: '5555555555',
39
+ contactType: 'wrong-phone',
40
+ },
41
+ ]}
42
+ data={{ testid: multipleTestId }}
43
+ firstName="Brenda"
44
+ lastName="Walters"
45
+ {...props}
46
+ />
47
+ </>
48
+ )
49
+ }
50
+
51
+ test('should render custom class and data', () => {
52
+ render(<PersonContactTest />)
53
+
54
+ const kit = screen.getByTestId(testId)
55
+ expect(kit).toHaveClass('custom-class')
56
+ })
57
+
58
+ test('should render id', () => {
59
+ render(<PersonContactTest />)
60
+
61
+ const kit = screen.getByTestId(testId)
62
+ expect(kit).toHaveProperty('id', testId)
63
+ })
64
+
65
+ test('should render aria-label', () => {
66
+ render(<PersonContactTest />)
67
+
68
+ const kit = screen.getByTestId(testId)
69
+ expect(kit).toHaveAttribute('aria-label', testId)
70
+ })
71
+
72
+ test('should render firstName', () => {
73
+ render(<PersonContactTest />)
74
+
75
+ const kit = screen.getByTestId(testId)
76
+ expect(kit).toHaveTextContent('Jose')
77
+ })
78
+
79
+ test('should render lastName', () => {
80
+ render(<PersonContactTest />)
81
+
82
+ const kit = screen.getByTestId(testId)
83
+ expect(kit).toHaveTextContent('da Silva')
84
+ })
85
+
86
+ test('should render contact value', () => {
87
+ render(<PersonContactTest />)
88
+
89
+ const kit = screen.getByTestId(testId)
90
+ expect(kit).toHaveTextContent('(555) 555-5555')
91
+ })
92
+
93
+ test('should render contact detail', () => {
94
+ render(<PersonContactTest />)
95
+
96
+ const kit = screen.getByTestId(testId)
97
+ expect(kit).toHaveTextContent('Home')
98
+ })
99
+
100
+ test('should render multiple contacts', () => {
101
+ render(<PersonContactTest />)
102
+
103
+ const kit = screen.getByTestId(multipleTestId)
104
+ expect(kit).toHaveTextContent('Brenda Walters')
105
+ })
106
+
107
+ test('should render wrong number', () => {
108
+ render(<PersonContactTest />)
109
+
110
+ const kit = screen.getByTestId(multipleTestId)
111
+ expect(kit).toHaveTextContent('wrong number')
112
+ })
@@ -1,32 +1,32 @@
1
1
  /* @flow */
2
- import React, { useEffect, useRef, useState } from 'react'
3
- import classnames from 'classnames'
4
- import { buildAriaProps, buildCss, buildDataProps } from '../utilities/props'
5
- import { globalProps } from '../utilities/globalProps'
6
- import intlTelInput from 'intl-tel-input'
7
- import 'intl-tel-input/build/css/intlTelInput.css'
8
- import TextInput from '../pb_text_input/_text_input'
2
+ import React, { useEffect, useRef, useState } from "react"
3
+ import classnames from "classnames"
4
+ import { buildAriaProps, buildCss, buildDataProps } from "../utilities/props"
5
+ import { globalProps } from "../utilities/globalProps"
6
+ import intlTelInput from "intl-tel-input"
7
+ import "intl-tel-input/build/css/intlTelInput.css"
8
+ import TextInput from "../pb_text_input/_text_input"
9
9
 
10
10
  declare global {
11
11
  interface Window {
12
- intlTelInputGlobals: any,
12
+ intlTelInputGlobals: any
13
13
  }
14
14
  }
15
15
 
16
16
  type PhoneNumberInputProps = {
17
- aria?: { [key: string]: string },
18
- className?: string,
19
- data?: { [key: string]: string },
20
- disabled?: boolean,
21
- id?: string,
22
- initialCountry?: string,
23
- isValid?: (valid: boolean) => void,
24
- label?: string,
25
- name?: string,
26
- onChange?: (e: React.FormEvent<HTMLInputElement>) => void,
27
- onlyCountries: string[],
28
- preferredCountries?: string[],
29
- value?: string,
17
+ aria?: { [key: string]: string }
18
+ className?: string
19
+ data?: { [key: string]: string }
20
+ disabled?: boolean
21
+ id?: string
22
+ initialCountry?: string
23
+ isValid?: (valid: boolean) => void
24
+ label?: string
25
+ name?: string
26
+ onChange?: (e: React.FormEvent<HTMLInputElement>) => void
27
+ onlyCountries: string[]
28
+ preferredCountries?: string[]
29
+ value?: string
30
30
  }
31
31
 
32
32
  enum ValidationError {
@@ -35,17 +35,20 @@ enum ValidationError {
35
35
  }
36
36
 
37
37
  const formatToGlobalCountryName = (countryName: string) => {
38
- return countryName.split('(')[0].trim()
38
+ return countryName.split("(")[0].trim()
39
39
  }
40
40
 
41
41
  const formatAllCountries = () => {
42
42
  let countryData = window.intlTelInputGlobals.getCountryData()
43
+
43
44
  for (let i = 0; i < countryData.length; i++) {
44
45
  let country = countryData[i]
45
46
  country.name = formatToGlobalCountryName(country.name)
46
47
  }
47
48
  }
48
49
 
50
+ formatAllCountries()
51
+
49
52
  const containOnlyNumbers = (value: string) => {
50
53
  return /^(\++)*(\d+)$/.test(value)
51
54
  }
@@ -56,25 +59,33 @@ const PhoneNumberInput = (props: PhoneNumberInputProps) => {
56
59
  className,
57
60
  data = {},
58
61
  disabled = false,
59
- id = '',
60
- initialCountry = '',
61
- isValid = () => {void 0 },
62
- label = '',
63
- name = '',
64
- onChange = () => { void 0 },
62
+ id = "",
63
+ initialCountry = "",
64
+ isValid = () => {
65
+ void 0
66
+ },
67
+ label = "",
68
+ name = "",
69
+ onChange = () => {
70
+ void 0
71
+ },
65
72
  onlyCountries = [],
66
73
  preferredCountries = [],
67
- value = '',
74
+ value = "",
68
75
  } = props
69
76
 
70
77
  const ariaProps = buildAriaProps(aria)
71
78
  const dataProps = buildDataProps(data)
72
- const classes = classnames(buildCss('pb_phone_number_input'), globalProps(props), className)
79
+ const classes = classnames(
80
+ buildCss("pb_phone_number_input"),
81
+ globalProps(props),
82
+ className
83
+ )
73
84
 
74
85
  const inputRef = useRef<HTMLInputElement>()
75
86
  const [inputValue, setInputValue] = useState(value)
76
87
  const [itiInit, setItiInit] = useState<any>()
77
- const [error, setError] = useState('')
88
+ const [error, setError] = useState("")
78
89
 
79
90
  const validateTooLongNumber = (itiInit: any) => {
80
91
  const error = itiInit.getValidationError()
@@ -83,7 +94,7 @@ const PhoneNumberInput = (props: PhoneNumberInputProps) => {
83
94
  const countryName = itiInit.getSelectedCountryData().name
84
95
  setError(`Invalid ${countryName} phone number (too long)`)
85
96
  } else {
86
- setError('')
97
+ setError("")
87
98
  }
88
99
  }
89
100
 
@@ -98,7 +109,7 @@ const PhoneNumberInput = (props: PhoneNumberInputProps) => {
98
109
 
99
110
  const validateOnlyNumbers = () => {
100
111
  if (inputValue && !containOnlyNumbers(inputValue)) {
101
- setError('Invalid phone number. Enter numbers only.')
112
+ setError("Invalid phone number. Enter numbers only.")
102
113
  }
103
114
  }
104
115
 
@@ -114,29 +125,32 @@ const PhoneNumberInput = (props: PhoneNumberInputProps) => {
114
125
  isValid(itiInit.isValidNumber())
115
126
  }
116
127
 
128
+ // Separating Concerns as React Docs Recommend
129
+ // This also Fixes things for our react_component rendering on the Rails Side
117
130
  useEffect(() => {
118
131
  formatAllCountries()
132
+ }, [])
119
133
 
134
+ useEffect(() => {
120
135
  const telInputInit = new intlTelInput(inputRef.current, {
121
- utilsScript: 'https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.19/js/utils.js',
122
- separateDialCode: true,
123
- preferredCountries,
124
- allowDropdown: !disabled,
125
- initialCountry,
126
- onlyCountries,
127
- }
136
+ utilsScript:
137
+ "https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.19/js/utils.js",
138
+ separateDialCode: true,
139
+ preferredCountries,
140
+ allowDropdown: !disabled,
141
+ initialCountry,
142
+ onlyCountries,
143
+ })
144
+
145
+ inputRef.current.addEventListener("countrychange", () =>
146
+ validateTooLongNumber(telInputInit)
128
147
  )
129
-
130
- inputRef.current.addEventListener("countrychange", () => validateTooLongNumber(telInputInit))
148
+
131
149
  setItiInit(telInputInit)
132
150
  }, [])
133
151
 
134
152
  return (
135
- <div
136
- {...ariaProps}
137
- {...dataProps}
138
- className={classes}
139
- >
153
+ <div {...ariaProps} {...dataProps} className={classes}>
140
154
  <TextInput
141
155
  disabled={disabled}
142
156
  error={error}
@@ -0,0 +1,3 @@
1
+ <%= pb_rails("phone_number_input", props: {
2
+ initial_country: "br"
3
+ }) %>