playbook_ui 15.1.0.pre.alpha.PLAY2468phonenuminputvalidation10993 → 15.1.0.pre.alpha.PLAY2468phonenuminputvalidation11111
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/pb_advanced_table/Hooks/useTableState.ts +0 -2
- data/app/pb_kits/playbook/pb_date_picker/_date_picker.scss +4 -0
- data/app/pb_kits/playbook/pb_dialog/docs/_dialog_stacked_alert.html.erb +16 -16
- data/app/pb_kits/playbook/pb_dialog/docs/_dialog_stacked_alert.jsx +2 -1
- data/app/pb_kits/playbook/pb_dialog/docs/_dialog_status.html.erb +31 -31
- data/app/pb_kits/playbook/pb_dialog/docs/_dialog_status.jsx +4 -3
- data/app/pb_kits/playbook/pb_form/docs/_form_form_with_validate.html.erb +11 -0
- data/app/pb_kits/playbook/pb_form/pb_form_validation.js +13 -37
- data/app/pb_kits/playbook/pb_icon_circle/_icon_circle.tsx +2 -2
- data/app/pb_kits/playbook/pb_icon_stat_value/_icon_stat_value.scss +15 -21
- data/app/pb_kits/playbook/pb_icon_stat_value/_icon_stat_value.tsx +6 -5
- data/app/pb_kits/playbook/pb_icon_stat_value/icon_stat_value.html.erb +2 -0
- data/app/pb_kits/playbook/pb_icon_stat_value/icon_stat_value.rb +11 -3
- data/app/pb_kits/playbook/pb_icon_stat_value/icon_stat_value.test.js +9 -8
- data/app/pb_kits/playbook/pb_phone_number_input/_phone_number_input.tsx +15 -89
- data/app/pb_kits/playbook/pb_text_input/_text_input.tsx +14 -6
- data/app/pb_kits/playbook/pb_text_input/docs/_text_input_default.html.erb +8 -4
- data/app/pb_kits/playbook/pb_text_input/docs/_text_input_default.jsx +5 -0
- data/app/pb_kits/playbook/pb_text_input/docs/_text_input_default.md +1 -0
- data/app/pb_kits/playbook/pb_text_input/text_input.html.erb +3 -1
- data/app/pb_kits/playbook/pb_text_input/text_input.rb +6 -0
- data/app/pb_kits/playbook/pb_typeahead/_typeahead.tsx +39 -1
- data/app/pb_kits/playbook/pb_typeahead/typeahead.rb +2 -0
- data/dist/chunks/{_line_graph-C3zTTfo0.js → _line_graph-Bb7DQKyL.js} +1 -1
- data/dist/chunks/{_typeahead-CfKPIYmd.js → _typeahead-BBamAvDm.js} +1 -1
- data/dist/chunks/{_weekday_stacked-CUTwEQ-P.js → _weekday_stacked-AqPvtHD7.js} +3 -3
- data/dist/chunks/pb_form_validation-CleM960_.js +1 -0
- data/dist/chunks/vendor.js +1 -1
- data/dist/playbook-doc.js +2 -2
- data/dist/playbook-rails-react-bindings.js +1 -1
- data/dist/playbook-rails.js +1 -1
- data/dist/playbook.css +1 -1
- data/lib/playbook/version.rb +1 -1
- metadata +7 -6
- data/dist/chunks/pb_form_validation-D1VURgVg.js +0 -1
|
@@ -110,41 +110,18 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
|
|
|
110
110
|
|
|
111
111
|
const inputRef = useRef<HTMLInputElement | null>(null)
|
|
112
112
|
const itiRef = useRef<any>(null);
|
|
113
|
-
const wrapperRef = useRef<HTMLDivElement | null>(null);
|
|
114
113
|
const [inputValue, setInputValue] = useState(value)
|
|
115
|
-
const [error, setError] = useState("")
|
|
114
|
+
const [error, setError] = useState(props.error || "")
|
|
116
115
|
const [dropDownIsOpen, setDropDownIsOpen] = useState(false)
|
|
117
116
|
const [selectedData, setSelectedData] = useState()
|
|
118
117
|
const [hasTyped, setHasTyped] = useState(false)
|
|
119
|
-
const [formSubmitted, setFormSubmitted] = useState(false)
|
|
120
|
-
|
|
121
|
-
// Function to update validation state on the wrapper element
|
|
122
|
-
// Only applies when input is required
|
|
123
|
-
const updateValidationState = (hasError: boolean) => {
|
|
124
|
-
if (wrapperRef.current && required) {
|
|
125
|
-
if (hasError) {
|
|
126
|
-
wrapperRef.current.setAttribute('data-pb-phone-validation-error', 'true')
|
|
127
|
-
} else {
|
|
128
|
-
wrapperRef.current.removeAttribute('data-pb-phone-validation-error')
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// Determine which error to display
|
|
134
|
-
// Show internal errors on blur (hasTyped) or on form submission (formSubmitted)
|
|
135
|
-
const shouldShowInternalError = (hasTyped || formSubmitted) && required && error
|
|
136
|
-
const displayError = props.error || (shouldShowInternalError ? error : "")
|
|
137
118
|
|
|
138
119
|
useEffect(() => {
|
|
139
|
-
|
|
140
|
-
if (hasError) {
|
|
120
|
+
if ((error ?? '').length > 0) {
|
|
141
121
|
onValidate(false)
|
|
142
122
|
} else {
|
|
143
123
|
onValidate(true)
|
|
144
124
|
}
|
|
145
|
-
|
|
146
|
-
// Update validation state whenever error changes
|
|
147
|
-
updateValidationState(hasError)
|
|
148
125
|
}, [error, onValidate])
|
|
149
126
|
|
|
150
127
|
const unformatNumber = (formattedNumber: any) => {
|
|
@@ -195,7 +172,7 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
|
|
|
195
172
|
}
|
|
196
173
|
|
|
197
174
|
const validateUnhandledError = (itiInit: any) => {
|
|
198
|
-
if (!
|
|
175
|
+
if (!itiInit) return
|
|
199
176
|
if (itiInit.getValidationError() === ValidationError.SomethingWentWrong) {
|
|
200
177
|
if (inputValue.length === 1) {
|
|
201
178
|
return showFormattedError('too short')
|
|
@@ -224,9 +201,8 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
|
|
|
224
201
|
}
|
|
225
202
|
}
|
|
226
203
|
|
|
227
|
-
// Validation for required empty fields
|
|
228
204
|
const validateRequiredField = () => {
|
|
229
|
-
if (
|
|
205
|
+
if (!inputValue || inputValue.trim() === '') {
|
|
230
206
|
setError('Missing phone number')
|
|
231
207
|
return true
|
|
232
208
|
}
|
|
@@ -234,17 +210,14 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
|
|
|
234
210
|
}
|
|
235
211
|
|
|
236
212
|
const validateErrors = () => {
|
|
237
|
-
// If field is empty,
|
|
213
|
+
// If field is empty, show error message
|
|
238
214
|
if (!inputValue || inputValue.trim() === '') {
|
|
239
215
|
if (validateRequiredField()) return
|
|
240
|
-
// Clear any existing errors if field is empty and not required
|
|
241
|
-
if (!required) {
|
|
242
|
-
setError('')
|
|
243
|
-
}
|
|
244
216
|
return
|
|
245
217
|
}
|
|
246
218
|
|
|
247
|
-
|
|
219
|
+
if (!hasTyped && !error) return
|
|
220
|
+
|
|
248
221
|
if (itiRef.current) isValid(itiRef.current.isValidNumber())
|
|
249
222
|
if (validateOnlyNumbers(itiRef.current)) return
|
|
250
223
|
if (validateTooLongNumber(itiRef.current)) return
|
|
@@ -254,29 +227,6 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
|
|
|
254
227
|
if (validateRepeatCountryCode(itiRef.current)) return
|
|
255
228
|
}
|
|
256
229
|
|
|
257
|
-
// Add listener for form validation to track when validation should be shown
|
|
258
|
-
useEffect(() => {
|
|
259
|
-
const handleInvalid = (event: Event) => {
|
|
260
|
-
const target = event.target as HTMLInputElement
|
|
261
|
-
const phoneNumberContainer = target.closest('.pb_phone_number_input')
|
|
262
|
-
|
|
263
|
-
if (phoneNumberContainer && phoneNumberContainer === wrapperRef.current) {
|
|
264
|
-
const invalidInputName = target.name || target.getAttribute('name')
|
|
265
|
-
if (invalidInputName === name) {
|
|
266
|
-
setFormSubmitted(true)
|
|
267
|
-
// Trigger validation when form is submitted
|
|
268
|
-
validateErrors()
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
document.addEventListener('invalid', handleInvalid, true)
|
|
274
|
-
|
|
275
|
-
return () => {
|
|
276
|
-
document.removeEventListener('invalid', handleInvalid, true)
|
|
277
|
-
}
|
|
278
|
-
}, [name, inputValue])
|
|
279
|
-
|
|
280
230
|
/*
|
|
281
231
|
useImperativeHandle exposes the kit's input element to a parent component via a ref.
|
|
282
232
|
See the Playbook docs for use cases.
|
|
@@ -288,11 +238,6 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
|
|
|
288
238
|
setInputValue("")
|
|
289
239
|
setError("")
|
|
290
240
|
setHasTyped(false)
|
|
291
|
-
setFormSubmitted(false)
|
|
292
|
-
// Only clear validation state if field was required
|
|
293
|
-
if (required) {
|
|
294
|
-
updateValidationState(false)
|
|
295
|
-
}
|
|
296
241
|
},
|
|
297
242
|
inputNode() {
|
|
298
243
|
return inputRef.current
|
|
@@ -302,15 +247,13 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
|
|
|
302
247
|
// Run validation and return error message or true
|
|
303
248
|
const isEmpty = !inputValue || inputValue.trim() === ''
|
|
304
249
|
|
|
305
|
-
if (required && isEmpty) {
|
|
306
|
-
setError('Missing phone number')
|
|
307
|
-
setFormSubmitted(true)
|
|
308
|
-
return 'Missing phone number'
|
|
309
|
-
}
|
|
310
|
-
|
|
311
250
|
if (isEmpty) {
|
|
312
|
-
|
|
313
|
-
|
|
251
|
+
// Show missing phone number error
|
|
252
|
+
const errorMessage = 'Missing phone number'
|
|
253
|
+
setError(errorMessage)
|
|
254
|
+
setHasTyped(true)
|
|
255
|
+
// Only return error for React Hook Form if field is required
|
|
256
|
+
return required ? errorMessage : true
|
|
314
257
|
}
|
|
315
258
|
|
|
316
259
|
if (!itiRef.current) {
|
|
@@ -323,7 +266,6 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
|
|
|
323
266
|
const countryName = itiRef.current.getSelectedCountryData().name
|
|
324
267
|
const errorMessage = `Invalid ${countryName} phone number (repeat country code)`
|
|
325
268
|
setError(errorMessage)
|
|
326
|
-
setFormSubmitted(true)
|
|
327
269
|
setHasTyped(true)
|
|
328
270
|
return errorMessage
|
|
329
271
|
}
|
|
@@ -333,7 +275,6 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
|
|
|
333
275
|
const countryName = itiRef.current.getSelectedCountryData().name
|
|
334
276
|
const errorMessage = `Invalid ${countryName} phone number (enter numbers only)`
|
|
335
277
|
setError(errorMessage)
|
|
336
|
-
setFormSubmitted(true)
|
|
337
278
|
setHasTyped(true)
|
|
338
279
|
return errorMessage
|
|
339
280
|
}
|
|
@@ -354,9 +295,7 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
|
|
|
354
295
|
errorMessage = `Invalid ${countryName} phone number`
|
|
355
296
|
}
|
|
356
297
|
|
|
357
|
-
// Set the error state so the validation attribute gets added
|
|
358
298
|
setError(errorMessage)
|
|
359
|
-
setFormSubmitted(true)
|
|
360
299
|
setHasTyped(true)
|
|
361
300
|
|
|
362
301
|
return errorMessage
|
|
@@ -376,12 +315,6 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
|
|
|
376
315
|
const handleOnChange = (evt: React.ChangeEvent<HTMLInputElement>) => {
|
|
377
316
|
if (!hasTyped) setHasTyped(true)
|
|
378
317
|
setInputValue(evt.target.value)
|
|
379
|
-
|
|
380
|
-
// Reset form submitted state when user types
|
|
381
|
-
if (formSubmitted) {
|
|
382
|
-
setFormSubmitted(false)
|
|
383
|
-
}
|
|
384
|
-
|
|
385
318
|
let phoneNumberData
|
|
386
319
|
if (formatAsYouType) {
|
|
387
320
|
const formattedPhoneNumberData = getCurrentSelectedData(itiRef.current, evt.target.value)
|
|
@@ -408,10 +341,6 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
|
|
|
408
341
|
}
|
|
409
342
|
|
|
410
343
|
isValid(itiRef.current.isValidNumber())
|
|
411
|
-
|
|
412
|
-
// Trigger validation after onChange for React Hook Form
|
|
413
|
-
// This ensures validation state is up-to-date
|
|
414
|
-
setTimeout(() => validateErrors(), 0)
|
|
415
344
|
}
|
|
416
345
|
|
|
417
346
|
// Separating Concerns as React Docs Recommend
|
|
@@ -470,7 +399,7 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
|
|
|
470
399
|
dark,
|
|
471
400
|
"data-phone-number": JSON.stringify(selectedData),
|
|
472
401
|
disabled,
|
|
473
|
-
error:
|
|
402
|
+
error: hasTyped ? error : props.error,
|
|
474
403
|
type: 'tel',
|
|
475
404
|
id,
|
|
476
405
|
label,
|
|
@@ -480,10 +409,7 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
|
|
|
480
409
|
value: inputValue
|
|
481
410
|
}
|
|
482
411
|
|
|
483
|
-
let wrapperProps: Record<string, unknown> = {
|
|
484
|
-
className: classes,
|
|
485
|
-
ref: wrapperRef
|
|
486
|
-
}
|
|
412
|
+
let wrapperProps: Record<string, unknown> = { className: classes }
|
|
487
413
|
|
|
488
414
|
if (!isEmpty(aria)) textInputProps = {...textInputProps, ...ariaProps}
|
|
489
415
|
if (!isEmpty(data)) wrapperProps = {...wrapperProps, ...dataProps}
|
|
@@ -140,10 +140,14 @@ const TextInput = (props: TextInputProps, ref: React.LegacyRef<HTMLInputElement>
|
|
|
140
140
|
formattedValue = value
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
+
const errorId = error ? `${id}-error` : undefined
|
|
144
|
+
|
|
143
145
|
const textInput = (
|
|
144
146
|
childInput ? React.cloneElement(children, { className: "text_input" }) :
|
|
145
147
|
(<input
|
|
146
148
|
{...domSafeProps(props)}
|
|
149
|
+
aria-describedby={errorId}
|
|
150
|
+
aria-invalid={!!error}
|
|
147
151
|
autoComplete={typeof autoComplete === "string" ? autoComplete : ( autoComplete ? undefined : "off" )}
|
|
148
152
|
className="text_input"
|
|
149
153
|
disabled={disabled}
|
|
@@ -202,16 +206,20 @@ const TextInput = (props: TextInputProps, ref: React.LegacyRef<HTMLInputElement>
|
|
|
202
206
|
{...htmlProps}
|
|
203
207
|
className={css}
|
|
204
208
|
>
|
|
205
|
-
{label &&
|
|
206
|
-
<
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
209
|
+
{label && (
|
|
210
|
+
<label htmlFor={id}>
|
|
211
|
+
<Caption className="pb_text_input_kit_label"
|
|
212
|
+
text={label}
|
|
213
|
+
/>
|
|
214
|
+
</label>
|
|
215
|
+
)}
|
|
211
216
|
<div className={`${addOnCss} text_input_wrapper`}>
|
|
212
217
|
{render}
|
|
213
218
|
|
|
214
219
|
{error && <Body
|
|
220
|
+
aria={{ atomic: "true", live: "polite" }}
|
|
221
|
+
htmlOptions={{ role: "alert" }}
|
|
222
|
+
id={errorId}
|
|
215
223
|
status="negative"
|
|
216
224
|
text={error}
|
|
217
225
|
variant={null}
|
|
@@ -9,23 +9,27 @@
|
|
|
9
9
|
|
|
10
10
|
<%= pb_rails("text_input", props: {
|
|
11
11
|
label: "Last Name",
|
|
12
|
-
placeholder: "Enter last name"
|
|
12
|
+
placeholder: "Enter last name",
|
|
13
|
+
id: "last-name"
|
|
13
14
|
}) %>
|
|
14
15
|
|
|
15
16
|
<%= pb_rails("text_input", props: {
|
|
16
17
|
label: "Phone Number",
|
|
17
18
|
type: "phone",
|
|
18
|
-
placeholder: "Enter phone number"
|
|
19
|
+
placeholder: "Enter phone number",
|
|
20
|
+
id: "phone"
|
|
19
21
|
}) %>
|
|
20
22
|
|
|
21
23
|
<%= pb_rails("text_input", props: {
|
|
22
24
|
label: "Email Address",
|
|
23
25
|
type: "email",
|
|
24
|
-
placeholder: "Enter email address"
|
|
26
|
+
placeholder: "Enter email address",
|
|
27
|
+
id: "email"
|
|
25
28
|
}) %>
|
|
26
29
|
|
|
27
30
|
<%= pb_rails("text_input", props: {
|
|
28
31
|
label: "Zip Code",
|
|
29
32
|
type: "number",
|
|
30
|
-
placeholder: "Enter zip code"
|
|
33
|
+
placeholder: "Enter zip code",
|
|
34
|
+
id: "zip"
|
|
31
35
|
}) %>
|
|
@@ -38,6 +38,7 @@ const TextInputDefault = (props) => {
|
|
|
38
38
|
{...props}
|
|
39
39
|
/>
|
|
40
40
|
<TextInput
|
|
41
|
+
id="last-name"
|
|
41
42
|
label="Last Name"
|
|
42
43
|
name="lastName"
|
|
43
44
|
onChange={handleOnChangeFormField}
|
|
@@ -46,6 +47,7 @@ const TextInputDefault = (props) => {
|
|
|
46
47
|
{...props}
|
|
47
48
|
/>
|
|
48
49
|
<TextInput
|
|
50
|
+
id="phone"
|
|
49
51
|
label="Phone Number"
|
|
50
52
|
name="phone"
|
|
51
53
|
onChange={handleOnChangeFormField}
|
|
@@ -55,6 +57,7 @@ const TextInputDefault = (props) => {
|
|
|
55
57
|
{...props}
|
|
56
58
|
/>
|
|
57
59
|
<TextInput
|
|
60
|
+
id="email"
|
|
58
61
|
label="Email Address"
|
|
59
62
|
name="email"
|
|
60
63
|
onChange={handleOnChangeFormField}
|
|
@@ -64,6 +67,7 @@ const TextInputDefault = (props) => {
|
|
|
64
67
|
{...props}
|
|
65
68
|
/>
|
|
66
69
|
<TextInput
|
|
70
|
+
id="zip"
|
|
67
71
|
label="Zip Code"
|
|
68
72
|
name="zip"
|
|
69
73
|
onChange={handleOnChangeFormField}
|
|
@@ -84,6 +88,7 @@ const TextInputDefault = (props) => {
|
|
|
84
88
|
<br />
|
|
85
89
|
|
|
86
90
|
<TextInput
|
|
91
|
+
id="first-name"
|
|
87
92
|
label="First Name"
|
|
88
93
|
onChange={handleOnChangeFirstName}
|
|
89
94
|
placeholder="Enter first name"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Add an `id` to your Text Input so that clicking the label will move focus directly to the input.
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
<%= pb_content_tag(:div, id: nil ) do %>
|
|
2
2
|
<% if object.label.present? %>
|
|
3
|
+
<label for="<%= object.input_options[:id] || object.id %>" >
|
|
3
4
|
<%= pb_rails("caption", props: { text: object.label, dark: object.dark, classname: "pb_text_input_kit_label" }) %>
|
|
5
|
+
</label>
|
|
4
6
|
<% end %>
|
|
5
7
|
<%= content_tag(:div, class: "#{add_on_class} text_input_wrapper") do %>
|
|
6
8
|
<% if content.present? %>
|
|
@@ -15,7 +17,7 @@
|
|
|
15
17
|
<% else %>
|
|
16
18
|
<%= input_tag %>
|
|
17
19
|
<% end %>
|
|
18
|
-
<%= pb_rails("body", props: {dark: object.dark, status: "negative", text: object.error}) if object.error %>
|
|
20
|
+
<%= pb_rails("body", props: {dark: object.dark, status: "negative", text: object.error, id: object.error_id, aria: { atomic: "true", live: "polite" }, html_options: { role: "alert" }}) if object.error %>
|
|
19
21
|
<% end %>
|
|
20
22
|
<% end %>
|
|
21
23
|
|
|
@@ -64,10 +64,16 @@ module Playbook
|
|
|
64
64
|
"#{object.id}-sanitized" if id.present?
|
|
65
65
|
end
|
|
66
66
|
|
|
67
|
+
def error_id
|
|
68
|
+
"#{id}-error" if error.present?
|
|
69
|
+
end
|
|
70
|
+
|
|
67
71
|
private
|
|
68
72
|
|
|
69
73
|
def all_input_options
|
|
70
74
|
{
|
|
75
|
+
'aria-describedby': error.present? ? error_id : nil,
|
|
76
|
+
'aria-invalid': error.present?,
|
|
71
77
|
autocomplete: autocomplete == true ? nil : (autocomplete.presence || "off"),
|
|
72
78
|
class: "text_input #{input_options.dig(:classname) || ''}",
|
|
73
79
|
data: validation_data,
|
|
@@ -53,6 +53,8 @@ type TypeaheadProps = {
|
|
|
53
53
|
pillColor?: "primary" | "neutral" | "success" | "warning" | "error" | "info" | "data_1" | "data_2" | "data_3" | "data_4" | "data_5" | "data_6" | "data_7" | "data_8" | "windows" | "siding" | "roofing" | "doors" | "gutters" | "solar" | "insulation" | "accessories",
|
|
54
54
|
onChange?: any,
|
|
55
55
|
optionsByContext?: Record<string, Array<{ label: string; value?: string }>>
|
|
56
|
+
required?: boolean,
|
|
57
|
+
validation?: { message: string },
|
|
56
58
|
searchContextSelector?: string,
|
|
57
59
|
clearOnContextChange?: boolean,
|
|
58
60
|
preserveSearchInput?: boolean,
|
|
@@ -94,12 +96,16 @@ const Typeahead = forwardRef<HTMLInputElement, TypeaheadProps>(({
|
|
|
94
96
|
onChange,
|
|
95
97
|
optionsByContext = {},
|
|
96
98
|
searchContextSelector,
|
|
99
|
+
required = false,
|
|
100
|
+
validation,
|
|
97
101
|
clearOnContextChange = false,
|
|
98
102
|
preserveSearchInput = false, // Default to false to maintain backward compatibility
|
|
99
103
|
...props
|
|
100
104
|
}: TypeaheadProps) => {
|
|
101
105
|
// State to manage the input value when preserveSearchInput is true
|
|
102
106
|
const [inputValue, setInputValue] = useState("")
|
|
107
|
+
// State to track if form has been submitted to control validation display for react rendered rails kit
|
|
108
|
+
const [formSubmitted, setFormSubmitted] = useState(false)
|
|
103
109
|
|
|
104
110
|
// If preserveSearchInput is true, we need to control the input value
|
|
105
111
|
const handleInputChange = preserveSearchInput
|
|
@@ -135,6 +141,7 @@ const Typeahead = forwardRef<HTMLInputElement, TypeaheadProps>(({
|
|
|
135
141
|
|
|
136
142
|
const selectProps = {
|
|
137
143
|
cacheOptions: true,
|
|
144
|
+
required,
|
|
138
145
|
components: {
|
|
139
146
|
Control,
|
|
140
147
|
ClearIndicator,
|
|
@@ -170,6 +177,27 @@ const Typeahead = forwardRef<HTMLInputElement, TypeaheadProps>(({
|
|
|
170
177
|
|
|
171
178
|
const [contextValue, setContextValue] = useState("")
|
|
172
179
|
|
|
180
|
+
// Add listener for form validation to track when validation should be shown (needed for react rendered rails kit)
|
|
181
|
+
useEffect(() => {
|
|
182
|
+
const handleInvalid = (event: Event) => {
|
|
183
|
+
const target = event.target as HTMLInputElement
|
|
184
|
+
const typeaheadContainer = target.closest('[data-pb-react-component="Typeahead"]')
|
|
185
|
+
|
|
186
|
+
if (typeaheadContainer) {
|
|
187
|
+
// Check if this invalid event is specifically for our typeahead by comparing names so we do not have to require ids
|
|
188
|
+
const invalidInputName = target.name || target.getAttribute('name')
|
|
189
|
+
if (invalidInputName === name) {
|
|
190
|
+
setFormSubmitted(true)
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
document.addEventListener('invalid', handleInvalid, true)
|
|
195
|
+
|
|
196
|
+
return () => {
|
|
197
|
+
document.removeEventListener('invalid', handleInvalid, true)
|
|
198
|
+
}
|
|
199
|
+
}, [name])
|
|
200
|
+
|
|
173
201
|
// Add listener for clearing
|
|
174
202
|
useEffect(() => {
|
|
175
203
|
const handleClear = () => {
|
|
@@ -230,6 +258,11 @@ const Typeahead = forwardRef<HTMLInputElement, TypeaheadProps>(({
|
|
|
230
258
|
}
|
|
231
259
|
}
|
|
232
260
|
|
|
261
|
+
// Reset form submitted state when a selection is made (this is all for react rendered rails kit)
|
|
262
|
+
if (action === 'select-option') {
|
|
263
|
+
setFormSubmitted(false)
|
|
264
|
+
}
|
|
265
|
+
|
|
233
266
|
// If a value is selected and we're preserving input on blur, clear the input
|
|
234
267
|
if (action === 'select-option' && preserveSearchInput) {
|
|
235
268
|
setInputValue('')
|
|
@@ -268,6 +301,11 @@ const Typeahead = forwardRef<HTMLInputElement, TypeaheadProps>(({
|
|
|
268
301
|
|
|
269
302
|
const inlineClass = selectProps.inline ? 'inline' : null
|
|
270
303
|
|
|
304
|
+
const shouldShowValidationError = required &&
|
|
305
|
+
formSubmitted
|
|
306
|
+
|
|
307
|
+
const errorDisplay = error || (shouldShowValidationError ? validation?.message || "Please fill out this field." : "")
|
|
308
|
+
|
|
271
309
|
return (
|
|
272
310
|
<div
|
|
273
311
|
{...dataProps}
|
|
@@ -276,7 +314,7 @@ const Typeahead = forwardRef<HTMLInputElement, TypeaheadProps>(({
|
|
|
276
314
|
>
|
|
277
315
|
<Tag
|
|
278
316
|
classNamePrefix="typeahead-kit-select"
|
|
279
|
-
error={
|
|
317
|
+
error={errorDisplay}
|
|
280
318
|
isDisabled={disabled}
|
|
281
319
|
onChange={handleOnChange}
|
|
282
320
|
{...selectProps}
|
|
@@ -101,6 +101,8 @@ module Playbook
|
|
|
101
101
|
plusIcon: plus_icon,
|
|
102
102
|
truncate: truncate,
|
|
103
103
|
wrapped: wrapped,
|
|
104
|
+
required: required,
|
|
105
|
+
validation: validation,
|
|
104
106
|
searchContextSelector: search_context_selector,
|
|
105
107
|
optionsByContext: options_by_context,
|
|
106
108
|
clearOnContextChange: clear_on_context_change,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx,Fragment,jsxs}from"react/jsx-runtime";import{useState,useEffect}from"react";import{d as buildAriaProps,e as buildDataProps,f as buildHtmlProps,H as HighchartsReact,g as Highcharts,h as classnames,i as globalProps,j as HighchartsMore,S as SolidGauge,k as buildCss}from"./_typeahead-CfKPIYmd.js";import{c as colors,h as highchartsTheme,m as merge,a as highchartsDarkTheme,t as typography}from"./lib-QZuu1ltS.js";const mapColors=array=>{const regex=/(data)\-[1-8]/;const newArray=array.map((item=>regex.test(item)?`${colors[`data_${item[item.length-1]}`]}`:item));return newArray};const BarGraph=({aria:aria={},data:data={},align:align="center",axisTitle:axisTitle,dark:dark=false,chartData:chartData,className:className="pb_bar_graph",colors:colors2,htmlOptions:htmlOptions={},customOptions:customOptions={},axisFormat:axisFormat,id:id,pointStart:pointStart,stacking:stacking,subTitle:subTitle,type:type="column",title:title="Title",xAxisCategories:xAxisCategories,yAxisMin:yAxisMin,yAxisMax:yAxisMax,legend:legend=false,toggleLegendClick:toggleLegendClick=true,height:height,layout:layout="horizontal",verticalAlign:verticalAlign="bottom",x:x=0,y:y=0,...props})=>{const ariaProps=buildAriaProps(aria);const dataProps=buildDataProps(data);const htmlProps=buildHtmlProps(htmlOptions);const setupTheme=()=>{dark?Highcharts.setOptions(highchartsDarkTheme):Highcharts.setOptions(highchartsTheme)};setupTheme();const staticOptions={title:{text:title},chart:{height:height,type:type},subtitle:{text:subTitle},yAxis:[{labels:{format:typeof axisFormat==="string"?axisFormat:axisFormat&&axisFormat[0]?axisFormat[0].format:""},min:yAxisMin,max:yAxisMax,opposite:false,title:{text:Array.isArray(axisTitle)?axisTitle.length>0?axisTitle[0].name:null:axisTitle},plotLines:typeof yAxisMin!=="undefined"&&yAxisMin!==null?[]:[{value:0,zIndex:10,color:"#E4E8F0"}]}],xAxis:{categories:xAxisCategories},legend:{enabled:legend,align:align,verticalAlign:verticalAlign,layout:layout,x:x,y:y},colors:colors2!==void 0&&colors2.length>0?mapColors(colors2):highchartsTheme.colors,plotOptions:{series:{stacking:stacking,pointStart:pointStart,borderWidth:stacking?0:"",events:{},dataLabels:{enabled:false}}},series:chartData,credits:false};if(Array.isArray(axisTitle)&&axisTitle.length>1&&axisTitle[1].name){staticOptions.yAxis.push({labels:{format:typeof axisFormat==="string"?axisFormat:axisFormat[1].format},min:yAxisMin,max:yAxisMax,opposite:true,title:{text:axisTitle[1].name},plotLines:typeof yAxisMin!=="undefined"&&yAxisMin!==null?[]:[{value:0,zIndex:10,color:"#E4E8F0"}]})}if(!toggleLegendClick){staticOptions.plotOptions.series.events={legendItemClick:()=>false}}const filteredProps={...props};delete filteredProps.verticalAlign;const[options,setOptions]=useState({});useEffect((()=>{setOptions(merge(staticOptions,customOptions))}),[chartData]);return jsx(HighchartsReact,{containerProps:{className:classnames(globalProps(filteredProps),className),id:id,...ariaProps,...dataProps,...htmlProps},highcharts:Highcharts,options:options})};const alignBlockElement=event=>{const itemToMove=document.querySelector(`#wrapper-circle-chart-${event.target.renderTo.id} .pb-circle-chart-block`);const chartContainer=document.querySelector(`#${event.target.renderTo.id}`);if(itemToMove!==null&&chartContainer!==null){itemToMove.style.height=`${event.target.chartHeight}px`;itemToMove.style.width=`${event.target.chartWidth}px`;if(chartContainer.firstChild!==null){chartContainer.firstChild.before(itemToMove)}}};const CircleChart=({align:align="center",aria:aria={},rounded:rounded=false,borderColor:borderColor=(rounded?null:""),borderWidth:borderWidth=(rounded?20:null),chartData:chartData,children:children,className:className,colors:colors2=[],customOptions:customOptions={},dark:dark=false,data:data={},dataLabelHtml:dataLabelHtml="<div>{point.name}</div>",dataLabels:dataLabels=false,height:height,htmlOptions:htmlOptions={},id:id,innerSize:innerSize="md",legend:legend=false,maxPointSize:maxPointSize=null,minPointSize:minPointSize=null,startAngle:startAngle=null,style:style="pie",title:title,tooltipHtml:tooltipHtml,useHtml:useHtml=false,zMin:zMin=null,layout:layout="horizontal",verticalAlign:verticalAlign="bottom",x:x=0,y:y=0,...props})=>{const ariaProps=buildAriaProps(aria);const dataProps=buildDataProps(data);const htmlProps=buildHtmlProps(htmlOptions);HighchartsMore(Highcharts);const setupTheme=()=>{dark?Highcharts.setOptions(highchartsDarkTheme):Highcharts.setOptions(highchartsTheme)};setupTheme();Highcharts.setOptions({tooltip:{headerFormat:null,pointFormat:tooltipHtml?tooltipHtml:'<span style="font-weight: bold; color:{point.color};">●</span>{point.name}: <b>{point.y}</b>',useHTML:useHtml}});const innerSizes={sm:"35%",md:"50%",lg:"85%",none:"0%"};const innerSizeFormat=size=>innerSizes[size];const filteredProps={...props};delete filteredProps.verticalAlign;const[options,setOptions]=useState({});useEffect((()=>{const formattedChartData=chartData.map((obj=>{obj.y=obj.value;delete obj.value;return obj}));const staticOptions={title:{text:title},chart:{height:height,type:style,events:{render:event=>alignBlockElement(event),redraw:event=>alignBlockElement(event)}},legend:{align:align,verticalAlign:verticalAlign,layout:layout,x:x,y:y},plotOptions:{pie:{colors:colors2.length>0?mapColors(colors2):highchartsTheme.colors,dataLabels:{enabled:dataLabels,connectorShape:"straight",connectorWidth:3,format:dataLabelHtml},showInLegend:legend}},series:[{minPointSize:minPointSize,maxPointSize:maxPointSize,innerSize:borderWidth==20?"100%":innerSizeFormat(innerSize),data:formattedChartData,zMin:zMin,startAngle:startAngle,borderWidth:borderWidth,borderColor:borderColor}],credits:false};setOptions(merge(staticOptions,customOptions))}),[chartData]);return jsx(Fragment,{children:children?jsxs("div",{id:`wrapper-circle-chart-${id}`,children:[jsx(HighchartsReact,{containerProps:{className:classnames("pb_circle_chart",globalProps(filteredProps)),id:id,...ariaProps,...dataProps,...htmlProps},highcharts:Highcharts,options:options}),jsx("div",{className:"pb-circle-chart-block",children:children})]}):jsx(HighchartsReact,{containerProps:{className:classnames("pb_circle_chart",globalProps(filteredProps)),id:id,...ariaProps,...dataProps,...htmlProps},highcharts:Highcharts,options:options})})};const Gauge=({aria:aria={},chartData:chartData,customOptions:customOptions={},dark:dark=false,data:data={},disableAnimation:disableAnimation=false,fullCircle:fullCircle=false,height:height=null,htmlOptions:htmlOptions={},id:id,max:max=100,min:min=0,prefix:prefix="",showLabels:showLabels=false,style:style="solidgauge",suffix:suffix="",title:title="",tooltipHtml:tooltipHtml='<span style="font-weight: bold; color:{point.color};">●</span>{point.name}: <b>{point.y}</b>',colors:colors$1=[],minorTickInterval:minorTickInterval=null,circumference:circumference=(fullCircle?[0,360]:[-100,100]),...props})=>{const ariaProps=buildAriaProps(aria);const dataProps=buildDataProps(data);const htmlProps=buildHtmlProps(htmlOptions);HighchartsMore(Highcharts);SolidGauge(Highcharts);const setupTheme=()=>{dark?Highcharts.setOptions(highchartsDarkTheme):Highcharts.setOptions(highchartsTheme)};setupTheme();Highcharts.setOptions({tooltip:{pointFormat:tooltipHtml,followPointer:true}});const css=buildCss({pb_gauge_kit:true});const[options,setOptions]=useState({});useEffect((()=>{const formattedChartData=chartData.map((obj=>{obj.y=obj.value;delete obj.value;return obj}));const staticOptions={chart:{events:{load(){setTimeout(this.reflow.bind(this),0)}},type:style,height:height},title:{text:title},yAxis:{min:min,max:max,lineWidth:0,tickWidth:0,minorTickInterval:minorTickInterval,tickAmount:2,tickPositions:[min,max],labels:{y:26,enabled:showLabels}},credits:false,series:[{data:formattedChartData}],pane:{center:["50%","50%"],size:"90%",startAngle:circumference[0],endAngle:circumference[1],background:{borderWidth:20,innerRadius:"90%",outerRadius:"90%",shape:"arc",className:"gauge-pane"}},colors:colors$1!==void 0&&colors$1.length>0?mapColors(colors$1):highchartsTheme.colors,plotOptions:{series:{animation:!disableAnimation},solidgauge:{borderColor:colors$1!==void 0&&colors$1.length===1?mapColors(colors$1).join():highchartsTheme.colors[0],borderWidth:20,radius:90,innerRadius:"90%",dataLabels:{borderWidth:0,color:colors.text_lt_default,enabled:true,format:`<span class="prefix${dark?" dark":""}">${prefix}</span><span class="fix${dark?" dark":""}">{y:,f}</span><span class="suffix${dark?" dark":""}">${suffix}</span>`,style:{fontFamily:typography.font_family_base,fontWeight:typography.regular,fontSize:typography.heading_2},y:-26}}}};setOptions(merge(staticOptions,customOptions));if(document.querySelector(".prefix")){document.querySelectorAll(".prefix").forEach((prefix2=>{prefix2.setAttribute("y","28")}));document.querySelectorAll(".fix").forEach((fix=>fix.setAttribute("y","38")))}}),[chartData]);return jsx(HighchartsReact,{containerProps:{className:classnames(css,globalProps(props)),id:id,...ariaProps,...dataProps,...htmlProps},highcharts:Highcharts,options:options})};const LineGraph=({aria:aria={},data:data={},align:align="center",className:className="pb_bar_graph",customOptions:customOptions={},dark:dark=false,gradient:gradient=false,type:type="line",htmlOptions:htmlOptions={},id:id,legend:legend=false,toggleLegendClick:toggleLegendClick=true,layout:layout="horizontal",verticalAlign:verticalAlign="bottom",x:x=0,y:y=0,axisTitle:axisTitle,xAxisCategories:xAxisCategories,yAxisMin:yAxisMin,yAxisMax:yAxisMax,chartData:chartData,pointStart:pointStart,subTitle:subTitle,title:title,height:height,colors:colors2=[],...props})=>{const ariaProps=buildAriaProps(aria);const dataProps=buildDataProps(data);const htmlProps=buildHtmlProps(htmlOptions);const setupTheme=()=>{dark?Highcharts.setOptions(highchartsDarkTheme):Highcharts.setOptions(highchartsTheme)};setupTheme();const staticOptions={title:{text:title},chart:{height:height,type:type},subtitle:{text:subTitle},yAxis:{min:yAxisMin,max:yAxisMax,title:{text:axisTitle}},xAxis:{categories:xAxisCategories},legend:{enabled:legend,align:align,verticalAlign:verticalAlign,layout:layout,x:x,y:y},colors:colors2!==void 0&&colors2.length>0?mapColors(colors2):highchartsTheme.colors,plotOptions:{series:{pointStart:pointStart,events:{},dataLabels:{enabled:false}}},series:chartData,credits:false};if(!toggleLegendClick){staticOptions.plotOptions.series.events={legendItemClick:()=>false}}const filteredProps={...props};delete filteredProps.verticalAlign;const[options,setOptions]=useState({});useEffect((()=>{setOptions(merge(staticOptions,customOptions))}),[chartData]);return jsx(HighchartsReact,{containerProps:{className:classnames(globalProps(filteredProps),className),id:id,...ariaProps,...dataProps,...htmlProps},highcharts:Highcharts,options:options})};export{BarGraph as B,CircleChart as C,Gauge as G,LineGraph as L};
|
|
1
|
+
import{jsx,Fragment,jsxs}from"react/jsx-runtime";import{useState,useEffect}from"react";import{d as buildAriaProps,e as buildDataProps,f as buildHtmlProps,H as HighchartsReact,g as Highcharts,h as classnames,i as globalProps,j as HighchartsMore,S as SolidGauge,k as buildCss}from"./_typeahead-BBamAvDm.js";import{c as colors,h as highchartsTheme,m as merge,a as highchartsDarkTheme,t as typography}from"./lib-QZuu1ltS.js";const mapColors=array=>{const regex=/(data)\-[1-8]/;const newArray=array.map((item=>regex.test(item)?`${colors[`data_${item[item.length-1]}`]}`:item));return newArray};const BarGraph=({aria:aria={},data:data={},align:align="center",axisTitle:axisTitle,dark:dark=false,chartData:chartData,className:className="pb_bar_graph",colors:colors2,htmlOptions:htmlOptions={},customOptions:customOptions={},axisFormat:axisFormat,id:id,pointStart:pointStart,stacking:stacking,subTitle:subTitle,type:type="column",title:title="Title",xAxisCategories:xAxisCategories,yAxisMin:yAxisMin,yAxisMax:yAxisMax,legend:legend=false,toggleLegendClick:toggleLegendClick=true,height:height,layout:layout="horizontal",verticalAlign:verticalAlign="bottom",x:x=0,y:y=0,...props})=>{const ariaProps=buildAriaProps(aria);const dataProps=buildDataProps(data);const htmlProps=buildHtmlProps(htmlOptions);const setupTheme=()=>{dark?Highcharts.setOptions(highchartsDarkTheme):Highcharts.setOptions(highchartsTheme)};setupTheme();const staticOptions={title:{text:title},chart:{height:height,type:type},subtitle:{text:subTitle},yAxis:[{labels:{format:typeof axisFormat==="string"?axisFormat:axisFormat&&axisFormat[0]?axisFormat[0].format:""},min:yAxisMin,max:yAxisMax,opposite:false,title:{text:Array.isArray(axisTitle)?axisTitle.length>0?axisTitle[0].name:null:axisTitle},plotLines:typeof yAxisMin!=="undefined"&&yAxisMin!==null?[]:[{value:0,zIndex:10,color:"#E4E8F0"}]}],xAxis:{categories:xAxisCategories},legend:{enabled:legend,align:align,verticalAlign:verticalAlign,layout:layout,x:x,y:y},colors:colors2!==void 0&&colors2.length>0?mapColors(colors2):highchartsTheme.colors,plotOptions:{series:{stacking:stacking,pointStart:pointStart,borderWidth:stacking?0:"",events:{},dataLabels:{enabled:false}}},series:chartData,credits:false};if(Array.isArray(axisTitle)&&axisTitle.length>1&&axisTitle[1].name){staticOptions.yAxis.push({labels:{format:typeof axisFormat==="string"?axisFormat:axisFormat[1].format},min:yAxisMin,max:yAxisMax,opposite:true,title:{text:axisTitle[1].name},plotLines:typeof yAxisMin!=="undefined"&&yAxisMin!==null?[]:[{value:0,zIndex:10,color:"#E4E8F0"}]})}if(!toggleLegendClick){staticOptions.plotOptions.series.events={legendItemClick:()=>false}}const filteredProps={...props};delete filteredProps.verticalAlign;const[options,setOptions]=useState({});useEffect((()=>{setOptions(merge(staticOptions,customOptions))}),[chartData]);return jsx(HighchartsReact,{containerProps:{className:classnames(globalProps(filteredProps),className),id:id,...ariaProps,...dataProps,...htmlProps},highcharts:Highcharts,options:options})};const alignBlockElement=event=>{const itemToMove=document.querySelector(`#wrapper-circle-chart-${event.target.renderTo.id} .pb-circle-chart-block`);const chartContainer=document.querySelector(`#${event.target.renderTo.id}`);if(itemToMove!==null&&chartContainer!==null){itemToMove.style.height=`${event.target.chartHeight}px`;itemToMove.style.width=`${event.target.chartWidth}px`;if(chartContainer.firstChild!==null){chartContainer.firstChild.before(itemToMove)}}};const CircleChart=({align:align="center",aria:aria={},rounded:rounded=false,borderColor:borderColor=(rounded?null:""),borderWidth:borderWidth=(rounded?20:null),chartData:chartData,children:children,className:className,colors:colors2=[],customOptions:customOptions={},dark:dark=false,data:data={},dataLabelHtml:dataLabelHtml="<div>{point.name}</div>",dataLabels:dataLabels=false,height:height,htmlOptions:htmlOptions={},id:id,innerSize:innerSize="md",legend:legend=false,maxPointSize:maxPointSize=null,minPointSize:minPointSize=null,startAngle:startAngle=null,style:style="pie",title:title,tooltipHtml:tooltipHtml,useHtml:useHtml=false,zMin:zMin=null,layout:layout="horizontal",verticalAlign:verticalAlign="bottom",x:x=0,y:y=0,...props})=>{const ariaProps=buildAriaProps(aria);const dataProps=buildDataProps(data);const htmlProps=buildHtmlProps(htmlOptions);HighchartsMore(Highcharts);const setupTheme=()=>{dark?Highcharts.setOptions(highchartsDarkTheme):Highcharts.setOptions(highchartsTheme)};setupTheme();Highcharts.setOptions({tooltip:{headerFormat:null,pointFormat:tooltipHtml?tooltipHtml:'<span style="font-weight: bold; color:{point.color};">●</span>{point.name}: <b>{point.y}</b>',useHTML:useHtml}});const innerSizes={sm:"35%",md:"50%",lg:"85%",none:"0%"};const innerSizeFormat=size=>innerSizes[size];const filteredProps={...props};delete filteredProps.verticalAlign;const[options,setOptions]=useState({});useEffect((()=>{const formattedChartData=chartData.map((obj=>{obj.y=obj.value;delete obj.value;return obj}));const staticOptions={title:{text:title},chart:{height:height,type:style,events:{render:event=>alignBlockElement(event),redraw:event=>alignBlockElement(event)}},legend:{align:align,verticalAlign:verticalAlign,layout:layout,x:x,y:y},plotOptions:{pie:{colors:colors2.length>0?mapColors(colors2):highchartsTheme.colors,dataLabels:{enabled:dataLabels,connectorShape:"straight",connectorWidth:3,format:dataLabelHtml},showInLegend:legend}},series:[{minPointSize:minPointSize,maxPointSize:maxPointSize,innerSize:borderWidth==20?"100%":innerSizeFormat(innerSize),data:formattedChartData,zMin:zMin,startAngle:startAngle,borderWidth:borderWidth,borderColor:borderColor}],credits:false};setOptions(merge(staticOptions,customOptions))}),[chartData]);return jsx(Fragment,{children:children?jsxs("div",{id:`wrapper-circle-chart-${id}`,children:[jsx(HighchartsReact,{containerProps:{className:classnames("pb_circle_chart",globalProps(filteredProps)),id:id,...ariaProps,...dataProps,...htmlProps},highcharts:Highcharts,options:options}),jsx("div",{className:"pb-circle-chart-block",children:children})]}):jsx(HighchartsReact,{containerProps:{className:classnames("pb_circle_chart",globalProps(filteredProps)),id:id,...ariaProps,...dataProps,...htmlProps},highcharts:Highcharts,options:options})})};const Gauge=({aria:aria={},chartData:chartData,customOptions:customOptions={},dark:dark=false,data:data={},disableAnimation:disableAnimation=false,fullCircle:fullCircle=false,height:height=null,htmlOptions:htmlOptions={},id:id,max:max=100,min:min=0,prefix:prefix="",showLabels:showLabels=false,style:style="solidgauge",suffix:suffix="",title:title="",tooltipHtml:tooltipHtml='<span style="font-weight: bold; color:{point.color};">●</span>{point.name}: <b>{point.y}</b>',colors:colors$1=[],minorTickInterval:minorTickInterval=null,circumference:circumference=(fullCircle?[0,360]:[-100,100]),...props})=>{const ariaProps=buildAriaProps(aria);const dataProps=buildDataProps(data);const htmlProps=buildHtmlProps(htmlOptions);HighchartsMore(Highcharts);SolidGauge(Highcharts);const setupTheme=()=>{dark?Highcharts.setOptions(highchartsDarkTheme):Highcharts.setOptions(highchartsTheme)};setupTheme();Highcharts.setOptions({tooltip:{pointFormat:tooltipHtml,followPointer:true}});const css=buildCss({pb_gauge_kit:true});const[options,setOptions]=useState({});useEffect((()=>{const formattedChartData=chartData.map((obj=>{obj.y=obj.value;delete obj.value;return obj}));const staticOptions={chart:{events:{load(){setTimeout(this.reflow.bind(this),0)}},type:style,height:height},title:{text:title},yAxis:{min:min,max:max,lineWidth:0,tickWidth:0,minorTickInterval:minorTickInterval,tickAmount:2,tickPositions:[min,max],labels:{y:26,enabled:showLabels}},credits:false,series:[{data:formattedChartData}],pane:{center:["50%","50%"],size:"90%",startAngle:circumference[0],endAngle:circumference[1],background:{borderWidth:20,innerRadius:"90%",outerRadius:"90%",shape:"arc",className:"gauge-pane"}},colors:colors$1!==void 0&&colors$1.length>0?mapColors(colors$1):highchartsTheme.colors,plotOptions:{series:{animation:!disableAnimation},solidgauge:{borderColor:colors$1!==void 0&&colors$1.length===1?mapColors(colors$1).join():highchartsTheme.colors[0],borderWidth:20,radius:90,innerRadius:"90%",dataLabels:{borderWidth:0,color:colors.text_lt_default,enabled:true,format:`<span class="prefix${dark?" dark":""}">${prefix}</span><span class="fix${dark?" dark":""}">{y:,f}</span><span class="suffix${dark?" dark":""}">${suffix}</span>`,style:{fontFamily:typography.font_family_base,fontWeight:typography.regular,fontSize:typography.heading_2},y:-26}}}};setOptions(merge(staticOptions,customOptions));if(document.querySelector(".prefix")){document.querySelectorAll(".prefix").forEach((prefix2=>{prefix2.setAttribute("y","28")}));document.querySelectorAll(".fix").forEach((fix=>fix.setAttribute("y","38")))}}),[chartData]);return jsx(HighchartsReact,{containerProps:{className:classnames(css,globalProps(props)),id:id,...ariaProps,...dataProps,...htmlProps},highcharts:Highcharts,options:options})};const LineGraph=({aria:aria={},data:data={},align:align="center",className:className="pb_bar_graph",customOptions:customOptions={},dark:dark=false,gradient:gradient=false,type:type="line",htmlOptions:htmlOptions={},id:id,legend:legend=false,toggleLegendClick:toggleLegendClick=true,layout:layout="horizontal",verticalAlign:verticalAlign="bottom",x:x=0,y:y=0,axisTitle:axisTitle,xAxisCategories:xAxisCategories,yAxisMin:yAxisMin,yAxisMax:yAxisMax,chartData:chartData,pointStart:pointStart,subTitle:subTitle,title:title,height:height,colors:colors2=[],...props})=>{const ariaProps=buildAriaProps(aria);const dataProps=buildDataProps(data);const htmlProps=buildHtmlProps(htmlOptions);const setupTheme=()=>{dark?Highcharts.setOptions(highchartsDarkTheme):Highcharts.setOptions(highchartsTheme)};setupTheme();const staticOptions={title:{text:title},chart:{height:height,type:type},subtitle:{text:subTitle},yAxis:{min:yAxisMin,max:yAxisMax,title:{text:axisTitle}},xAxis:{categories:xAxisCategories},legend:{enabled:legend,align:align,verticalAlign:verticalAlign,layout:layout,x:x,y:y},colors:colors2!==void 0&&colors2.length>0?mapColors(colors2):highchartsTheme.colors,plotOptions:{series:{pointStart:pointStart,events:{},dataLabels:{enabled:false}}},series:chartData,credits:false};if(!toggleLegendClick){staticOptions.plotOptions.series.events={legendItemClick:()=>false}}const filteredProps={...props};delete filteredProps.verticalAlign;const[options,setOptions]=useState({});useEffect((()=>{setOptions(merge(staticOptions,customOptions))}),[chartData]);return jsx(HighchartsReact,{containerProps:{className:classnames(globalProps(filteredProps),className),id:id,...ariaProps,...dataProps,...htmlProps},highcharts:Highcharts,options:options})};export{BarGraph as B,CircleChart as C,Gauge as G,LineGraph as L};
|