playbook_ui 12.25.0.pre.alpha.play822bolddefaultfortitle3764 → 12.25.0.pre.alpha.play824786
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.
- checksums.yaml +4 -4
- data/app/pb_kits/playbook/_playbook.scss +1 -0
- data/app/pb_kits/playbook/index.js +1 -0
- data/app/pb_kits/playbook/pb_avatar/docs/_avatar_swift.md +82 -1
- data/app/pb_kits/playbook/pb_detail/_detail.scss +44 -0
- data/app/pb_kits/playbook/pb_detail/_detail.tsx +55 -0
- data/app/pb_kits/playbook/pb_detail/_detail_mixins.scss +29 -0
- data/app/pb_kits/playbook/pb_detail/detail.html.erb +7 -0
- data/app/pb_kits/playbook/pb_detail/detail.rb +31 -0
- data/app/pb_kits/playbook/pb_detail/detail.test.jsx +46 -0
- data/app/pb_kits/playbook/pb_detail/docs/_description.md +1 -0
- data/app/pb_kits/playbook/pb_detail/docs/_detail_bold.html.erb +34 -0
- data/app/pb_kits/playbook/pb_detail/docs/_detail_bold.jsx +49 -0
- data/app/pb_kits/playbook/pb_detail/docs/_detail_bold.md +1 -0
- data/app/pb_kits/playbook/pb_detail/docs/_detail_colors.html.erb +24 -0
- data/app/pb_kits/playbook/pb_detail/docs/_detail_colors.jsx +38 -0
- data/app/pb_kits/playbook/pb_detail/docs/_detail_colors.md +6 -0
- data/app/pb_kits/playbook/pb_detail/docs/_detail_default.html.erb +3 -0
- data/app/pb_kits/playbook/pb_detail/docs/_detail_default.jsx +13 -0
- data/app/pb_kits/playbook/pb_detail/docs/_detail_styled.html.erb +22 -0
- data/app/pb_kits/playbook/pb_detail/docs/_detail_styled.jsx +32 -0
- data/app/pb_kits/playbook/pb_detail/docs/example.yml +11 -0
- data/app/pb_kits/playbook/pb_detail/docs/index.js +4 -0
- data/app/pb_kits/playbook/pb_docs/kit_example.html.erb +14 -13
- data/app/pb_kits/playbook/pb_form_pill/_form_pill.tsx +3 -2
- data/app/pb_kits/playbook/pb_multi_level_select/_helper_functions.tsx +212 -0
- data/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.scss +58 -98
- data/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.tsx +340 -86
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_default.md +1 -1
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_return_all_selected.html.erb +1 -0
- data/app/pb_kits/playbook/pb_multi_level_select/multi_level_select.test.jsx +1 -1
- data/app/pb_kits/playbook/pb_phone_number_input/_phone_number_input.tsx +109 -44
- data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_validation.html.erb +14 -0
- data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_validation.jsx +60 -0
- data/app/pb_kits/playbook/pb_phone_number_input/docs/example.yml +3 -1
- data/app/pb_kits/playbook/pb_phone_number_input/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_phone_number_input/phone_number_input.rb +6 -0
- data/app/pb_kits/playbook/pb_phone_number_input/phone_number_input.test.js +110 -62
- data/app/pb_kits/playbook/pb_title/_title.scss +1 -1
- data/app/pb_kits/playbook/pb_title/_title.tsx +3 -2
- data/app/pb_kits/playbook/pb_title/docs/_title_light_weight.html.erb +0 -1
- data/app/pb_kits/playbook/pb_title/docs/_title_light_weight.jsx +0 -6
- data/app/pb_kits/playbook/pb_title/docs/_title_light_weight.md +2 -1
- data/app/pb_kits/playbook/pb_title/title.rb +10 -3
- data/app/pb_kits/playbook/pb_title/title.test.js +3 -3
- data/app/pb_kits/playbook/playbook-doc.js +2 -0
- data/app/pb_kits/playbook/utilities/object.ts +3 -0
- data/dist/menu.yml +1 -0
- data/dist/playbook-rails.js +7 -7
- data/lib/playbook/forms/builder/intl_telephone_field.rb +12 -0
- data/lib/playbook/forms/builder.rb +1 -0
- data/lib/playbook/version.rb +1 -1
- metadata +26 -4
- data/app/pb_kits/playbook/pb_multi_level_select/_multi_select_helper.tsx +0 -31
- data/app/pb_kits/playbook/pb_multi_level_select/helper_functions.ts +0 -87
@@ -1,12 +1,17 @@
|
|
1
|
-
import React, { useEffect, useRef, useState } from 'react'
|
1
|
+
import React, { forwardRef, useEffect, useRef, useState } from 'react'
|
2
2
|
import classnames from 'classnames'
|
3
|
-
|
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
|
-
|
53
|
+
const countryData = window.intlTelInputGlobals.getCountryData()
|
44
54
|
|
45
55
|
for (let i = 0; i < countryData.length; i++) {
|
46
|
-
|
56
|
+
const country = countryData[i]
|
47
57
|
country.name = formatToGlobalCountryName(country.name)
|
48
58
|
}
|
49
59
|
}
|
@@ -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,83 @@ 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
|
+
const showFormattedError = (reason = '') => {
|
115
|
+
const countryName = itiInit.getSelectedCountryData().name
|
116
|
+
const reasonText = reason.length > 0 ? ` (${reason})` : ''
|
117
|
+
setError(`Invalid ${countryName} phone number${reasonText}`)
|
118
|
+
return true
|
119
|
+
}
|
120
|
+
|
94
121
|
const validateTooLongNumber = (itiInit: any) => {
|
95
|
-
|
122
|
+
if (!itiInit) return
|
123
|
+
if (itiInit.getValidationError() === ValidationError.TooLong) {
|
124
|
+
return showFormattedError('too long')
|
125
|
+
} else {
|
126
|
+
setError('')
|
127
|
+
}
|
128
|
+
}
|
96
129
|
|
97
|
-
|
98
|
-
|
99
|
-
|
130
|
+
const validateTooShortNumber = (itiInit: any) => {
|
131
|
+
if (!itiInit) return
|
132
|
+
if (itiInit.getValidationError() === ValidationError.TooShort) {
|
133
|
+
return showFormattedError('too short')
|
100
134
|
} else {
|
101
|
-
|
135
|
+
if (inputValue.length === 1) {
|
136
|
+
return showFormattedError('too short')
|
137
|
+
} else {
|
138
|
+
setError('')
|
139
|
+
}
|
102
140
|
}
|
103
141
|
}
|
104
142
|
|
105
|
-
const
|
106
|
-
|
143
|
+
const validateOnlyNumbers = (itiInit: any) => {
|
144
|
+
if (!itiInit) return
|
145
|
+
if (inputValue && !containOnlyNumbers(inputValue)) {
|
146
|
+
return showFormattedError('enter numbers only')
|
147
|
+
}
|
148
|
+
}
|
107
149
|
|
108
|
-
|
109
|
-
|
110
|
-
|
150
|
+
const validateUnhandledError = (itiInit: any) => {
|
151
|
+
if (!required || !itiInit) return
|
152
|
+
if (itiInit.getValidationError() === ValidationError.SomethingWentWrong) {
|
153
|
+
if (inputValue.length === 1) {
|
154
|
+
return showFormattedError('too short')
|
155
|
+
} else if (inputValue.length === 0) {
|
156
|
+
setError('Missing phone number')
|
157
|
+
return true
|
158
|
+
} else {
|
159
|
+
return showFormattedError()
|
160
|
+
}
|
111
161
|
}
|
112
162
|
}
|
113
163
|
|
114
|
-
const
|
115
|
-
if (
|
116
|
-
|
164
|
+
const validateMissingAreaCode = (itiInit: any) => {
|
165
|
+
if (!required || !itiInit) return
|
166
|
+
if (itiInit.getValidationError() === ValidationError.MissingAreaCode) {
|
167
|
+
showFormattedError('missing area code')
|
168
|
+
return true
|
117
169
|
}
|
118
170
|
}
|
119
171
|
|
120
172
|
const validateErrors = () => {
|
121
|
-
|
122
|
-
validateOnlyNumbers()
|
173
|
+
if (itiInit) isValid(itiInit.isValidNumber())
|
174
|
+
if (validateOnlyNumbers(itiInit)) return
|
175
|
+
if (validateTooLongNumber(itiInit)) return
|
176
|
+
if (validateTooShortNumber(itiInit)) return
|
177
|
+
if (validateUnhandledError(itiInit)) return
|
178
|
+
if (validateMissingAreaCode(itiInit)) return
|
123
179
|
}
|
124
180
|
|
125
181
|
const getCurrentSelectedData = (itiInit: any, inputValue: string) => {
|
@@ -128,7 +184,6 @@ const PhoneNumberInput = (props: PhoneNumberInputProps) => {
|
|
128
184
|
|
129
185
|
const handleOnChange = (evt: React.ChangeEvent<HTMLInputElement>) => {
|
130
186
|
setInputValue(evt.target.value)
|
131
|
-
validateTooLongNumber(itiInit)
|
132
187
|
const phoneNumberData = getCurrentSelectedData(itiInit, evt.target.value)
|
133
188
|
setSelectedData(phoneNumberData)
|
134
189
|
onChange(phoneNumberData)
|
@@ -137,25 +192,24 @@ const PhoneNumberInput = (props: PhoneNumberInputProps) => {
|
|
137
192
|
|
138
193
|
// Separating Concerns as React Docs Recommend
|
139
194
|
// This also Fixes things for our react_component rendering on the Rails Side
|
140
|
-
useEffect(
|
141
|
-
formatAllCountries()
|
142
|
-
}, [])
|
195
|
+
useEffect(formatAllCountries, [])
|
143
196
|
|
144
197
|
useEffect(() => {
|
145
|
-
const telInputInit =
|
198
|
+
const telInputInit = intlTelInput(inputRef.current, {
|
146
199
|
separateDialCode: true,
|
147
200
|
preferredCountries,
|
148
201
|
allowDropdown: !disabled,
|
202
|
+
autoInsertDialCode: false,
|
149
203
|
initialCountry,
|
150
204
|
onlyCountries,
|
151
|
-
|
152
|
-
)
|
205
|
+
utilsScript: "https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/18.1.6/js/utils.min.js"
|
206
|
+
})
|
153
207
|
|
154
208
|
inputRef.current.addEventListener("countrychange", (evt: Event) => {
|
155
|
-
validateTooLongNumber(telInputInit)
|
156
209
|
const phoneNumberData = getCurrentSelectedData(telInputInit, (evt.target as HTMLInputElement).value)
|
157
210
|
setSelectedData(phoneNumberData)
|
158
211
|
onChange(phoneNumberData)
|
212
|
+
validateErrors()
|
159
213
|
})
|
160
214
|
|
161
215
|
inputRef.current.addEventListener("open:countrydropdown", () => setDropDownIsOpen(true))
|
@@ -164,24 +218,35 @@ const PhoneNumberInput = (props: PhoneNumberInputProps) => {
|
|
164
218
|
setItiInit(telInputInit)
|
165
219
|
}, [])
|
166
220
|
|
221
|
+
let textInputProps: {[key: string]: any} = {
|
222
|
+
className: dropDownIsOpen ? 'dropdown_open' : '',
|
223
|
+
dark,
|
224
|
+
"data-phone-number": JSON.stringify(selectedData),
|
225
|
+
disabled,
|
226
|
+
error,
|
227
|
+
type: 'tel',
|
228
|
+
id,
|
229
|
+
label,
|
230
|
+
name,
|
231
|
+
onBlur: validateErrors,
|
232
|
+
onChange: handleOnChange,
|
233
|
+
value: inputValue
|
234
|
+
}
|
235
|
+
|
236
|
+
let wrapperProps: Record<string, unknown> = { className: classes }
|
237
|
+
|
238
|
+
if (!isEmpty(aria)) textInputProps = {...textInputProps, ...ariaProps}
|
239
|
+
if (!isEmpty(data)) wrapperProps = {...wrapperProps, ...dataProps}
|
240
|
+
if (required) textInputProps.required = true
|
241
|
+
|
167
242
|
return (
|
168
|
-
<div {...
|
243
|
+
<div {...wrapperProps}>
|
169
244
|
<TextInput
|
170
|
-
|
171
|
-
|
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}
|
245
|
+
ref={inputRef}
|
246
|
+
{...textInputProps}
|
182
247
|
/>
|
183
248
|
</div>
|
184
249
|
)
|
185
250
|
}
|
186
251
|
|
187
|
-
export default PhoneNumberInput
|
252
|
+
export default forwardRef(PhoneNumberInput)
|
@@ -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,11 @@ 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
|
8
9
|
|
9
10
|
rails:
|
10
11
|
- phone_number_input_default: Default
|
11
12
|
- phone_number_input_preferred_countries: Preferred Countries
|
12
13
|
- phone_number_input_initial_country: Initial Country
|
13
|
-
- phone_number_input_only_countries: Limited Countries
|
14
|
+
- phone_number_input_only_countries: Limited Countries
|
15
|
+
- phone_number_input_validation: Form Validation
|
@@ -2,3 +2,4 @@ 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'
|
@@ -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
|
2
|
-
import { render, screen } from
|
3
|
-
import PhoneNumberInput from
|
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(
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
7
|
+
test("should be disabled", () => {
|
8
|
+
const props = {
|
9
|
+
disabled: true,
|
10
|
+
id: testId,
|
11
|
+
};
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
})
|
13
|
+
render(<PhoneNumberInput {...props} />);
|
14
|
+
const kit = screen.getByRole("textbox");
|
15
|
+
expect(kit).toBeDisabled();
|
16
|
+
});
|
17
17
|
|
18
|
-
test(
|
19
|
-
|
20
|
-
|
21
|
-
|
18
|
+
test("should be enabled by default", () => {
|
19
|
+
const props = {
|
20
|
+
id: testId,
|
21
|
+
};
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
})
|
23
|
+
render(<PhoneNumberInput {...props} />);
|
24
|
+
const kit = screen.getByRole("textbox");
|
25
|
+
expect(kit).not.toBeDisabled();
|
26
|
+
});
|
27
27
|
|
28
|
-
test(
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
28
|
+
test("should have label", () => {
|
29
|
+
const label = "Phone Number";
|
30
|
+
const props = {
|
31
|
+
id: testId,
|
32
|
+
label,
|
33
|
+
};
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
})
|
35
|
+
render(<PhoneNumberInput {...props} />);
|
36
|
+
const kit = screen.getByText(label);
|
37
|
+
expect(kit).toBeInTheDocument();
|
38
|
+
});
|
39
39
|
|
40
|
-
test(
|
41
|
-
|
42
|
-
|
43
|
-
|
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
|
-
|
47
|
-
|
48
|
-
|
49
|
-
})
|
71
|
+
render(<PhoneNumberInput {...props} />);
|
72
|
+
const kit = screen.getByRole("textbox");
|
73
|
+
expect(kit).toHaveDisplayValue(value);
|
74
|
+
});
|
50
75
|
|
51
|
-
test
|
52
|
-
|
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
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
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
|
-
|
68
|
-
|
69
|
-
}
|
70
|
-
|
71
|
-
render(
|
72
|
-
|
73
|
-
|
74
|
-
|
111
|
+
id: testId,
|
112
|
+
onValidate: handleOnValidate
|
113
|
+
};
|
114
|
+
|
115
|
+
render(
|
116
|
+
<PhoneNumberInput
|
117
|
+
{...props}
|
118
|
+
/>
|
119
|
+
);
|
120
|
+
|
121
|
+
expect(handleOnValidate).toBeCalledWith(true)
|
122
|
+
});
|
@@ -27,7 +27,7 @@ const Title = (props: TitleProps): React.ReactElement => {
|
|
27
27
|
data = {},
|
28
28
|
id,
|
29
29
|
size = 3,
|
30
|
-
bold = true,
|
30
|
+
bold = size === 3 ? false : true,
|
31
31
|
tag = 'h3',
|
32
32
|
text,
|
33
33
|
variant = null,
|
@@ -35,9 +35,10 @@ const Title = (props: TitleProps): React.ReactElement => {
|
|
35
35
|
|
36
36
|
const ariaProps: {[key: string]: string | number} = buildAriaProps(aria)
|
37
37
|
const dataProps: {[key: string]: string | number} = buildDataProps(data)
|
38
|
+
|
38
39
|
const getBold = bold ? '' : 'thin'
|
39
40
|
const classes = classnames(
|
40
|
-
buildCss(
|
41
|
+
buildCss("pb_title_kit", `size_${size}`, variant, color) + ` ${getBold}`,
|
41
42
|
globalProps(props),
|
42
43
|
className
|
43
44
|
)
|
@@ -1,3 +1,4 @@
|
|
1
1
|
##### Prop
|
2
|
-
Title `size 1
|
2
|
+
Title `size 1` & `size 2` will use `font-weight: 700` by default, if you want a lighter font weight, use the `bold` prop set to `false`.
|
3
|
+
Title `size 3` uses a light font weight by default and will not accept a bold font weight.
|
3
4
|
Title `size 4` uses a heavy font weight by default and will not accept a lighter font weight.
|
@@ -17,14 +17,21 @@ module Playbook
|
|
17
17
|
values: [nil, "link"],
|
18
18
|
default: nil,
|
19
19
|
deprecated: true
|
20
|
-
|
20
|
+
|
21
|
+
def initialize(props)
|
22
|
+
props[:bold] = [1, 2, 4].include?(props[:size]) unless props.key?(:bold)
|
23
|
+
props[:bold] = false if props[:size].nil? && !props.key?(:bold)
|
24
|
+
super(props)
|
25
|
+
end
|
26
|
+
|
27
|
+
prop :bold, type: Playbook::Props::Boolean
|
21
28
|
|
22
29
|
def classname
|
23
|
-
generate_classname("pb_title_kit", size, variant, color
|
30
|
+
generate_classname("pb_title_kit", size, variant, color) + is_bold
|
24
31
|
end
|
25
32
|
|
26
33
|
def is_bold
|
27
|
-
bold ?
|
34
|
+
bold ? "" : " thin"
|
28
35
|
end
|
29
36
|
end
|
30
37
|
end
|