playbook_ui 15.6.0.pre.alpha.play266913088 → 15.6.0.pre.rc.0

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 (169) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/pb_advanced_table/Components/RegularTableView.tsx +2 -3
  3. data/app/pb_kits/playbook/pb_advanced_table/Components/TableHeaderCell.tsx +0 -4
  4. data/app/pb_kits/playbook/pb_advanced_table/advanced_table.test.jsx +0 -95
  5. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_background_control_rails.html.erb +5 -11
  6. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_background_control_rails.md +1 -7
  7. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_table_props.html.erb +163 -1
  8. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_table_props.jsx +190 -0
  9. data/app/pb_kits/playbook/pb_advanced_table/docs/example.yml +1 -4
  10. data/app/pb_kits/playbook/pb_advanced_table/docs/index.js +1 -3
  11. data/app/pb_kits/playbook/pb_advanced_table/table_header.html.erb +2 -2
  12. data/app/pb_kits/playbook/pb_advanced_table/table_header.rb +0 -57
  13. data/app/pb_kits/playbook/pb_background/_background.tsx +6 -6
  14. data/app/pb_kits/playbook/pb_background/background.test.js +1 -5
  15. data/app/pb_kits/playbook/pb_background/docs/_background_light.html.erb +1 -1
  16. data/app/pb_kits/playbook/pb_background/docs/_background_light.jsx +1 -0
  17. data/app/pb_kits/playbook/pb_background/docs/example.yml +2 -2
  18. data/app/pb_kits/playbook/pb_card/docs/_card_header.md +1 -1
  19. data/app/pb_kits/playbook/pb_card/docs/_card_highlight.md +1 -1
  20. data/app/pb_kits/playbook/pb_collapsible/__snapshots__/collapsible.test.js.snap +2 -2
  21. data/app/pb_kits/playbook/pb_collapsible/child_kits/CollapsibleIcon.tsx +8 -10
  22. data/app/pb_kits/playbook/pb_collapsible/docs/_collapsible_icons.jsx +1 -0
  23. data/app/pb_kits/playbook/pb_collapsible/docs/_collapsible_state.jsx +3 -0
  24. data/app/pb_kits/playbook/pb_contact/_contact.tsx +24 -51
  25. data/app/pb_kits/playbook/pb_contact/contact.html.erb +19 -53
  26. data/app/pb_kits/playbook/pb_contact/contact.rb +1 -11
  27. data/app/pb_kits/playbook/pb_contact/contact.test.js +0 -76
  28. data/app/pb_kits/playbook/pb_contact/docs/example.yml +0 -2
  29. data/app/pb_kits/playbook/pb_contact/docs/index.js +0 -1
  30. data/app/pb_kits/playbook/pb_date_picker/date_picker.test.js +0 -24
  31. data/app/pb_kits/playbook/pb_date_picker/date_picker_helper.ts +7 -197
  32. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_range_pattern_rails.html.erb +14 -23
  33. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_range_pattern_rails.md +1 -1
  34. data/app/pb_kits/playbook/pb_dialog/_dialog.tsx +1 -2
  35. data/app/pb_kits/playbook/pb_dialog/dialog.html.erb +1 -1
  36. data/app/pb_kits/playbook/pb_dialog/dialog.rb +0 -1
  37. data/app/pb_kits/playbook/pb_dialog/dialog.test.jsx +0 -14
  38. data/app/pb_kits/playbook/pb_dialog/dialog_header.html.erb +4 -5
  39. data/app/pb_kits/playbook/pb_dialog/dialog_header.rb +0 -2
  40. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_compound_components.html.erb +0 -31
  41. data/app/pb_kits/playbook/pb_dialog/docs/example.yml +0 -4
  42. data/app/pb_kits/playbook/pb_dialog/docs/index.js +1 -3
  43. data/app/pb_kits/playbook/pb_distribution_bar/docs/_distribution_bar_custom_colors.md +1 -1
  44. data/app/pb_kits/playbook/pb_draggable/context/index.tsx +7 -458
  45. data/app/pb_kits/playbook/pb_draggable/context/types.ts +3 -8
  46. data/app/pb_kits/playbook/pb_draggable/docs/example.yml +2 -3
  47. data/app/pb_kits/playbook/pb_draggable/docs/index.js +1 -2
  48. data/app/pb_kits/playbook/pb_draggable/draggable.test.jsx +1 -77
  49. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_default_rails.html.erb +5 -7
  50. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_display_rails.html.erb +1 -3
  51. data/app/pb_kits/playbook/pb_dropdown/docs/example.yml +0 -5
  52. data/app/pb_kits/playbook/pb_dropdown/dropdown.html.erb +0 -4
  53. data/app/pb_kits/playbook/pb_dropdown/dropdown.rb +5 -39
  54. data/app/pb_kits/playbook/pb_dropdown/index.js +3 -171
  55. data/app/pb_kits/playbook/pb_file_upload/_file_upload.scss +4 -4
  56. data/app/pb_kits/playbook/pb_filter/Filter/FilterBackground.tsx +3 -3
  57. data/app/pb_kits/playbook/pb_home_address_street/_home_address_street.tsx +22 -34
  58. data/app/pb_kits/playbook/pb_home_address_street/city_emphasis.html.erb +12 -16
  59. data/app/pb_kits/playbook/pb_home_address_street/docs/_home_address_street_default.html.erb +1 -1
  60. data/app/pb_kits/playbook/pb_home_address_street/none_emphasis.html.erb +12 -16
  61. data/app/pb_kits/playbook/pb_home_address_street/street_emphasis.html.erb +12 -16
  62. data/app/pb_kits/playbook/pb_multiple_users/_multiple_users.scss +0 -10
  63. data/app/pb_kits/playbook/pb_multiple_users/_multiple_users.tsx +15 -66
  64. data/app/pb_kits/playbook/pb_multiple_users/docs/example.yml +0 -1
  65. data/app/pb_kits/playbook/pb_multiple_users/docs/index.js +0 -1
  66. data/app/pb_kits/playbook/pb_multiple_users/multiple_users.test.js +0 -25
  67. data/app/pb_kits/playbook/pb_phone_number_input/_phone_number_input.tsx +10 -44
  68. data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_validation.html.erb +4 -34
  69. data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_validation.jsx +7 -16
  70. data/app/pb_kits/playbook/pb_radio/docs/_radio_error.md +1 -1
  71. data/app/pb_kits/playbook/pb_select/_select.tsx +3 -8
  72. data/app/pb_kits/playbook/pb_select/docs/_select_error.md +1 -1
  73. data/app/pb_kits/playbook/pb_select/docs/example.yml +0 -2
  74. data/app/pb_kits/playbook/pb_select/docs/index.js +0 -1
  75. data/app/pb_kits/playbook/pb_select/select.html.erb +2 -2
  76. data/app/pb_kits/playbook/pb_select/select.rb +1 -3
  77. data/app/pb_kits/playbook/pb_select/select.test.js +0 -23
  78. data/app/pb_kits/playbook/pb_table/_table.tsx +33 -187
  79. data/app/pb_kits/playbook/pb_table/docs/example.yml +0 -4
  80. data/app/pb_kits/playbook/pb_table/docs/index.js +0 -2
  81. data/app/pb_kits/playbook/pb_table/table.html.erb +12 -68
  82. data/app/pb_kits/playbook/pb_table/table.rb +3 -22
  83. data/app/pb_kits/playbook/pb_table/table.test.js +0 -143
  84. data/app/pb_kits/playbook/pb_text_input/docs/_text_input_error.md +1 -1
  85. data/app/pb_kits/playbook/pb_textarea/docs/_textarea_error.md +1 -1
  86. data/app/pb_kits/playbook/pb_timeline/_item.tsx +0 -3
  87. data/app/pb_kits/playbook/pb_timeline/docs/_timeline_with_date.md +1 -1
  88. data/app/pb_kits/playbook/pb_timeline/docs/example.yml +0 -2
  89. data/app/pb_kits/playbook/pb_timeline/docs/index.js +0 -1
  90. data/app/pb_kits/playbook/pb_timeline/item.html.erb +1 -1
  91. data/app/pb_kits/playbook/pb_timeline/item.rb +0 -2
  92. data/app/pb_kits/playbook/pb_timeline/label.html.erb +1 -2
  93. data/app/pb_kits/playbook/pb_timeline/label.rb +0 -2
  94. data/app/pb_kits/playbook/pb_timeline/subcomponents/Label.tsx +0 -3
  95. data/app/pb_kits/playbook/pb_timeline/timeline.test.js +0 -51
  96. data/app/pb_kits/playbook/pb_typeahead/_typeahead.test.jsx +0 -15
  97. data/app/pb_kits/playbook/pb_typeahead/_typeahead.tsx +0 -3
  98. data/app/pb_kits/playbook/pb_typeahead/components/ClearIndicator.tsx +2 -13
  99. data/app/pb_kits/playbook/pb_typeahead/components/MultiValue.tsx +1 -6
  100. data/app/pb_kits/playbook/pb_typeahead/components/ValueContainer.tsx +7 -34
  101. data/app/pb_kits/playbook/pb_typeahead/docs/example.yml +0 -2
  102. data/app/pb_kits/playbook/pb_typeahead/docs/index.js +1 -2
  103. data/app/pb_kits/playbook/pb_typeahead/typeahead.rb +1 -6
  104. data/app/pb_kits/playbook/tokens/_colors.scss +1 -2
  105. data/dist/chunks/_typeahead-kRdz5zPn.js +6 -0
  106. data/dist/chunks/lib-CgpqUb6l.js +29 -0
  107. data/dist/chunks/vendor.js +3 -3
  108. data/dist/menu.yml +1 -1
  109. data/dist/playbook-rails-react-bindings.js +1 -1
  110. data/dist/playbook-rails.js +1 -1
  111. data/dist/playbook.css +1 -1
  112. data/lib/playbook/forms/builder/collection_select_field.rb +1 -9
  113. data/lib/playbook/forms/builder/select_field.rb +1 -9
  114. data/lib/playbook/forms/builder/time_zone_select_field.rb +1 -9
  115. data/lib/playbook/pb_kit_helper.rb +0 -35
  116. data/lib/playbook/version.rb +2 -2
  117. metadata +4 -54
  118. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_background_colors_rails.html.erb +0 -43
  119. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_background_colors_rails.md +0 -1
  120. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_styling_background.jsx +0 -54
  121. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_styling_background.md +0 -9
  122. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_styling_background_multi.jsx +0 -80
  123. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_styling_background_multi.md +0 -3
  124. data/app/pb_kits/playbook/pb_background/docs/_background_light.md +0 -1
  125. data/app/pb_kits/playbook/pb_contact/docs/_contact_unstyled.html.erb +0 -33
  126. data/app/pb_kits/playbook/pb_contact/docs/_contact_unstyled.jsx +0 -46
  127. data/app/pb_kits/playbook/pb_contact/docs/_contact_unstyled_rails.md +0 -2
  128. data/app/pb_kits/playbook/pb_contact/docs/_contact_unstyled_react.md +0 -2
  129. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_closeable.html.erb +0 -24
  130. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_closeable.jsx +0 -60
  131. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_closeable.md +0 -3
  132. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_overflow_visible.html.erb +0 -71
  133. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_overflow_visible.jsx +0 -57
  134. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_overflow_visible_rails.md +0 -1
  135. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_overflow_visible_react.md +0 -1
  136. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_multiple_containers_dropzone.jsx +0 -180
  137. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_multiple_containers_dropzone.md +0 -22
  138. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_quickpick_default_dates.html.erb +0 -19
  139. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_quickpick_rails.html.erb +0 -12
  140. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_quickpick_rails.md +0 -26
  141. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_quickpick_range_end_rails.html.erb +0 -19
  142. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_quickpick_range_end_rails.md +0 -1
  143. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_quickpick_with_date_pickers_default_rails.html.erb +0 -30
  144. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_quickpick_with_date_pickers_default_rails.md +0 -3
  145. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_quickpick_with_date_pickers_rails.html.erb +0 -29
  146. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_quickpick_with_date_pickers_rails.md +0 -13
  147. data/app/pb_kits/playbook/pb_dropdown/quickpick_helper.rb +0 -75
  148. data/app/pb_kits/playbook/pb_multiple_users/docs/_multiple_users_with_tooltip.jsx +0 -42
  149. data/app/pb_kits/playbook/pb_multiple_users/docs/_multiple_users_with_tooltip.md +0 -1
  150. data/app/pb_kits/playbook/pb_select/docs/_select_input_options.html.erb +0 -16
  151. data/app/pb_kits/playbook/pb_select/docs/_select_input_options.jsx +0 -30
  152. data/app/pb_kits/playbook/pb_select/docs/_select_input_options.md +0 -1
  153. data/app/pb_kits/playbook/pb_table/docs/_table_with_filter_variant.jsx +0 -134
  154. data/app/pb_kits/playbook/pb_table/docs/_table_with_filter_variant.md +0 -34
  155. data/app/pb_kits/playbook/pb_table/docs/_table_with_filter_variant_rails.html.erb +0 -101
  156. data/app/pb_kits/playbook/pb_table/docs/_table_with_filter_variant_rails.md +0 -33
  157. data/app/pb_kits/playbook/pb_table/docs/_table_with_filter_variant_with_pagination.jsx +0 -180
  158. data/app/pb_kits/playbook/pb_table/docs/_table_with_filter_variant_with_pagination.md +0 -3
  159. data/app/pb_kits/playbook/pb_table/docs/_table_with_filter_variant_with_pagination_rails.html.erb +0 -122
  160. data/app/pb_kits/playbook/pb_table/docs/_table_with_filter_variant_with_pagination_rails.md +0 -3
  161. data/app/pb_kits/playbook/pb_timeline/docs/_timeline_show_current_year.html.erb +0 -60
  162. data/app/pb_kits/playbook/pb_timeline/docs/_timeline_show_current_year.jsx +0 -118
  163. data/app/pb_kits/playbook/pb_timeline/docs/_timeline_show_current_year.md +0 -1
  164. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_input_display.html.erb +0 -30
  165. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_input_display.jsx +0 -37
  166. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_input_display.md +0 -3
  167. data/app/pb_kits/playbook/utilities/deprecated.ts +0 -73
  168. data/dist/chunks/_typeahead-CbjBmIDu.js +0 -6
  169. data/dist/chunks/lib-DxDBrGZX.js +0 -29
@@ -5,19 +5,17 @@ import { buildAriaProps, buildCss, buildDataProps, buildHtmlProps } from '../uti
5
5
  import { globalProps } from '../utilities/globalProps'
6
6
 
7
7
  import Avatar from '../pb_avatar/_avatar'
8
- import Tooltip from '../pb_tooltip/_tooltip'
9
8
 
10
9
  type MultipleUsersProps = {
11
10
  aria?: { [key: string]: string },
12
11
  className?: string,
13
12
  dark?: boolean,
14
13
  data?: { [key: string]: string },
15
- htmlOptions?: { [key: string]: string | number | boolean | (() => void) },
14
+ htmlOptions?: {[key: string]: string | number | boolean | (() => void)},
16
15
  id?: string,
17
16
  maxDisplayedUsers?: number,
18
17
  reverse?: boolean,
19
18
  size?: "md" | "lg" | "sm" | "xl" | "xs" | "xxs",
20
- withTooltip?: boolean,
21
19
  users: Array<{ [key: string]: string }>,
22
20
  }
23
21
 
@@ -32,7 +30,6 @@ const MultipleUsers = (props: MultipleUsersProps): React.ReactElement => {
32
30
  maxDisplayedUsers = 4,
33
31
  reverse = false,
34
32
  size = 'xs',
35
- withTooltip = false,
36
33
  users,
37
34
  } = props
38
35
 
@@ -65,70 +62,22 @@ const MultipleUsers = (props: MultipleUsersProps): React.ReactElement => {
65
62
  className={classes}
66
63
  id={id}
67
64
  >
68
- {withTooltip ?
69
- <>
70
- {usersToDisplay.map((avatarData, index) => (
71
- <Tooltip
72
- key={"user_tooltip_" + index}
73
- placement='top'
74
- text={avatarData.tooltip ? avatarData.tooltip : ''}
75
- zIndex={10}
76
- >
77
- <Avatar
78
- {...avatarData}
79
- className={"pb_multiple_users_item" + (withTooltip ? " user_tooltip" : "")}
80
- dark={dark}
81
- imageAlt={avatarData.name}
82
- key={index}
83
- size={size}
84
- />
85
- </Tooltip>
86
- ))}
65
+ {usersToDisplay.map((avatarData, index) => (
66
+ <Avatar
67
+ {...avatarData}
68
+ className="pb_multiple_users_item"
69
+ dark={dark}
70
+ imageAlt={avatarData.name}
71
+ key={index}
72
+ size={size}
73
+ />
74
+ ))}
87
75
 
88
- {users.length > maxDisplayedUsers &&
89
- <Tooltip
90
- placement='top'
91
- text={
92
- <div>
93
- {
94
- usersToDisplay.length < users.length ?
95
- users.slice(displayCount).map((u, i) => (
96
- <div key={i}>{u.tooltip}</div>
97
- ))
98
- :
99
- ''
100
- }
101
- </div>
102
- }
103
- zIndex={10}
104
- >
105
- <div className={itemClasses + (withTooltip ? " user_count_tooltip" : "")}>
106
- {`+${users.length - displayCount}`}
107
- </div>
108
- </Tooltip>
109
- }
110
- </>
111
- :
112
- <>
113
- {usersToDisplay.map((avatarData, index) => (
114
- <Avatar
115
- {...avatarData}
116
- className="pb_multiple_users_item"
117
- dark={dark}
118
- imageAlt={avatarData.name}
119
- key={index}
120
- size={size}
121
- />
122
- ))}
123
-
124
- {users.length > maxDisplayedUsers &&
125
- <div className={itemClasses}>
126
- {`+${users.length - 3}`}
127
- </div>
128
- }
129
- </>
76
+ { users.length > maxDisplayedUsers &&
77
+ <div className={itemClasses}>
78
+ {`+${users.length - 3}`}
79
+ </div>
130
80
  }
131
-
132
81
  </div>
133
82
  )
134
83
  }
@@ -10,7 +10,6 @@ examples:
10
10
  - multiple_users_default: Default
11
11
  - multiple_users_reverse: Reverse
12
12
  - multiple_users_size: Size
13
- - multiple_users_with_tooltip: With Tooltip
14
13
 
15
14
  swift:
16
15
  - multiple_users_default_swift: Default
@@ -1,4 +1,3 @@
1
1
  export { default as MultipleUsersDefault } from './_multiple_users_default.jsx'
2
2
  export { default as MultipleUsersReverse } from './_multiple_users_reverse.jsx'
3
3
  export { default as MultipleUsersSize } from './_multiple_users_size.jsx'
4
- export { default as MultipleUsersWithTooltip } from './_multiple_users_with_tooltip.jsx'
@@ -49,29 +49,4 @@ test('should render aria-label', () => {
49
49
 
50
50
  const kit = screen.getByTestId(testId)
51
51
  expect(kit).toHaveAttribute('aria-label', testId)
52
- })
53
-
54
- test('should render withTooltip prop', () => {
55
- render(
56
- <MultipleUsers
57
- data={{ testid: testId }}
58
- users={[
59
- {
60
- name: 'Patrick Welch',
61
- imageUrl: 'https://randomuser.me/api/portraits/men/9.jpg',
62
- tooltip: "Patrick Welch - Online"
63
- },
64
- {
65
- name: 'Lucille Sanchez',
66
- imageUrl: 'https://randomuser.me/api/portraits/women/6.jpg',
67
- tooltip: "Lucille Sanchez - Offline"
68
- },
69
- ]}
70
- withTooltip
71
- />
72
- )
73
-
74
- const kit = screen.getByTestId(testId)
75
- const childWithTooltip = kit.querySelector('.pb_tooltip_kit')
76
- expect(childWithTooltip).not.toBeNull()
77
52
  })
@@ -110,25 +110,13 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
110
110
  const inputRef = useRef<HTMLInputElement | null>(null)
111
111
  const itiRef = useRef<any>(null);
112
112
  const wrapperRef = useRef<HTMLDivElement | null>(null);
113
- const hasBlurredRef = useRef<boolean>(false);
114
- const formSubmittedRef = useRef<boolean>(false);
115
113
  const [inputValue, setInputValue] = useState(value)
116
114
  const [error, setError] = useState(props.error || "")
117
115
  const [dropDownIsOpen, setDropDownIsOpen] = useState(false)
118
116
  const [selectedData, setSelectedData] = useState()
119
117
  const [hasTyped, setHasTyped] = useState(false)
120
- const [hasBlurred, setHasBlurred] = useState(false)
121
118
  const [formSubmitted, setFormSubmitted] = useState(false)
122
119
  const [hasStartedValidating, setHasStartedValidating] = useState(false)
123
-
124
- // Keep refs in sync with state for use in event listeners
125
- useEffect(() => {
126
- hasBlurredRef.current = hasBlurred
127
- }, [hasBlurred])
128
-
129
- useEffect(() => {
130
- formSubmittedRef.current = formSubmitted
131
- }, [formSubmitted])
132
120
 
133
121
  // Only sync initial error from props, not continuous updates
134
122
  // Once validation starts, internal validation takes over
@@ -155,8 +143,8 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
155
143
  }
156
144
 
157
145
  // Determine which error to display
158
- // Show internal errors only after blur (hasBlurred) or on form submission (formSubmitted)
159
- const shouldShowInternalError = (hasBlurred || formSubmitted) && error
146
+ // Show internal errors on blur (hasTyped) or on form submission (formSubmitted)
147
+ const shouldShowInternalError = (hasTyped || formSubmitted) && required && error
160
148
  const displayError = shouldShowInternalError ? error : ""
161
149
 
162
150
  useEffect(() => {
@@ -271,9 +259,7 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
271
259
  return
272
260
  }
273
261
 
274
- // Only validate if field has been blurred or form has been submitted
275
- // Use refs here since state updates are async and we need current values
276
- if (!hasBlurredRef.current && !formSubmittedRef.current) return
262
+ if (!hasTyped && !error) return
277
263
 
278
264
  // Run validation checks
279
265
  if (itiRef.current) isValid(itiRef.current.isValidNumber())
@@ -294,7 +280,6 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
294
280
  if (phoneNumberContainer && phoneNumberContainer === wrapperRef.current) {
295
281
  const invalidInputName = target.name || target.getAttribute('name')
296
282
  if (invalidInputName === name) {
297
- formSubmittedRef.current = true
298
283
  setFormSubmitted(true)
299
284
  // Trigger validation when form is submitted
300
285
  validateErrors()
@@ -320,9 +305,6 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
320
305
  setInputValue("")
321
306
  setError("")
322
307
  setHasTyped(false)
323
- hasBlurredRef.current = false
324
- setHasBlurred(false)
325
- formSubmittedRef.current = false
326
308
  setFormSubmitted(false)
327
309
  setHasStartedValidating(false)
328
310
  // Only clear validation state if field was required
@@ -340,7 +322,6 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
340
322
 
341
323
  if (required && isEmpty) {
342
324
  setError('Missing phone number')
343
- formSubmittedRef.current = true
344
325
  setFormSubmitted(true)
345
326
  return 'Missing phone number'
346
327
  }
@@ -397,7 +378,6 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
397
378
 
398
379
  // Set the error state so the validation attribute gets added
399
380
  setError(errorMessage)
400
- formSubmittedRef.current = true
401
381
  setFormSubmitted(true)
402
382
  setHasTyped(true)
403
383
 
@@ -421,7 +401,6 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
421
401
 
422
402
  // Reset form submitted state when user types
423
403
  if (formSubmitted) {
424
- formSubmittedRef.current = false
425
404
  setFormSubmitted(false)
426
405
  }
427
406
 
@@ -437,15 +416,11 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
437
416
 
438
417
  setSelectedData(phoneNumberData)
439
418
  onChange(phoneNumberData)
440
-
441
- // Don't call isValid callback on change - only on blur or form submission
442
- // This prevents triggering validation while typing
443
- // Use refs to get current values in case this is called from event listener
444
- if (hasBlurredRef.current || formSubmittedRef.current) {
445
- isValid(itiRef.current.isValidNumber())
446
- }
419
+ isValid(itiRef.current.isValidNumber())
447
420
 
448
- // Don't validate on change - only validate on blur or form submission
421
+ // Trigger validation after onChange for React Hook Form
422
+ // This ensures validation state is up-to-date
423
+ setTimeout(() => validateErrors(), 0)
449
424
  }
450
425
 
451
426
  // Separating Concerns as React Docs Recommend
@@ -507,12 +482,7 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
507
482
 
508
483
  setSelectedData(phoneNumberData)
509
484
  onChange(phoneNumberData)
510
-
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)
513
- if (hasBlurredRef.current || formSubmittedRef.current) {
514
- isValid(telInputInit.isValidNumber())
515
- }
485
+ isValid(telInputInit.isValidNumber())
516
486
  })
517
487
  }
518
488
  }
@@ -522,16 +492,12 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
522
492
  dark,
523
493
  "data-phone-number": JSON.stringify(selectedData),
524
494
  disabled,
525
- error: displayError || props.error || "",
495
+ error: hasTyped ? error : props.error || displayError,
526
496
  type: 'tel',
527
497
  id,
528
498
  label,
529
499
  name,
530
- onBlur: () => {
531
- hasBlurredRef.current = true
532
- setHasBlurred(true)
533
- validateErrors()
534
- },
500
+ onBlur: validateErrors,
535
501
  onChange: formatAsYouType ? undefined : handleOnChange,
536
502
  value: inputValue
537
503
  }
@@ -1,42 +1,12 @@
1
1
  <form id="example-form-validation" action="" method="get">
2
- <%= pb_rails("phone_number_input", props: {
3
- id: "validation",
4
- initial_country: "af",
5
- value: "",
6
- required: true
7
- }) %>
2
+ <%= pb_rails("phone_number_input", props: { error: "Missing phone number", id: "validation", initial_country: "af", value: "", required: true }) %>
8
3
  <%= pb_rails("button", props: {html_type: "submit", text: "Save Phone Number"}) %>
9
4
  </form>
10
5
 
11
6
  <%= javascript_tag do %>
12
7
  document.addEventListener('DOMContentLoaded', function () {
13
- const form = document.querySelector('#example-form-validation');
14
-
15
- // Wait for React component to mount
16
- function waitForComponent() {
17
- const phoneInput = form.querySelector('#validation');
18
-
19
- if (!phoneInput) {
20
- setTimeout(waitForComponent, 100);
21
- return;
22
- }
23
-
24
- // Wait for intl-tel-input to initialize, then focus and blur to trigger validation
25
- setTimeout(function() {
26
- phoneInput.focus({ preventScroll: true });
27
- setTimeout(function() {
28
- phoneInput.blur();
29
- }, 100);
30
- }, 500);
31
- }
32
-
33
- waitForComponent();
34
-
35
- // Prevent form submission if there are validation errors
36
- form.addEventListener('submit', function (e) {
37
- if (e.target.querySelectorAll('[error]:not([error=""])').length > 0) {
38
- e.preventDefault();
39
- }
40
- });
8
+ document.querySelector('#example-form-validation').addEventListener('submit', function (e) {
9
+ if (e.target.querySelectorAll('[error]:not([error=""])').length > 0) e.preventDefault();
10
+ })
41
11
  })
42
12
  <% end %>
@@ -10,19 +10,8 @@ const PhoneNumberInputValidation = (props) => {
10
10
  const [showFormErrors, setShowFormErrors] = useState(false);
11
11
  const [phoneNumber, setPhoneNumber] = useState("");
12
12
  const [countryCode, setCountryCode] = useState("af");
13
- const [isValid, setIsValid] = useState(false);
14
- const [hasInteracted, setHasInteracted] = useState(false);
15
-
16
- // Start with initial error - will be cleared on blur if valid
17
- const initialError = (
18
- <>
19
- <Icon icon="warning" /> Missing phone number.
20
- </>
21
- );
22
13
 
23
14
  const handleOnValidate = (valid) => {
24
- setIsValid(valid);
25
- setHasInteracted(true);
26
15
  setFormErrors(
27
16
  valid ? "" : "Please correct the fields below and try again."
28
17
  );
@@ -34,16 +23,18 @@ const PhoneNumberInputValidation = (props) => {
34
23
  };
35
24
 
36
25
  const handleOnSubmit = (e) => {
37
- if (!isValid) e.preventDefault()
26
+ if (showFormErrors) e.preventDefault()
38
27
  }
39
28
 
40
29
  useEffect(() => {
41
30
  setShowFormErrors(formErrors.length > 0);
42
31
  }, [formErrors]);
43
32
 
44
- // Only show error prop initially, or if invalid after interaction
45
- // Clear error prop once valid (component handles validation on blur)
46
- const shouldShowError = !hasInteracted || (hasInteracted && !isValid);
33
+ const error = (
34
+ <>
35
+ <Icon icon="warning" /> Missing phone number.
36
+ </>
37
+ )
47
38
 
48
39
  return (
49
40
  <form
@@ -59,7 +50,7 @@ const PhoneNumberInputValidation = (props) => {
59
50
  />
60
51
  )}
61
52
  <PhoneNumberInput
62
- error={shouldShowError ? initialError : undefined}
53
+ error={error}
63
54
  id="validation"
64
55
  initialCountry={countryCode}
65
56
  onChange={handleOnChange}
@@ -1 +1 @@
1
- Error shows that the radio option must be selected or is invalid (i.e. when used in a form it signals a user to fix an error).
1
+ Error shows that the radio option must be selected or is invalid (ie when used in a form it signals a user to fix an error).
@@ -29,7 +29,6 @@ type SelectProps = {
29
29
  id?: string,
30
30
  includeBlank?: string,
31
31
  inline?: boolean,
32
- inputOptions?: {[key: string]: string | number | boolean | (() => void)},
33
32
  label?: string,
34
33
  margin: string,
35
34
  marginBottom: string,
@@ -64,7 +63,6 @@ const Select = ({
64
63
  label,
65
64
  htmlOptions = {},
66
65
  inline = false,
67
- inputOptions = {},
68
66
  multiple = false,
69
67
  name,
70
68
  onChange = () => undefined,
@@ -96,17 +94,14 @@ const Select = ({
96
94
  const angleDown = getAllIcons()["angleDown"].icon as unknown as { [key: string]: SVGElement }
97
95
 
98
96
  const selectWrapperClass = classnames(buildCss('pb_select_kit_wrapper'), { error }, className)
99
- const selectId = (inputOptions?.id as string) || name
100
-
101
97
  const selectBody =(() =>{
102
98
  if (children) return children
103
99
  return (
104
100
  <select
105
101
  {...htmlOptions}
106
102
  {...domSafeProps(props)}
107
- {...inputOptions}
108
103
  disabled={disabled}
109
- id={selectId}
104
+ id={name}
110
105
  multiple={multiple}
111
106
  name={name}
112
107
  onChange={onChange}
@@ -130,7 +125,7 @@ const Select = ({
130
125
  {label &&
131
126
  <label
132
127
  className="pb_select_kit_label"
133
- htmlFor={selectId}
128
+ htmlFor={name}
134
129
  >
135
130
  <Caption
136
131
  dark={props.dark}
@@ -140,7 +135,7 @@ const Select = ({
140
135
  }
141
136
  <label
142
137
  className={selectWrapperClass}
143
- htmlFor={selectId}
138
+ htmlFor={name}
144
139
  >
145
140
  {selectBody}
146
141
  { multiple !== true ?
@@ -1 +1 @@
1
- Select w/ Error shows that an option must be selected or is invalid (i.e. when used in a form it signals a user to fix an error).
1
+ Select w/ Error shows that the radio option must be selected or is invalid (ie when used in a form it signals a user to fix an error).
@@ -15,7 +15,6 @@ examples:
15
15
  - select_inline_compact: Select Inline Compact
16
16
  - select_attributes: Select W/ Attributes
17
17
  - select_multiple: Select Multiple
18
- - select_input_options: Input Options
19
18
 
20
19
 
21
20
 
@@ -34,7 +33,6 @@ examples:
34
33
  - select_inline_compact: Select Inline Compact
35
34
  - select_multiple: Select Multiple
36
35
  - select_react_hook: React Hook
37
- - select_input_options: Input Options
38
36
 
39
37
  swift:
40
38
  - select_default_swift: Default
@@ -12,4 +12,3 @@ export { default as SelectInlineCompact } from './_select_inline_compact.jsx'
12
12
  export { default as SelectMultiple } from './_select_multiple.jsx'
13
13
  export { default as SelectReactHook } from './_select_react_hook.jsx'
14
14
  export { default as SelectCustomSelectSubheaders } from './_select_custom_select_subheaders.jsx'
15
- export { default as SelectInputOptions } from './_select_input_options.jsx'
@@ -2,11 +2,11 @@
2
2
  id: nil,
3
3
  class: object.classnames ) do %>
4
4
  <% if object.label %>
5
- <label class="pb_select_kit_label" for="<%= object.input_options[:id] || object.name %>">
5
+ <label class="pb_select_kit_label" for="<%= object.name %>">
6
6
  <%= pb_rails("caption", props: { text: object.label, dark: object.dark }) %>
7
7
  </label>
8
8
  <% end %>
9
- <label class="<%= object.select_wrapper_class %>" for="<%= object.input_options[:id] || object.name %>">
9
+ <label class="<%= object.select_wrapper_class %>" for="<%= object.name %>">
10
10
  <% if content.present? %>
11
11
  <%= content %>
12
12
  <%= pb_rails("body", props: { status: "negative", text: object.error }) %>
@@ -14,8 +14,6 @@ module Playbook
14
14
  prop :error
15
15
  prop :include_blank
16
16
  prop :inline, type: Playbook::Props::Boolean, default: false
17
- prop :input_options, type: Playbook::Props::HashProp,
18
- default: {}
19
17
  prop :label
20
18
  prop :multiple, type: Playbook::Props::Boolean, default: false
21
19
  prop :name
@@ -40,7 +38,7 @@ module Playbook
40
38
  multiple: multiple,
41
39
  onchange: onchange,
42
40
  include_blank: include_blank,
43
- }.merge(attributes).merge(input_options)
41
+ }.merge(attributes)
44
42
  end
45
43
 
46
44
  def classname
@@ -65,27 +65,4 @@ test('returns multiple variant', () => {
65
65
  const selectElement = kit.querySelector('select');
66
66
 
67
67
  expect(selectElement).toHaveAttribute('multiple', '');
68
- });
69
-
70
- test('inputOptions are passed to select element', () => {
71
- render(
72
- <Select
73
- data={{ testid: testId }}
74
- inputOptions={{
75
- id: 'custom-select-id',
76
- className: 'custom-select-class',
77
- 'aria-label': 'Custom aria label',
78
- }}
79
- label="Favorite Food"
80
- name="food"
81
- options={options}
82
- />
83
- )
84
-
85
- const kit = screen.getByTestId(testId)
86
- const selectElement = kit.querySelector('select')
87
-
88
- expect(selectElement).toHaveAttribute('id', 'custom-select-id')
89
- expect(selectElement).toHaveClass('custom-select-class')
90
- expect(selectElement).toHaveAttribute('aria-label', 'Custom aria label')
91
68
  });