playbook_ui 15.3.0.pre.alpha.play2541phonenumberkitvalidation12084 → 15.3.0.pre.alpha.play199912019

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 (40) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/pb_advanced_table/Components/RegularTableView.tsx +1 -2
  3. data/app/pb_kits/playbook/pb_advanced_table/advanced_table.test.jsx +0 -63
  4. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_background_control_rails.html.erb +0 -4
  5. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_background_control_rails.md +1 -1
  6. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_styling.jsx +1 -3
  7. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_styling.md +0 -2
  8. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_styling_column_headers.jsx +1 -1
  9. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_styling_rails.html.erb +0 -1
  10. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_styling_rails.md +0 -2
  11. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_padding_control.jsx +1 -9
  12. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_padding_control.md +1 -1
  13. data/app/pb_kits/playbook/pb_advanced_table/table_row.rb +2 -31
  14. data/app/pb_kits/playbook/pb_background/background.html.erb +2 -10
  15. data/app/pb_kits/playbook/pb_badge/_badge.tsx +3 -0
  16. data/app/pb_kits/playbook/pb_badge/badge.test.js +13 -0
  17. data/app/pb_kits/playbook/pb_currency/_currency.tsx +7 -20
  18. data/app/pb_kits/playbook/pb_currency/currency.rb +8 -35
  19. data/app/pb_kits/playbook/pb_currency/currency.test.js +0 -47
  20. data/app/pb_kits/playbook/pb_currency/docs/_currency_variants.html.erb +1 -1
  21. data/app/pb_kits/playbook/pb_currency/docs/_currency_variants.jsx +1 -1
  22. data/app/pb_kits/playbook/pb_form/pb_form_validation.js +11 -44
  23. data/app/pb_kits/playbook/pb_phone_number_input/_phone_number_input.tsx +17 -110
  24. data/app/pb_kits/playbook/pb_typeahead/_typeahead.scss +7 -0
  25. data/app/pb_kits/playbook/pb_typeahead/_typeahead.test.jsx +64 -1
  26. data/app/pb_kits/playbook/pb_typeahead/components/MultiValue.tsx +11 -1
  27. data/dist/chunks/{_line_graph-CZlP3Ci7.js → _line_graph-D-adVl2G.js} +1 -1
  28. data/dist/chunks/_typeahead-BM-vXmpm.js +6 -0
  29. data/dist/chunks/{_weekday_stacked-qGKMxoAo.js → _weekday_stacked-BQORBqJE.js} +2 -2
  30. data/dist/chunks/pb_form_validation-DebqlUKZ.js +1 -0
  31. data/dist/chunks/vendor.js +1 -1
  32. data/dist/playbook-doc.js +1 -1
  33. data/dist/playbook-rails-react-bindings.js +1 -1
  34. data/dist/playbook-rails.js +1 -1
  35. data/dist/playbook.css +1 -1
  36. data/lib/playbook/version.rb +1 -1
  37. metadata +6 -7
  38. data/app/pb_kits/playbook/pb_currency/docs/_currency_variants.md +0 -1
  39. data/dist/chunks/_typeahead-gfPOrCeR.js +0 -6
  40. data/dist/chunks/pb_form_validation-CbtOLNdG.js +0 -1
@@ -55,6 +55,7 @@ const formatToGlobalCountryName = (countryName: string) => {
55
55
 
56
56
  const formatAllCountries = () => {
57
57
  const countryData = intlTelInput.getCountryData()
58
+
58
59
  for (let i = 0; i < countryData.length; i++) {
59
60
  const country = countryData[i]
60
61
  country.name = formatToGlobalCountryName(country.name)
@@ -109,54 +110,18 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
109
110
 
110
111
  const inputRef = useRef<HTMLInputElement | null>(null)
111
112
  const itiRef = useRef<any>(null);
112
- const wrapperRef = useRef<HTMLDivElement | null>(null);
113
113
  const [inputValue, setInputValue] = useState(value)
114
114
  const [error, setError] = useState(props.error || "")
115
115
  const [dropDownIsOpen, setDropDownIsOpen] = useState(false)
116
116
  const [selectedData, setSelectedData] = useState()
117
117
  const [hasTyped, setHasTyped] = useState(false)
118
- const [formSubmitted, setFormSubmitted] = useState(false)
119
- const [hasStartedValidating, setHasStartedValidating] = useState(false)
120
-
121
- // Only sync initial error from props, not continuous updates
122
- // Once validation starts, internal validation takes over
123
- useEffect(() => {
124
- if (props.error && !hasStartedValidating) {
125
- setError(props.error)
126
- // If there's an initial error from props, mark as submitted so it shows
127
- if (props.error) {
128
- setFormSubmitted(true)
129
- }
130
- }
131
- }, [props.error, hasStartedValidating])
132
-
133
- // Function to update validation state on the wrapper element
134
- // Only applies when input is required
135
- const updateValidationState = (hasError: boolean) => {
136
- if (wrapperRef.current && required) {
137
- if (hasError) {
138
- wrapperRef.current.setAttribute('data-pb-phone-validation-error', 'true')
139
- } else {
140
- wrapperRef.current.removeAttribute('data-pb-phone-validation-error')
141
- }
142
- }
143
- }
144
-
145
- // Determine which error to display
146
- // Show internal errors on blur (hasTyped) or on form submission (formSubmitted)
147
- const shouldShowInternalError = (hasTyped || formSubmitted) && required && error
148
- const displayError = shouldShowInternalError ? error : ""
149
118
 
150
119
  useEffect(() => {
151
- const hasError = (error ?? '').length > 0
152
- if (hasError) {
120
+ if ((error ?? '').length > 0) {
153
121
  onValidate(false)
154
122
  } else {
155
123
  onValidate(true)
156
124
  }
157
-
158
- // Update validation state whenever error changes
159
- updateValidationState(hasError)
160
125
  }, [error, onValidate])
161
126
 
162
127
  const unformatNumber = (formattedNumber: any) => {
@@ -172,7 +137,6 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
172
137
 
173
138
  const validateTooLongNumber = (itiInit: any) => {
174
139
  if (!itiInit) return
175
-
176
140
  if (itiInit.getValidationError() === ValidationError.TooLong) {
177
141
  return showFormattedError('too long')
178
142
  } else {
@@ -182,11 +146,13 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
182
146
 
183
147
  const validateTooShortNumber = (itiInit: any) => {
184
148
  if (!itiInit) return
149
+
185
150
  // If field is empty, don't show "too short" error
186
151
  if (!inputValue || inputValue.trim() === '') {
187
152
  setError('')
188
153
  return false
189
154
  }
155
+
190
156
  if (itiInit.getValidationError() === ValidationError.TooShort) {
191
157
  return showFormattedError('too short')
192
158
  } else {
@@ -206,7 +172,7 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
206
172
  }
207
173
 
208
174
  const validateUnhandledError = (itiInit: any) => {
209
- if (!required || !itiInit) return
175
+ if (!itiInit) return
210
176
  if (itiInit.getValidationError() === ValidationError.SomethingWentWrong) {
211
177
  if (inputValue.length === 1) {
212
178
  return showFormattedError('too short')
@@ -218,6 +184,7 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
218
184
  }
219
185
  }
220
186
  }
187
+
221
188
  const validateMissingAreaCode = (itiInit: any) => {
222
189
  if (!itiInit) return
223
190
  if (itiInit.getValidationError() === ValidationError.MissingAreaCode) {
@@ -234,9 +201,8 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
234
201
  }
235
202
  }
236
203
 
237
- // Validation for required empty fields
238
204
  const validateRequiredField = () => {
239
- if (required && (!inputValue || inputValue.trim() === '')) {
205
+ if (!inputValue || inputValue.trim() === '') {
240
206
  setError('Missing phone number')
241
207
  return true
242
208
  }
@@ -244,24 +210,14 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
244
210
  }
245
211
 
246
212
  const validateErrors = () => {
247
- // Signal validation has started, so prop errors won't override internal validation
248
- if (!hasStartedValidating) {
249
- setHasStartedValidating(true)
250
- }
251
-
252
- // If field is empty, only show required field error if applicable
213
+ // If field is empty, show error message
253
214
  if (!inputValue || inputValue.trim() === '') {
254
215
  if (validateRequiredField()) return
255
- // Clear any existing errors if field is empty and not required
256
- if (!required) {
257
- setError('')
258
- }
259
216
  return
260
217
  }
261
218
 
262
- if (!hasTyped && !error) return
219
+ if (!hasTyped && !error) return
263
220
 
264
- // Run validation checks
265
221
  if (itiRef.current) isValid(itiRef.current.isValidNumber())
266
222
  if (validateOnlyNumbers(itiRef.current)) return
267
223
  if (validateTooLongNumber(itiRef.current)) return
@@ -271,29 +227,6 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
271
227
  if (validateRepeatCountryCode(itiRef.current)) return
272
228
  }
273
229
 
274
- // Add listener for form validation to track when validation should be shown
275
- useEffect(() => {
276
- const handleInvalid = (event: Event) => {
277
- const target = event.target as HTMLInputElement
278
- const phoneNumberContainer = target.closest('.pb_phone_number_input')
279
-
280
- if (phoneNumberContainer && phoneNumberContainer === wrapperRef.current) {
281
- const invalidInputName = target.name || target.getAttribute('name')
282
- if (invalidInputName === name) {
283
- setFormSubmitted(true)
284
- // Trigger validation when form is submitted
285
- validateErrors()
286
- }
287
- }
288
- }
289
-
290
- document.addEventListener('invalid', handleInvalid, true)
291
-
292
- return () => {
293
- document.removeEventListener('invalid', handleInvalid, true)
294
- }
295
- }, [name, inputValue])
296
-
297
230
  /*
298
231
  useImperativeHandle exposes the kit's input element to a parent component via a ref.
299
232
  See the Playbook docs for use cases.
@@ -305,12 +238,6 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
305
238
  setInputValue("")
306
239
  setError("")
307
240
  setHasTyped(false)
308
- setFormSubmitted(false)
309
- setHasStartedValidating(false)
310
- // Only clear validation state if field was required
311
- if (required) {
312
- updateValidationState(false)
313
- }
314
241
  },
315
242
  inputNode() {
316
243
  return inputRef.current
@@ -320,12 +247,6 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
320
247
  // Run validation and return error message or true
321
248
  const isEmpty = !inputValue || inputValue.trim() === ''
322
249
 
323
- if (required && isEmpty) {
324
- setError('Missing phone number')
325
- setFormSubmitted(true)
326
- return 'Missing phone number'
327
- }
328
-
329
250
  if (isEmpty) {
330
251
  // Show missing phone number error
331
252
  const errorMessage = 'Missing phone number'
@@ -345,7 +266,6 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
345
266
  const countryName = itiRef.current.getSelectedCountryData().name
346
267
  const errorMessage = `Invalid ${countryName} phone number (repeat country code)`
347
268
  setError(errorMessage)
348
- setFormSubmitted(true)
349
269
  setHasTyped(true)
350
270
  return errorMessage
351
271
  }
@@ -355,7 +275,6 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
355
275
  const countryName = itiRef.current.getSelectedCountryData().name
356
276
  const errorMessage = `Invalid ${countryName} phone number (enter numbers only)`
357
277
  setError(errorMessage)
358
- setFormSubmitted(true)
359
278
  setHasTyped(true)
360
279
  return errorMessage
361
280
  }
@@ -376,9 +295,7 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
376
295
  errorMessage = `Invalid ${countryName} phone number`
377
296
  }
378
297
 
379
- // Set the error state so the validation attribute gets added
380
298
  setError(errorMessage)
381
- setFormSubmitted(true)
382
299
  setHasTyped(true)
383
300
 
384
301
  return errorMessage
@@ -397,16 +314,11 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
397
314
 
398
315
  const handleOnChange = (evt: React.ChangeEvent<HTMLInputElement>) => {
399
316
  if (!hasTyped) setHasTyped(true)
400
- setInputValue(evt.target.value)
401
317
 
402
- // Reset form submitted state when user types
403
- if (formSubmitted) {
404
- setFormSubmitted(false)
405
- }
318
+ setInputValue(evt.target.value)
406
319
 
407
320
  let phoneNumberData
408
321
 
409
- // Handle formatAsYouType with input event
410
322
  if (formatAsYouType) {
411
323
  const formattedPhoneNumberData = getCurrentSelectedData(itiRef.current, evt.target.value)
412
324
  phoneNumberData = {...formattedPhoneNumberData, number: unformatNumber(formattedPhoneNumberData.number)}
@@ -417,15 +329,12 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
417
329
  setSelectedData(phoneNumberData)
418
330
  onChange(phoneNumberData)
419
331
  isValid(itiRef.current.isValidNumber())
420
-
421
- // Trigger validation after onChange for React Hook Form
422
- // This ensures validation state is up-to-date
423
- setTimeout(() => validateErrors(), 0)
424
332
  }
425
333
 
426
334
  // Separating Concerns as React Docs Recommend
427
335
  // This also Fixes things for our react_component rendering on the Rails Side
428
336
  useEffect(formatAllCountries, [])
337
+
429
338
  // If an initial country is not specified, the "globe" icon will show
430
339
  // Always set a country
431
340
  const fallbackCountry =
@@ -466,9 +375,9 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
466
375
  inputRef.current.addEventListener("open:countrydropdown", () => setDropDownIsOpen(true))
467
376
  inputRef.current.addEventListener("close:countrydropdown", () => setDropDownIsOpen(false))
468
377
 
469
- // Handle formatAsYouType with input event
470
- if (formatAsYouType) {
471
- inputRef.current.addEventListener("input", (evt: Event) => {
378
+ // Handle formatAsYouType with input event
379
+ if (formatAsYouType) {
380
+ inputRef.current.addEventListener("input", (evt: Event) => {
472
381
  const target = evt.target as HTMLInputElement
473
382
  const formattedValue = target.value
474
383
 
@@ -487,12 +396,13 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
487
396
  }
488
397
  }
489
398
  }, [])
399
+
490
400
  let textInputProps: {[key: string]: any} = {
491
401
  className: dropDownIsOpen ? 'dropdown_open' : '',
492
402
  dark,
493
403
  "data-phone-number": JSON.stringify(selectedData),
494
404
  disabled,
495
- error: hasTyped ? error : props.error || displayError,
405
+ error: hasTyped ? error : props.error,
496
406
  type: 'tel',
497
407
  id,
498
408
  label,
@@ -502,10 +412,7 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
502
412
  value: inputValue
503
413
  }
504
414
 
505
- let wrapperProps: Record<string, unknown> = {
506
- className: classes,
507
- ref: wrapperRef
508
- }
415
+ let wrapperProps: Record<string, unknown> = { className: classes }
509
416
 
510
417
  if (!isEmpty(aria)) textInputProps = {...textInputProps, ...ariaProps}
511
418
  if (!isEmpty(data)) wrapperProps = {...wrapperProps, ...dataProps}
@@ -165,6 +165,13 @@
165
165
  line-height: 16.5px;
166
166
  letter-spacing: normal;
167
167
  }
168
+
169
+ // Add focus indicator for multi-value pills
170
+ .pb_form_pill_or_badge_focused {
171
+ outline: $primary solid 2px;
172
+ outline-offset: -1px;
173
+ }
174
+
168
175
  &.inline {
169
176
  &:not(:hover) {
170
177
  .text_input {
@@ -212,4 +212,67 @@ test('typeahead with grouped options and defaultValue focus behavior', async ()
212
212
  const kit = screen.getByTestId('grouped-options-focus-test')
213
213
  const inputDiv = kit.querySelector(".typeahead-kit-select__single-value")
214
214
  expect(inputDiv).toHaveTextContent("Pink")
215
- })
215
+ })
216
+
217
+ test('multi-value pills have tabIndex for keyboard navigation', () => {
218
+ render(
219
+ <Typeahead
220
+ data={{ testid: 'pill-tabindex-test' }}
221
+ defaultValue={[options[0], options[1]]}
222
+ isMulti
223
+ options={options}
224
+ />
225
+ )
226
+
227
+ const kit = screen.getByTestId('pill-tabindex-test')
228
+ const pills = kit.querySelectorAll('.pb_form_pill_kit')
229
+
230
+ expect(pills.length).toBe(2)
231
+
232
+ pills.forEach(pill => {
233
+ expect(pill).toHaveAttribute('tabIndex', '0')
234
+ })
235
+ })
236
+
237
+ test('multi-value pills show focus indicator when focused', async () => {
238
+ render(
239
+ <Typeahead
240
+ data={{ testid: 'pill-focus-indicator-test' }}
241
+ defaultValue={[options[0], options[1], options[2]]}
242
+ isMulti
243
+ options={options}
244
+ />
245
+ )
246
+
247
+ const kit = screen.getByTestId('pill-focus-indicator-test')
248
+ const pills = kit.querySelectorAll('.pb_form_pill_kit')
249
+
250
+ expect(pills.length).toBe(3)
251
+
252
+ const firstPill = pills[0]
253
+ firstPill.focus()
254
+
255
+ expect(document.activeElement).toBe(firstPill)
256
+ })
257
+
258
+ test('multi-value badges have tabIndex and focus class when focused', () => {
259
+ render(
260
+ <Typeahead
261
+ data={{ testid: 'badge-focus-test' }}
262
+ defaultValue={[options[0], options[1]]}
263
+ isMulti
264
+ multiKit="badge"
265
+ options={options}
266
+ />
267
+ )
268
+
269
+ const kit = screen.getByTestId('badge-focus-test')
270
+ const badges = kit.querySelectorAll('.pb_badge_kit_primary')
271
+
272
+ expect(badges.length).toBe(2)
273
+
274
+ badges.forEach(badge => {
275
+ expect(badge).toHaveAttribute('tabIndex', '0')
276
+ })
277
+ })
278
+
@@ -12,11 +12,12 @@ type Props = {
12
12
  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",
13
13
  removeProps: any,
14
14
  selectProps: any,
15
+ isFocused?: boolean,
15
16
  }
16
17
 
17
18
 
18
19
  const MultiValue = (props: Props) => {
19
- const { removeProps } = props
20
+ const { removeProps, isFocused } = props
20
21
  const { imageUrl, label } = props.data
21
22
  const { dark, multiKit, pillColor, truncate, wrapped } = props.selectProps
22
23
 
@@ -29,6 +30,9 @@ const MultiValue = (props: Props) => {
29
30
 
30
31
  if (typeof imageUrl === 'string') formPillProps.avatarUrl = imageUrl
31
32
 
33
+ // Add className for focus state
34
+ const pillClassName = isFocused ? 'pb_form_pill_or_badge_focused' : ''
35
+
32
36
  return (
33
37
  <components.MultiValueContainer
34
38
  className="text_input_multivalue_container"
@@ -36,8 +40,10 @@ const MultiValue = (props: Props) => {
36
40
  >
37
41
  {multiKit === 'badge' &&
38
42
  <Badge
43
+ className={pillClassName}
39
44
  closeProps={removeProps}
40
45
  removeIcon
46
+ tabIndex={0}
41
47
  text={label}
42
48
  variant="primary"
43
49
  />
@@ -46,12 +52,14 @@ const MultiValue = (props: Props) => {
46
52
  {multiKit !== 'badge' && imageUrl &&
47
53
  <FormPill
48
54
  avatarUrl={imageUrl}
55
+ className={pillClassName}
49
56
  closeProps={removeProps}
50
57
  color={pillColor}
51
58
  dark={dark}
52
59
  marginRight="xs"
53
60
  name={label}
54
61
  size={multiKit === 'smallPill' ? 'small' : ''}
62
+ tabIndex={0}
55
63
  text=''
56
64
  truncate={truncate}
57
65
  wrapped={wrapped}
@@ -61,12 +69,14 @@ const MultiValue = (props: Props) => {
61
69
 
62
70
  {multiKit !== 'badge' && !imageUrl &&
63
71
  <FormPill
72
+ className={pillClassName}
64
73
  closeProps={removeProps}
65
74
  color={pillColor}
66
75
  dark={dark}
67
76
  marginRight="xs"
68
77
  name=''
69
78
  size={multiKit === 'smallPill' ? 'small' : ''}
79
+ tabIndex={0}
70
80
  text={label}
71
81
  truncate={truncate}
72
82
  wrapped={wrapped}
@@ -1 +1 @@
1
- import{jsx,Fragment,jsxs}from"react/jsx-runtime";import{useState,useEffect}from"react";import{f as buildAriaProps,g as buildDataProps,h as buildHtmlProps,H as HighchartsReact,i as Highcharts,j as classnames,k as globalProps,l as HighchartsMore,S as SolidGauge,m as buildCss}from"./_typeahead-gfPOrCeR.js";import{c as colors,h as highchartsTheme,m as merge,a as highchartsDarkTheme,t as typography}from"./lib-CGxXTQ75.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{f as buildAriaProps,g as buildDataProps,h as buildHtmlProps,H as HighchartsReact,i as Highcharts,j as classnames,k as globalProps,l as HighchartsMore,S as SolidGauge,m as buildCss}from"./_typeahead-BM-vXmpm.js";import{c as colors,h as highchartsTheme,m as merge,a as highchartsDarkTheme,t as typography}from"./lib-CGxXTQ75.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};