playbook_ui 12.5.0 → 12.6.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.
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
+ }) %>