playbook_ui 12.26.1.pre.alpha.PLAY603datepickerquickpickinputpresetdropdown831 → 12.26.1.pre.alpha.PLAY860PhoneNumInputOptions836

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 (38) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/pb_date_picker/_date_picker.scss +0 -26
  3. data/app/pb_kits/playbook/pb_date_picker/_date_picker.tsx +95 -102
  4. data/app/pb_kits/playbook/pb_date_picker/date_picker.html.erb +2 -18
  5. data/app/pb_kits/playbook/pb_date_picker/date_picker.rb +4 -15
  6. data/app/pb_kits/playbook/pb_date_picker/date_picker.test.js +1 -84
  7. data/app/pb_kits/playbook/pb_date_picker/date_picker_helper.ts +4 -38
  8. data/app/pb_kits/playbook/pb_date_picker/docs/example.yml +0 -4
  9. data/app/pb_kits/playbook/pb_date_picker/docs/index.js +1 -3
  10. data/app/pb_kits/playbook/pb_date_picker/sass_partials/_calendar_input_icon.scss +2 -3
  11. data/app/pb_kits/playbook/pb_nav/_item.tsx +1 -1
  12. data/app/pb_kits/playbook/pb_nav/_subtle_mixin.scss +1 -1
  13. data/app/pb_kits/playbook/pb_phone_number_input/_phone_number_input.tsx +132 -45
  14. data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_access_input_element.jsx +26 -0
  15. data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_access_input_element.md +3 -0
  16. data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_clear_field.jsx +30 -0
  17. data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_clear_field.md +3 -0
  18. data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_validation.html.erb +14 -0
  19. data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_validation.jsx +60 -0
  20. data/app/pb_kits/playbook/pb_phone_number_input/docs/example.yml +5 -1
  21. data/app/pb_kits/playbook/pb_phone_number_input/docs/index.js +3 -0
  22. data/app/pb_kits/playbook/pb_phone_number_input/phone_number_input.rb +6 -0
  23. data/app/pb_kits/playbook/pb_phone_number_input/phone_number_input.test.js +110 -62
  24. data/app/pb_kits/playbook/utilities/object.ts +3 -0
  25. data/dist/playbook-rails.js +7 -279
  26. data/lib/playbook/forms/builder/intl_telephone_field.rb +12 -0
  27. data/lib/playbook/forms/builder.rb +1 -0
  28. data/lib/playbook/version.rb +1 -1
  29. metadata +10 -11
  30. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_quick_pick_rails.html.erb +0 -12
  31. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_quick_pick_rails.md +0 -3
  32. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_quick_pick_range_limit.html.erb +0 -12
  33. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_quick_pick_range_limit.jsx +0 -18
  34. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_quick_pick_range_limit.md +0 -1
  35. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_quick_pick_react.jsx +0 -17
  36. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_quick_pick_react.md +0 -1
  37. data/app/pb_kits/playbook/pb_date_picker/plugins/quickPick.tsx +0 -168
  38. data/app/pb_kits/playbook/pb_date_picker/sass_partials/_quick_pick_styles.scss +0 -75
@@ -1,12 +1,17 @@
1
- import React, { useEffect, useRef, useState } from 'react'
1
+ import React, { forwardRef, useEffect, useRef, useState, useImperativeHandle } from 'react'
2
2
  import classnames from 'classnames'
3
- import { buildAriaProps, buildCss, buildDataProps } from '../utilities/props'
4
- import { globalProps } from '../utilities/globalProps'
3
+
5
4
  import intlTelInput from 'intl-tel-input'
6
5
  import 'intl-tel-input/build/css/intlTelInput.css'
7
- import TextInput from '../pb_text_input/_text_input'
8
6
  import 'intl-tel-input/build/js/utils.js'
9
7
 
8
+ import { buildAriaProps, buildCss, buildDataProps } from '../utilities/props'
9
+ import { globalProps } from '../utilities/globalProps'
10
+
11
+ import TextInput from '../pb_text_input/_text_input'
12
+ import { Callback } from '../types'
13
+ import { isEmpty } from '../utilities/object'
14
+
10
15
  declare global {
11
16
  interface Window {
12
17
  intlTelInputGlobals: any
@@ -19,20 +24,25 @@ type PhoneNumberInputProps = {
19
24
  dark?: boolean,
20
25
  data?: { [key: string]: string },
21
26
  disabled?: boolean,
27
+ error?: string,
22
28
  id?: string,
23
29
  initialCountry?: string,
24
30
  isValid?: (valid: boolean) => void,
25
31
  label?: string,
26
32
  name?: string,
27
33
  onChange?: (e: React.FormEvent<HTMLInputElement>) => void,
34
+ onValidate?: Callback<boolean, void>,
28
35
  onlyCountries: string[],
29
36
  preferredCountries?: string[],
37
+ required?: boolean,
30
38
  value?: string,
31
39
  }
32
40
 
33
41
  enum ValidationError {
34
42
  TooShort = 2,
35
43
  TooLong = 3,
44
+ MissingAreaCode = 4,
45
+ SomethingWentWrong = -99
36
46
  }
37
47
 
38
48
  const formatToGlobalCountryName = (countryName: string) => {
@@ -40,10 +50,10 @@ const formatToGlobalCountryName = (countryName: string) => {
40
50
  }
41
51
 
42
52
  const formatAllCountries = () => {
43
- let countryData = window.intlTelInputGlobals.getCountryData()
53
+ const countryData = window.intlTelInputGlobals.getCountryData()
44
54
 
45
55
  for (let i = 0; i < countryData.length; i++) {
46
- let country = countryData[i]
56
+ const country = countryData[i]
47
57
  country.name = formatToGlobalCountryName(country.name)
48
58
  }
49
59
  }
@@ -54,7 +64,7 @@ const containOnlyNumbers = (value: string) => {
54
64
  return /^[()+\-\ .\d]*$/g.test(value)
55
65
  }
56
66
 
57
- const PhoneNumberInput = (props: PhoneNumberInputProps) => {
67
+ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.MutableRefObject<unknown>) => {
58
68
  const {
59
69
  aria = {},
60
70
  className,
@@ -71,7 +81,9 @@ const PhoneNumberInput = (props: PhoneNumberInputProps) => {
71
81
  onChange = () => {
72
82
  void 0
73
83
  },
84
+ onValidate = () => null,
74
85
  onlyCountries = [],
86
+ required = false,
75
87
  preferredCountries = [],
76
88
  value = "",
77
89
  } = props
@@ -87,39 +99,100 @@ const PhoneNumberInput = (props: PhoneNumberInputProps) => {
87
99
  const inputRef = useRef<HTMLInputElement>()
88
100
  const [inputValue, setInputValue] = useState(value)
89
101
  const [itiInit, setItiInit] = useState<any>()
90
- const [error, setError] = useState('')
102
+ const [error, setError] = useState(props.error)
91
103
  const [dropDownIsOpen, setDropDownIsOpen] = useState(false)
92
104
  const [selectedData, setSelectedData] = useState()
93
105
 
106
+ useEffect(() => {
107
+ if (error?.length > 0) {
108
+ onValidate(false)
109
+ } else {
110
+ onValidate(true)
111
+ }
112
+ }, [error, onValidate])
113
+
114
+ /*
115
+ useImperativeHandle exposes the kit's input element to a parent component via a ref.
116
+ See the Playbook docs for use cases.
117
+ Read: https://react.dev/reference/react/useImperativeHandle
118
+ */
119
+ useImperativeHandle(ref, () => {
120
+ return {
121
+ clearField() {
122
+ setInputValue("")
123
+ setError("")
124
+ },
125
+ inputNode() {
126
+ return inputRef.current
127
+ }
128
+ }
129
+ })
130
+
131
+ const showFormattedError = (reason = '') => {
132
+ const countryName = itiInit.getSelectedCountryData().name
133
+ const reasonText = reason.length > 0 ? ` (${reason})` : ''
134
+ setError(`Invalid ${countryName} phone number${reasonText}`)
135
+ return true
136
+ }
137
+
94
138
  const validateTooLongNumber = (itiInit: any) => {
95
- const error = itiInit.getValidationError()
139
+ if (!itiInit) return
140
+ if (itiInit.getValidationError() === ValidationError.TooLong) {
141
+ return showFormattedError('too long')
142
+ } else {
143
+ setError('')
144
+ }
145
+ }
96
146
 
97
- if (error === ValidationError.TooLong) {
98
- const countryName = itiInit.getSelectedCountryData().name
99
- setError(`Invalid ${countryName} phone number (too long)`)
147
+ const validateTooShortNumber = (itiInit: any) => {
148
+ if (!itiInit) return
149
+ if (itiInit.getValidationError() === ValidationError.TooShort) {
150
+ return showFormattedError('too short')
100
151
  } else {
101
- setError("")
152
+ if (inputValue.length === 1) {
153
+ return showFormattedError('too short')
154
+ } else {
155
+ setError('')
156
+ }
102
157
  }
103
158
  }
104
159
 
105
- const validateTooShortNumber = () => {
106
- const error = itiInit.getValidationError()
160
+ const validateOnlyNumbers = (itiInit: any) => {
161
+ if (!itiInit) return
162
+ if (inputValue && !containOnlyNumbers(inputValue)) {
163
+ return showFormattedError('enter numbers only')
164
+ }
165
+ }
107
166
 
108
- if (error === ValidationError.TooShort) {
109
- const countryName = itiInit.getSelectedCountryData().name
110
- setError(`Invalid ${countryName} phone number (too short)`)
167
+ const validateUnhandledError = (itiInit: any) => {
168
+ if (!required || !itiInit) return
169
+ if (itiInit.getValidationError() === ValidationError.SomethingWentWrong) {
170
+ if (inputValue.length === 1) {
171
+ return showFormattedError('too short')
172
+ } else if (inputValue.length === 0) {
173
+ setError('Missing phone number')
174
+ return true
175
+ } else {
176
+ return showFormattedError()
177
+ }
111
178
  }
112
179
  }
113
180
 
114
- const validateOnlyNumbers = () => {
115
- if (inputValue && !containOnlyNumbers(inputValue)) {
116
- setError("Invalid phone number. Enter numbers only.")
181
+ const validateMissingAreaCode = (itiInit: any) => {
182
+ if (!required || !itiInit) return
183
+ if (itiInit.getValidationError() === ValidationError.MissingAreaCode) {
184
+ showFormattedError('missing area code')
185
+ return true
117
186
  }
118
187
  }
119
188
 
120
189
  const validateErrors = () => {
121
- validateTooShortNumber()
122
- validateOnlyNumbers()
190
+ if (itiInit) isValid(itiInit.isValidNumber())
191
+ if (validateOnlyNumbers(itiInit)) return
192
+ if (validateTooLongNumber(itiInit)) return
193
+ if (validateTooShortNumber(itiInit)) return
194
+ if (validateUnhandledError(itiInit)) return
195
+ if (validateMissingAreaCode(itiInit)) return
123
196
  }
124
197
 
125
198
  const getCurrentSelectedData = (itiInit: any, inputValue: string) => {
@@ -128,7 +201,6 @@ const PhoneNumberInput = (props: PhoneNumberInputProps) => {
128
201
 
129
202
  const handleOnChange = (evt: React.ChangeEvent<HTMLInputElement>) => {
130
203
  setInputValue(evt.target.value)
131
- validateTooLongNumber(itiInit)
132
204
  const phoneNumberData = getCurrentSelectedData(itiInit, evt.target.value)
133
205
  setSelectedData(phoneNumberData)
134
206
  onChange(phoneNumberData)
@@ -137,25 +209,24 @@ const PhoneNumberInput = (props: PhoneNumberInputProps) => {
137
209
 
138
210
  // Separating Concerns as React Docs Recommend
139
211
  // This also Fixes things for our react_component rendering on the Rails Side
140
- useEffect(() => {
141
- formatAllCountries()
142
- }, [])
212
+ useEffect(formatAllCountries, [])
143
213
 
144
214
  useEffect(() => {
145
- const telInputInit = new intlTelInput(inputRef.current, {
215
+ const telInputInit = intlTelInput(inputRef.current, {
146
216
  separateDialCode: true,
147
217
  preferredCountries,
148
218
  allowDropdown: !disabled,
219
+ autoInsertDialCode: false,
149
220
  initialCountry,
150
221
  onlyCountries,
151
- }
152
- )
222
+ utilsScript: "intl-tel-input/build/js/utils.js"
223
+ })
153
224
 
154
225
  inputRef.current.addEventListener("countrychange", (evt: Event) => {
155
- validateTooLongNumber(telInputInit)
156
226
  const phoneNumberData = getCurrentSelectedData(telInputInit, (evt.target as HTMLInputElement).value)
157
227
  setSelectedData(phoneNumberData)
158
228
  onChange(phoneNumberData)
229
+ validateErrors()
159
230
  })
160
231
 
161
232
  inputRef.current.addEventListener("open:countrydropdown", () => setDropDownIsOpen(true))
@@ -164,24 +235,40 @@ const PhoneNumberInput = (props: PhoneNumberInputProps) => {
164
235
  setItiInit(telInputInit)
165
236
  }, [])
166
237
 
238
+ let textInputProps: {[key: string]: any} = {
239
+ className: dropDownIsOpen ? 'dropdown_open' : '',
240
+ dark,
241
+ "data-phone-number": JSON.stringify(selectedData),
242
+ disabled,
243
+ error,
244
+ type: 'tel',
245
+ id,
246
+ label,
247
+ name,
248
+ onBlur: validateErrors,
249
+ onChange: handleOnChange,
250
+ value: inputValue
251
+ }
252
+
253
+ let wrapperProps: Record<string, unknown> = { className: classes }
254
+
255
+ if (!isEmpty(aria)) textInputProps = {...textInputProps, ...ariaProps}
256
+ if (!isEmpty(data)) wrapperProps = {...wrapperProps, ...dataProps}
257
+ if (required) textInputProps.required = true
258
+
167
259
  return (
168
- <div {...ariaProps} {...dataProps} className={classes}>
260
+ <div {...wrapperProps}>
169
261
  <TextInput
170
- className={dropDownIsOpen ? 'dropdown_open' : ''}
171
- dark={dark}
172
- data-phone-number={JSON.stringify(selectedData)}
173
- disabled={disabled}
174
- error={error}
175
- id={id}
176
- label={label}
177
- name={name}
178
- onBlur={() => validateErrors()}
179
- onChange={handleOnChange}
180
- ref={inputRef}
181
- value={inputValue}
262
+ ref={
263
+ inputNode => {
264
+ ref ? ref.current = inputNode : null
265
+ inputRef.current = inputNode
266
+ }
267
+ }
268
+ {...textInputProps}
182
269
  />
183
270
  </div>
184
271
  )
185
272
  }
186
273
 
187
- export default PhoneNumberInput
274
+ export default forwardRef(PhoneNumberInput)
@@ -0,0 +1,26 @@
1
+ import React, { useEffect, useRef } from 'react'
2
+ import { Body, PhoneNumberInput } from '../..'
3
+
4
+ const PhoneNumberInputAccessInputElement = (props) => {
5
+ // 1. Create a ref - this accesses the kit's input element.
6
+ const ref = useRef()
7
+
8
+ // 2. Add any event listener to ref.current.inputNode() inside a useEffect hook.
9
+ useEffect(() => {
10
+ ref.current.inputNode().addEventListener("click", () => alert("Clicked!"))
11
+ })
12
+
13
+ // 3. Pass the ref to the ref prop.
14
+ return (
15
+ <>
16
+ <Body text="Click the input field below:" />
17
+ <PhoneNumberInput
18
+ id="access-input-element"
19
+ ref={ref}
20
+ {...props}
21
+ />
22
+ </>
23
+ )
24
+ }
25
+
26
+ export default PhoneNumberInputAccessInputElement
@@ -0,0 +1,3 @@
1
+ To access the kit's input element attributes or add event listeners, create a `ref` inside your parent component, pass it to the kit's `ref` prop, and use `ref.current.inputNode()` with your desired attribute or event listener inside a `useEffect` hook. `useEffect` is necessary because the `ref` will be initially `undefined`.
2
+
3
+ `inputNode()` is a custom function inside the kit that returns the input DOM element and its attributes. For example, to get the `name` attribute, use `ref.current.inputNode().name`
@@ -0,0 +1,30 @@
1
+ import React, { useRef } from 'react'
2
+ import { Button, PhoneNumberInput } from '../..'
3
+
4
+ const PhoneNumberInputClearField = (props) => {
5
+ // 1. Create a ref - this accesses the kit's input element.
6
+ const ref = useRef()
7
+
8
+ // 2. Use clearField() to clear the field.
9
+ const handleClick = () => {
10
+ ref.current.clearField()
11
+ }
12
+
13
+ // 3. Pass the ref to the ref prop.
14
+ return (
15
+ <>
16
+ <PhoneNumberInput
17
+ id="clear-field"
18
+ ref={ref}
19
+ {...props}
20
+ />
21
+
22
+ <Button
23
+ onClick={handleClick}
24
+ text="Clear the Input Field"
25
+ />
26
+ </>
27
+ )
28
+ }
29
+
30
+ export default PhoneNumberInputClearField
@@ -0,0 +1,3 @@
1
+ To clear a number inside the input element, create a `ref` inside your parent component, pass it to the kit's `ref` prop, and use `ref.current.clearField()`.
2
+
3
+ `clearField()` is a custom function inside the kit to clear numbers and the error message while still providing validation.
@@ -0,0 +1,14 @@
1
+ <form id="example-form-validation" action="" method="get">
2
+ <%= pb_rails("phone_number_input", props: { error: "Missing phone number.", id: "validation", initial_country: "af", value: "", required: true }) %>
3
+ <%= pb_rails("button", props: {html_type: "submit", text: "Save Phone Number"}) %>
4
+ </form>
5
+
6
+ <% content_for(:pb_js) do %>
7
+ <%= javascript_tag do %>
8
+ document.addEventListener('DOMContentLoaded', function () {
9
+ document.querySelector('#example-form-validation').addEventListener('submit', function (e) {
10
+ if (e.target.querySelectorAll('[error]:not([error=""])').length > 0) e.preventDefault();
11
+ })
12
+ })
13
+ <% end %>
14
+ <% end %>
@@ -0,0 +1,60 @@
1
+ import React, { useEffect, useState } from "react";
2
+ import { Button, FixedConfirmationToast, PhoneNumberInput } from "../../";
3
+
4
+ const PhoneNumberInputValidation = (props) => {
5
+ const [formErrors, setFormErrors] = useState("");
6
+ const [showFormErrors, setShowFormErrors] = useState(false);
7
+ const [phoneNumber, setPhoneNumber] = useState("");
8
+ const [countryCode, setCountryCode] = useState("af");
9
+
10
+ const handleOnValidate = (valid) => {
11
+ setFormErrors(
12
+ valid ? "" : "Please correct the fields below and try again."
13
+ );
14
+ };
15
+
16
+ const handleOnChange = ({ iso2, number }) => {
17
+ setCountryCode(iso2);
18
+ setPhoneNumber(number);
19
+ };
20
+
21
+ const handleOnSubmit = (e) => {
22
+ if (showFormErrors) e.preventDefault()
23
+ }
24
+
25
+ useEffect(() => {
26
+ setShowFormErrors(formErrors.length > 0);
27
+ }, [formErrors]);
28
+
29
+ return (
30
+ <form
31
+ action=""
32
+ method="get"
33
+ onSubmit={handleOnSubmit}
34
+ >
35
+ {showFormErrors && (
36
+ <FixedConfirmationToast
37
+ marginBottom="md"
38
+ status="error"
39
+ text={formErrors}
40
+ />
41
+ )}
42
+ <PhoneNumberInput
43
+ error="Missing phone number."
44
+ id="validation"
45
+ initialCountry={countryCode}
46
+ onChange={handleOnChange}
47
+ onValidate={handleOnValidate}
48
+ required
49
+ value={phoneNumber}
50
+ {...props}
51
+ />
52
+ <Button
53
+ htmlType="submit"
54
+ text="Save Phone Number"
55
+ />
56
+ </form>
57
+ );
58
+ };
59
+
60
+ export default PhoneNumberInputValidation;
@@ -5,9 +5,13 @@ examples:
5
5
  - phone_number_input_preferred_countries: Preferred Countries
6
6
  - phone_number_input_initial_country: Initial Country
7
7
  - phone_number_input_only_countries: Limited Countries
8
+ - phone_number_input_validation: Form Validation
9
+ - phone_number_input_clear_field: Clearing the Input Field
10
+ - phone_number_input_access_input_element: Accessing the Input Element
8
11
 
9
12
  rails:
10
13
  - phone_number_input_default: Default
11
14
  - phone_number_input_preferred_countries: Preferred Countries
12
15
  - phone_number_input_initial_country: Initial Country
13
- - phone_number_input_only_countries: Limited Countries
16
+ - phone_number_input_only_countries: Limited Countries
17
+ - phone_number_input_validation: Form Validation
@@ -2,3 +2,6 @@ export { default as PhoneNumberInputDefault } from './_phone_number_input_defaul
2
2
  export { default as PhoneNumberInputPreferredCountries } from './_phone_number_input_preferred_countries'
3
3
  export { default as PhoneNumberInputInitialCountry } from './_phone_number_input_initial_country'
4
4
  export { default as PhoneNumberInputOnlyCountries } from './_phone_number_input_only_countries'
5
+ export { default as PhoneNumberInputValidation } from './_phone_number_input_validation'
6
+ export { default as PhoneNumberInputClearField } from './_phone_number_input_clear_field'
7
+ export { default as PhoneNumberInputAccessInputElement } from './_phone_number_input_access_input_element'
@@ -5,6 +5,8 @@ module Playbook
5
5
  class PhoneNumberInput < Playbook::KitBase
6
6
  prop :disabled, type: Playbook::Props::Boolean,
7
7
  default: false
8
+ prop :required, type: Playbook::Props::Boolean,
9
+ default: false
8
10
  prop :initial_country, type: Playbook::Props::String,
9
11
  default: ""
10
12
  prop :label, type: Playbook::Props::String,
@@ -15,6 +17,8 @@ module Playbook
15
17
  default: []
16
18
  prop :preferred_countries, type: Playbook::Props::Array,
17
19
  default: []
20
+ prop :error, type: Playbook::Props::String,
21
+ default: ""
18
22
  prop :value, type: Playbook::Props::String,
19
23
  default: ""
20
24
 
@@ -27,11 +31,13 @@ module Playbook
27
31
  id: id,
28
32
  dark: dark,
29
33
  disabled: disabled,
34
+ error: error,
30
35
  initialCountry: initial_country,
31
36
  label: label,
32
37
  name: name,
33
38
  onlyCountries: only_countries,
34
39
  preferredCountries: preferred_countries,
40
+ required: required,
35
41
  value: value,
36
42
  }
37
43
  end
@@ -1,74 +1,122 @@
1
- import React from 'react'
2
- import { render, screen } from '../utilities/test-utils'
3
- import PhoneNumberInput from './_phone_number_input'
1
+ import React from "react";
2
+ import { render, screen } from "../utilities/test-utils";
3
+ import PhoneNumberInput from "./_phone_number_input";
4
4
 
5
- const testId = "phoneNumberInput"
5
+ const testId = "phoneNumberInput";
6
6
 
7
- test('should be disabled', () => {
8
- const props = {
9
- disabled: true,
10
- id: testId,
11
- }
7
+ test("should be disabled", () => {
8
+ const props = {
9
+ disabled: true,
10
+ id: testId,
11
+ };
12
12
 
13
- render(<PhoneNumberInput {...props} />)
14
- const kit = screen.getByRole("textbox")
15
- expect(kit).toBeDisabled()
16
- })
13
+ render(<PhoneNumberInput {...props} />);
14
+ const kit = screen.getByRole("textbox");
15
+ expect(kit).toBeDisabled();
16
+ });
17
17
 
18
- test('should be enabled by default', () => {
19
- const props = {
20
- id: testId,
21
- }
18
+ test("should be enabled by default", () => {
19
+ const props = {
20
+ id: testId,
21
+ };
22
22
 
23
- render(<PhoneNumberInput {...props} />)
24
- const kit = screen.getByRole("textbox")
25
- expect(kit).not.toBeDisabled()
26
- })
23
+ render(<PhoneNumberInput {...props} />);
24
+ const kit = screen.getByRole("textbox");
25
+ expect(kit).not.toBeDisabled();
26
+ });
27
27
 
28
- test('should have label', () => {
29
- const label = 'Phone Number'
30
- const props = {
31
- id: testId,
32
- label,
33
- }
28
+ test("should have label", () => {
29
+ const label = "Phone Number";
30
+ const props = {
31
+ id: testId,
32
+ label,
33
+ };
34
34
 
35
- render(<PhoneNumberInput {...props} />)
36
- const kit = screen.getByText(label)
37
- expect(kit).toBeInTheDocument()
38
- })
35
+ render(<PhoneNumberInput {...props} />);
36
+ const kit = screen.getByText(label);
37
+ expect(kit).toBeInTheDocument();
38
+ });
39
39
 
40
- test('should pass data prop', () => {
41
- const props = {
42
- data: { testid: testId },
43
- id: testId,
44
- }
40
+ test("should pass data prop", () => {
41
+ const props = {
42
+ data: { testid: testId },
43
+ id: testId,
44
+ };
45
+
46
+ render(<PhoneNumberInput {...props} />);
47
+ const kit = screen.getByTestId(testId);
48
+ expect(kit).toBeInTheDocument();
49
+ });
50
+
51
+ test("should pass className prop", () => {
52
+ const className = "custom-class-name";
53
+ const props = {
54
+ className,
55
+ data: { testid: testId },
56
+ id: testId,
57
+ };
58
+
59
+ render(<PhoneNumberInput {...props} />);
60
+ const kit = screen.getByTestId(testId);
61
+ expect(kit).toHaveClass(className);
62
+ });
63
+
64
+ test("should pass value prop", () => {
65
+ const value = "1234567890";
66
+ const props = {
67
+ id: testId,
68
+ value,
69
+ };
45
70
 
46
- render(<PhoneNumberInput {...props} />)
47
- const kit = screen.getByTestId(testId)
48
- expect(kit).toBeInTheDocument()
49
- })
71
+ render(<PhoneNumberInput {...props} />);
72
+ const kit = screen.getByRole("textbox");
73
+ expect(kit).toHaveDisplayValue(value);
74
+ });
50
75
 
51
- test('should pass className prop', () => {
52
- const className = 'custom-class-name'
76
+ //TODO: test required field presence
77
+ test("should pass required prop", () => {
78
+ const props = {
79
+ id: testId,
80
+ };
81
+
82
+ render(
83
+ <PhoneNumberInput
84
+ required
85
+ {...props}
86
+ />
87
+ );
88
+ const kit = screen.getByRole("textbox");
89
+ expect(kit).toHaveAttribute("required");
90
+ });
91
+
92
+ test("should have error attribute when invalid", () => {
53
93
  const props = {
54
- className,
55
- data: { testid: testId },
56
- id: testId,
57
- }
58
-
59
- render(<PhoneNumberInput {...props} />)
60
- const kit = screen.getByTestId(testId)
61
- expect(kit).toHaveClass(className)
62
- })
63
-
64
- test('should pass value prop', () => {
65
- const value = '1234567890'
94
+ id: testId,
95
+ error: "Something isn't right here."
96
+ };
97
+
98
+ render(
99
+ <PhoneNumberInput
100
+ {...props}
101
+ />
102
+ );
103
+ const kit = screen.getByRole("textbox");
104
+ expect(kit).toHaveAttribute("error");
105
+ });
106
+
107
+ test("should trigger callback", () => {
108
+ const handleOnValidate = jest.fn((valid) => valid)
109
+
66
110
  const props = {
67
- id: testId,
68
- value,
69
- }
70
-
71
- render(<PhoneNumberInput {...props} />)
72
- const kit = screen.getByRole("textbox")
73
- expect(kit).toHaveDisplayValue(value)
74
- })
111
+ id: testId,
112
+ onValidate: handleOnValidate
113
+ };
114
+
115
+ render(
116
+ <PhoneNumberInput
117
+ {...props}
118
+ />
119
+ );
120
+
121
+ expect(handleOnValidate).toBeCalledWith(true)
122
+ });