playbook_ui 15.5.0.pre.alpha.PLAY2581aggressivevalidation12653 → 15.5.0.pre.alpha.PLAY2581aggressivevalidation12698

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bd8b63915fa51f6daabd0a877e7bd6c0dbe337c900389228dd9434f5deeaa535
4
- data.tar.gz: 1ba2091df0504ec326221fd2660e9238e7220673385b159e0c207ad82fb28e35
3
+ metadata.gz: ae823d2ea188c8b8b0476223c92ffb8cbf0604e42028c011f6fe12b81a25b8d1
4
+ data.tar.gz: 7d8758ea0c6fb712605df92777b66589a7d62c63b43cefb3e0cb0a4a104b9547
5
5
  SHA512:
6
- metadata.gz: 212923b88fdcc63bd98592cc373ff989b51f237d1d147b6fb5f083e15b521812e7a06d9f9ee54f2b1ccf16edf3160ee94e6b28f81a10caf5bcbcee59b731774d
7
- data.tar.gz: 8ee030cb7e451dae0bedec3d130b94ae4607ce49037f95c4901ce02a755eb054829734682c1d46c067cca2955da6272baa46c741cc1124b4be94b2fddb64859f
6
+ metadata.gz: b0bdb702a07ce7985616a28ee935a875208cf9e6292c78d4368408804bbd5a18743e52f642be425d0282b951035fbdbf89a51ced9f143ac314e9545e51069b7a
7
+ data.tar.gz: 2b3897ff7f64c3d7a618ba0ae8056bcc817b81dbf65088e66b800fec33f23144966bdceec47386a8356cc04727c62d8db0e5f5d3f6f0f53be142d04545a3329f
@@ -1,3 +1,24 @@
1
+ <%
2
+ options = [
3
+ {
4
+ label: "United States",
5
+ value: "unitedStates",
6
+ id: "us"
7
+ },
8
+ {
9
+ label: "United Kingdom",
10
+ value: "unitedKingdom",
11
+ id: "gb"
12
+ },
13
+ {
14
+ label: "Pakistan",
15
+ value: "pakistan",
16
+ id: "pk"
17
+ }
18
+ ]
19
+ %>
20
+
21
+
1
22
  <%= pb_rails("button", props: { text: "Open Complex Dialog", data:{"open-dialog": "dialog-complex"} }) %>
2
23
 
3
24
  <%= pb_rails("dialog", props: { id:"dialog-complex", size: "lg", full_height: true }) do %>
@@ -10,6 +31,16 @@
10
31
  <%= pb_rails("rich_text_editor", props: {id: "default", value: "Add your text here"}) %>
11
32
  <%= pb_rails("caption", props: { text: "Type in a word or term too help find tickets later. ex. training, phone setup, hr", margin_bottom: "xs", margin_top: "sm" }) %>
12
33
  <%= pb_rails("typeahead", props: { placeholder: "Tags.."}) %>
34
+ <%= pb_rails("dropdown", props: {options: options, autocomplete: true}) %>
35
+ <%= pb_rails("typeahead", props: {
36
+ id: "typeahead-default",
37
+ placeholder: "Select one...",
38
+ options: options,
39
+ name: :foo,
40
+ margin_top: "sm",
41
+ is_multi: false
42
+ })
43
+ %>
13
44
 
14
45
  <% end %>
15
46
  <%= pb_rails("dialog/dialog_footer", props: {cancel_button: "Back", confirm_button: "Send my Issue", confirm_button_id:"confirm-complex", id: "dialog-complex"}) %>
@@ -143,25 +143,30 @@ export default class PbDialog extends PbEnhancedElement {
143
143
 
144
144
  // Close dialog box on outside click
145
145
  dialogs.forEach((dialogElement) => {
146
- const originalMousedownHandler = dialogElement._outsideClickHandler
147
- if (originalMousedownHandler) dialogElement.removeEventListener("mousedown", originalMousedownHandler)
146
+ const originalClickHandler = dialogElement._outsideClickHandler
147
+ if (originalClickHandler) dialogElement.removeEventListener("click", originalClickHandler)
148
+
148
149
  dialogElement._outsideClickHandler = (event) => {
149
150
  const dialogParentDataset = dialogElement.parentElement.dataset
150
151
  if (dialogParentDataset.overlayClick === "overlay_close") return
151
152
 
152
- const dialogModal = event.target.getBoundingClientRect()
153
- const clickedOutsideDialogModal = event.clientX < dialogModal.left ||
154
- event.clientX > dialogModal.right ||
155
- event.clientY < dialogModal.top ||
156
- event.clientY > dialogModal.bottom
157
-
158
- if (clickedOutsideDialogModal) {
153
+ // Get the dialog's bounding box (the actual content area)
154
+ const rect = dialogElement.getBoundingClientRect()
155
+ const clickedInDialog = (
156
+ event.clientX >= rect.left &&
157
+ event.clientX <= rect.right &&
158
+ event.clientY >= rect.top &&
159
+ event.clientY <= rect.bottom
160
+ )
161
+
162
+ // Only close if clicked outside the dialog content (on the backdrop)
163
+ if (!clickedInDialog) {
159
164
  dialogElement.close()
160
165
  event.stopPropagation()
161
166
  }
162
167
  }
163
168
 
164
- dialogElement.addEventListener("mousedown", dialogElement._outsideClickHandler);
169
+ dialogElement.addEventListener("click", dialogElement._outsideClickHandler);
165
170
  })
166
171
  }
167
172
  }
@@ -1,5 +1,5 @@
1
1
  .pb_file_upload_kit {
2
- .pb_card_kit_deselected_border_radius_md {
2
+ .pb_card_kit {
3
3
  border: 1px #ccc dashed;
4
4
  text-align: center;
5
5
  }
@@ -11,7 +11,7 @@
11
11
  }
12
12
  &.error,
13
13
  &.pb_file_upload_kit_error {
14
- .pb_card_kit_deselected_border_radius_md {
14
+ .pb_card_kit {
15
15
  border-color: $error;
16
16
  }
17
17
  .pb_body_kit_negative {
@@ -30,12 +30,12 @@
30
30
  }
31
31
 
32
32
  .dark .pb_file_upload_kit {
33
- .pb_card_kit_deselected_border_radius_md {
33
+ .pb_card_kit {
34
34
  border: 1px $text_dk_lighter dashed;
35
35
  }
36
36
  &.error,
37
37
  &.pb_file_upload_kit_error {
38
- .pb_card_kit_deselected_border_radius_md {
38
+ .pb_card_kit {
39
39
  border-color: $error_dark;
40
40
  }
41
41
  }
@@ -112,19 +112,14 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
112
112
  const wrapperRef = useRef<HTMLDivElement | null>(null);
113
113
  const hasBlurredRef = useRef<boolean>(false);
114
114
  const formSubmittedRef = useRef<boolean>(false);
115
- // Handle value prop - it might be a string or an object with number property (from react-hook-form)
116
- const getValueString = (val: any): string => {
117
- if (typeof val === 'string') return val
118
- if (val?.number) return val.number
119
- return ""
120
- }
121
- const [inputValue, setInputValue] = useState(getValueString(value))
115
+ const [inputValue, setInputValue] = useState(value)
122
116
  const [error, setError] = useState(props.error || "")
123
117
  const [dropDownIsOpen, setDropDownIsOpen] = useState(false)
124
118
  const [selectedData, setSelectedData] = useState()
125
119
  const [hasTyped, setHasTyped] = useState(false)
126
120
  const [hasBlurred, setHasBlurred] = useState(false)
127
121
  const [formSubmitted, setFormSubmitted] = useState(false)
122
+ const [hasStartedValidating, setHasStartedValidating] = useState(false)
128
123
 
129
124
  // Keep refs in sync with state for use in event listeners
130
125
  useEffect(() => {
@@ -134,16 +129,6 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
134
129
  useEffect(() => {
135
130
  formSubmittedRef.current = formSubmitted
136
131
  }, [formSubmitted])
137
- const [hasStartedValidating, setHasStartedValidating] = useState(false)
138
-
139
- // Sync value prop when it changes (e.g., from react-hook-form)
140
- useEffect(() => {
141
- const newValue = getValueString(props.value)
142
- if (newValue !== inputValue) {
143
- setInputValue(newValue)
144
- }
145
- // eslint-disable-next-line react-hooks/exhaustive-deps
146
- }, [props.value])
147
132
 
148
133
  // Only sync initial error from props, not continuous updates
149
134
  // Once validation starts, internal validation takes over
@@ -173,10 +158,6 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
173
158
  // Show internal errors only after blur (hasBlurred) or on form submission (formSubmitted)
174
159
  const shouldShowInternalError = (hasBlurred || formSubmitted) && error
175
160
  const displayError = shouldShowInternalError ? error : ""
176
-
177
- // Only show error prop after blur (to prevent showing react-hook-form errors while typing)
178
- const shouldShowPropError = hasBlurred || formSubmitted
179
- const propError = shouldShowPropError ? (props.error || "") : ""
180
161
 
181
162
  useEffect(() => {
182
163
  const hasError = (error ?? '').length > 0
@@ -291,8 +272,8 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
291
272
  }
292
273
 
293
274
  // Only validate if field has been blurred or form has been submitted
294
- // Don't validate on change - only on blur or submission
295
- if (!hasBlurred && !formSubmitted) return
275
+ // Use refs here since state updates are async and we need current values
276
+ if (!hasBlurredRef.current && !formSubmittedRef.current) return
296
277
 
297
278
  // Run validation checks
298
279
  if (itiRef.current) isValid(itiRef.current.isValidNumber())
@@ -306,7 +287,7 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
306
287
 
307
288
  // Add listener for form validation to track when validation should be shown
308
289
  useEffect(() => {
309
- const handleInvalid = (event: Event) => {
290
+ const handleInvalid = (event: Event) => {
310
291
  const target = event.target as HTMLInputElement
311
292
  const phoneNumberContainer = target.closest('.pb_phone_number_input')
312
293
 
@@ -444,12 +425,6 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
444
425
  setFormSubmitted(false)
445
426
  }
446
427
 
447
- // Clear error when user starts typing (before blur)
448
- // This prevents showing validation errors while typing
449
- if (!hasBlurredRef.current && error) {
450
- setError('')
451
- }
452
-
453
428
  let phoneNumberData
454
429
 
455
430
  // Handle formatAsYouType with input event
@@ -465,6 +440,7 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
465
440
 
466
441
  // Don't call isValid callback on change - only on blur or form submission
467
442
  // This prevents triggering validation while typing
443
+ // Use refs to get current values in case this is called from event listener
468
444
  if (hasBlurredRef.current || formSubmittedRef.current) {
469
445
  isValid(itiRef.current.isValidNumber())
470
446
  }
@@ -525,11 +501,6 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
525
501
  setInputValue(formattedValue)
526
502
  setHasTyped(true)
527
503
 
528
- // Clear error when user types (before blur) - use ref to get current value
529
- if (!hasBlurredRef.current) {
530
- setError('')
531
- }
532
-
533
504
  // Get phone number data with unformatted number
534
505
  const formattedPhoneNumberData = getCurrentSelectedData(telInputInit, formattedValue)
535
506
  const phoneNumberData = {...formattedPhoneNumberData, number: unformatNumber(formattedPhoneNumberData.number)}
@@ -538,6 +509,7 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
538
509
  onChange(phoneNumberData)
539
510
 
540
511
  // Don't call isValid callback on change - only on blur or form submission
512
+ // Use refs to check current blur state in the event listener (closure issue)
541
513
  if (hasBlurredRef.current || formSubmittedRef.current) {
542
514
  isValid(telInputInit.isValidNumber())
543
515
  }
@@ -550,7 +522,7 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
550
522
  dark,
551
523
  "data-phone-number": JSON.stringify(selectedData),
552
524
  disabled,
553
- error: displayError || propError,
525
+ error: displayError || props.error || "",
554
526
  type: 'tel',
555
527
  id,
556
528
  label,
@@ -7,18 +7,29 @@ type ClearContainerProps = {
7
7
  id: string,
8
8
  },
9
9
  clearValue: () => void,
10
+ innerProps?: any,
10
11
  }
11
12
 
12
- const ClearContainer = (props: ClearContainerProps): React.ReactElement => {
13
- const { selectProps, clearValue } = props
13
+ const ClearContainer = (props: ClearContainerProps | any): React.ReactElement => {
14
+ const { selectProps, clearValue, innerProps } = props
14
15
  useEffect(() => {
15
16
  document.addEventListener(`pb-typeahead-kit-${selectProps.id}:clear`, clearValue)
16
17
  }, [clearValue, selectProps.id])
17
18
 
19
+ // To stop this from bubbling up when inside a dialog or other modal
20
+ const handleMouseDown = (event: React.MouseEvent) => {
21
+ event.stopPropagation()
22
+ innerProps?.onMouseDown?.(event)
23
+ }
24
+
18
25
  return (
19
26
  <components.ClearIndicator
20
27
  className="clear_indicator"
21
28
  {...props}
29
+ innerProps={{
30
+ ...innerProps,
31
+ onMouseDown: handleMouseDown,
32
+ }}
22
33
  />
23
34
  )
24
35
  }