playbook_ui 14.11.1 → 14.12.0.pre.alpha.PBNTR456fixedconftoastrailsautoclose5728

Sign up to get free protection for your applications and to get access to all the features.
Files changed (195) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/_playbook.scss +3 -0
  3. data/app/pb_kits/playbook/pb_advanced_table/Components/CustomCell.tsx +18 -2
  4. data/app/pb_kits/playbook/pb_advanced_table/Components/TableHeaderCell.tsx +27 -5
  5. data/app/pb_kits/playbook/pb_advanced_table/SubKits/TableBody.tsx +17 -2
  6. data/app/pb_kits/playbook/pb_advanced_table/SubKits/TableHeader.tsx +23 -1
  7. data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.scss +29 -0
  8. data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.tsx +61 -4
  9. data/app/pb_kits/playbook/pb_advanced_table/advanced_table.html.erb +3 -3
  10. data/app/pb_kits/playbook/pb_advanced_table/advanced_table.rb +5 -1
  11. data/app/pb_kits/playbook/pb_advanced_table/advanced_table.test.jsx +1 -1
  12. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_loading.html.erb +33 -0
  13. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_loading_rails.md +1 -0
  14. data/app/pb_kits/playbook/pb_advanced_table/docs/{_advanced_table_loading.md → _advanced_table_loading_react.md} +2 -2
  15. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_no_subrows.jsx +50 -0
  16. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_pagination.jsx +1 -0
  17. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_pagination_with_props.jsx +1 -0
  18. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_responsive.html.erb +38 -0
  19. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows.jsx +60 -0
  20. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows.md +5 -0
  21. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows_actions.jsx +78 -0
  22. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows_actions.md +1 -0
  23. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows_header.jsx +53 -0
  24. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows_header.md +1 -0
  25. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows_no_subrows.jsx +52 -0
  26. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows_no_subrows.md +1 -0
  27. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_sort_control.md +2 -2
  28. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_table_props.html.erb +33 -0
  29. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_table_props_rails.md +1 -0
  30. data/app/pb_kits/playbook/pb_advanced_table/docs/advanced_table_mock_data_no_subrows.json +42 -0
  31. data/app/pb_kits/playbook/pb_advanced_table/docs/advanced_table_mock_data_with_id.json +299 -0
  32. data/app/pb_kits/playbook/pb_advanced_table/docs/example.yml +8 -0
  33. data/app/pb_kits/playbook/pb_advanced_table/docs/index.js +6 -1
  34. data/app/pb_kits/playbook/pb_advanced_table/table_body.rb +17 -3
  35. data/app/pb_kits/playbook/pb_advanced_table/table_header.html.erb +15 -11
  36. data/app/pb_kits/playbook/pb_advanced_table/table_header.rb +14 -3
  37. data/app/pb_kits/playbook/pb_advanced_table/table_row.html.erb +2 -2
  38. data/app/pb_kits/playbook/pb_advanced_table/table_row.rb +9 -1
  39. data/app/pb_kits/playbook/pb_advanced_table/table_subrow_header.html.erb +1 -1
  40. data/app/pb_kits/playbook/pb_advanced_table/table_subrow_header.rb +9 -0
  41. data/app/pb_kits/playbook/pb_avatar/_avatar.scss +5 -0
  42. data/app/pb_kits/playbook/pb_button/button.html.erb +2 -3
  43. data/app/pb_kits/playbook/pb_card/card.html.erb +21 -2
  44. data/app/pb_kits/playbook/pb_card/card.rb +7 -0
  45. data/app/pb_kits/playbook/pb_checkbox/checkbox.html.erb +1 -6
  46. data/app/pb_kits/playbook/pb_collapsible/collapsible.html.erb +3 -1
  47. data/app/pb_kits/playbook/pb_collapsible/collapsible.rb +3 -0
  48. data/app/pb_kits/playbook/pb_copy_button/_copy_button.scss +3 -0
  49. data/app/pb_kits/playbook/pb_copy_button/_copy_button.tsx +92 -0
  50. data/app/pb_kits/playbook/pb_copy_button/copy_button.test.jsx +64 -0
  51. data/app/pb_kits/playbook/pb_copy_button/docs/_copy_button_default.jsx +21 -0
  52. data/app/pb_kits/playbook/pb_copy_button/docs/_copy_button_from.jsx +45 -0
  53. data/app/pb_kits/playbook/pb_copy_button/docs/_copy_button_from.md +1 -0
  54. data/app/pb_kits/playbook/pb_copy_button/docs/example.yml +8 -0
  55. data/app/pb_kits/playbook/pb_copy_button/docs/index.js +2 -0
  56. data/app/pb_kits/playbook/pb_date_picker/date_picker.html.erb +24 -16
  57. data/app/pb_kits/playbook/pb_date_picker/date_picker.rb +2 -0
  58. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_default_date.md +1 -1
  59. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_turbo_frames.html.erb +13 -0
  60. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_turbo_frames_rails.md +3 -0
  61. data/app/pb_kits/playbook/pb_date_picker/docs/example.yml +1 -0
  62. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_with_cards_rails.html.erb +1 -3
  63. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_with_cards_rails.md +7 -0
  64. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_with_list_rails.html.erb +3 -9
  65. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_with_list_rails.md +5 -0
  66. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_with_selectable_list_rails.html.erb +38 -0
  67. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_with_selectable_list_rails.md +3 -0
  68. data/app/pb_kits/playbook/pb_draggable/docs/example.yml +1 -0
  69. data/app/pb_kits/playbook/pb_drawer/_drawer.scss +145 -183
  70. data/app/pb_kits/playbook/pb_drawer/_drawer.tsx +158 -268
  71. data/app/pb_kits/playbook/pb_drawer/context.ts +11 -0
  72. data/app/pb_kits/playbook/pb_drawer/docs/_drawer_behavior.jsx +38 -0
  73. data/app/pb_kits/playbook/pb_drawer/docs/_drawer_borders.jsx +3 -45
  74. data/app/pb_kits/playbook/pb_drawer/docs/_drawer_breakpoints.jsx +0 -1
  75. data/app/pb_kits/playbook/pb_drawer/docs/_drawer_default.jsx +9 -16
  76. data/app/pb_kits/playbook/pb_drawer/docs/_drawer_menu.jsx +44 -19
  77. data/app/pb_kits/playbook/pb_drawer/docs/_drawer_menu.md +21 -3
  78. data/app/pb_kits/playbook/pb_drawer/docs/_drawer_overlay.jsx +16 -21
  79. data/app/pb_kits/playbook/pb_drawer/docs/_drawer_sizes.jsx +2 -19
  80. data/app/pb_kits/playbook/pb_drawer/docs/example.yml +2 -1
  81. data/app/pb_kits/playbook/pb_drawer/docs/index.js +1 -0
  82. data/app/pb_kits/playbook/pb_drawer/drawer.test.jsx +5 -5
  83. data/app/pb_kits/playbook/pb_drawer/hooks/useBreakpoint.tsx +60 -0
  84. data/app/pb_kits/playbook/pb_drawer/hooks/useDrawerAnimation.tsx +21 -0
  85. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_subtle_variant.md +1 -1
  86. data/app/pb_kits/playbook/pb_dropdown/dropdown.html.erb +7 -12
  87. data/app/pb_kits/playbook/pb_dropdown/dropdown_container.html.erb +9 -14
  88. data/app/pb_kits/playbook/pb_dropdown/dropdown_option.html.erb +6 -11
  89. data/app/pb_kits/playbook/pb_dropdown/dropdown_trigger.html.erb +8 -14
  90. data/app/pb_kits/playbook/pb_fixed_confirmation_toast/docs/_fixed_confirmation_toast_auto_close.html.erb +74 -0
  91. data/app/pb_kits/playbook/pb_fixed_confirmation_toast/docs/_fixed_confirmation_toast_auto_close_rails.md +3 -0
  92. data/app/pb_kits/playbook/pb_fixed_confirmation_toast/docs/example.yml +1 -0
  93. data/app/pb_kits/playbook/pb_fixed_confirmation_toast/index.js +24 -13
  94. data/app/pb_kits/playbook/pb_icon_button/_icon_button.scss +78 -0
  95. data/app/pb_kits/playbook/pb_icon_button/docs/_icon_button_default.html.erb +3 -0
  96. data/app/pb_kits/playbook/pb_icon_button/docs/example.yml +7 -0
  97. data/app/pb_kits/playbook/pb_icon_button/icon_button.html.erb +16 -0
  98. data/app/pb_kits/playbook/pb_icon_button/icon_button.rb +22 -0
  99. data/app/pb_kits/playbook/pb_list/item.html.erb +30 -8
  100. data/app/pb_kits/playbook/pb_list/item.rb +7 -0
  101. data/app/pb_kits/playbook/pb_list/list.html.erb +31 -11
  102. data/app/pb_kits/playbook/pb_list/list.rb +4 -0
  103. data/app/pb_kits/playbook/pb_loading_inline/_loading_inline.tsx +6 -1
  104. data/app/pb_kits/playbook/pb_multiple_users/_multiple_users.scss +4 -0
  105. data/app/pb_kits/playbook/pb_multiple_users/_multiple_users.tsx +1 -0
  106. data/app/pb_kits/playbook/pb_multiple_users/multiple_users.html.erb +1 -1
  107. data/app/pb_kits/playbook/pb_phone_number_input/_phone_number_input.tsx +30 -12
  108. data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_format.html.erb +15 -0
  109. data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_format.jsx +24 -0
  110. data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_format.md +1 -0
  111. data/app/pb_kits/playbook/pb_phone_number_input/docs/example.yml +3 -1
  112. data/app/pb_kits/playbook/pb_phone_number_input/docs/index.js +1 -0
  113. data/app/pb_kits/playbook/pb_phone_number_input/phone_number_input.rb +3 -0
  114. data/app/pb_kits/playbook/pb_phone_number_input/phone_number_input.test.js +20 -1
  115. data/app/pb_kits/playbook/pb_radio/_radio.scss +12 -8
  116. data/app/pb_kits/playbook/pb_radio/docs/_radio_custom_children.jsx +8 -3
  117. data/app/pb_kits/playbook/pb_select/_select.scss +3 -5
  118. data/app/pb_kits/playbook/pb_select/_select.tsx +5 -1
  119. data/app/pb_kits/playbook/pb_select/select.html.erb +2 -2
  120. data/app/pb_kits/playbook/pb_selectable_icon/_selectable_icon.tsx +9 -1
  121. data/app/pb_kits/playbook/pb_selectable_icon/docs/_selectable_icon_default.jsx +4 -1
  122. data/app/pb_kits/playbook/pb_selectable_icon/docs/_selectable_icon_single_select.jsx +4 -1
  123. data/app/pb_kits/playbook/pb_selectable_list/selectable_list.html.erb +17 -3
  124. data/app/pb_kits/playbook/pb_selectable_list/selectable_list.rb +3 -0
  125. data/app/pb_kits/playbook/pb_selectable_list/selectable_list_item.html.erb +11 -4
  126. data/app/pb_kits/playbook/pb_selectable_list/selectable_list_item.rb +3 -0
  127. data/app/pb_kits/playbook/pb_table/_table.tsx +2 -3
  128. data/app/pb_kits/playbook/pb_table/docs/_table_sticky_columns.html.erb +74 -0
  129. data/app/pb_kits/playbook/pb_table/docs/_table_sticky_columns_rails.md +3 -0
  130. data/app/pb_kits/playbook/pb_table/docs/_table_sticky_left_columns_rails.md +2 -2
  131. data/app/pb_kits/playbook/pb_table/docs/_table_sticky_right_columns.html.erb +74 -0
  132. data/app/pb_kits/playbook/pb_table/docs/_table_sticky_right_columns_rails.md +3 -0
  133. data/app/pb_kits/playbook/pb_table/docs/_table_with_collapsible.html.erb +47 -0
  134. data/app/pb_kits/playbook/pb_table/docs/_table_with_collapsible_rails.md +2 -0
  135. data/app/pb_kits/playbook/pb_table/docs/_table_with_collapsible_with_custom_content.jsx +12 -8
  136. data/app/pb_kits/playbook/pb_table/docs/_table_with_collapsible_with_custom_content_rails.html.erb +52 -0
  137. data/app/pb_kits/playbook/pb_table/docs/_table_with_collapsible_with_custom_content_rails.md +0 -0
  138. data/app/pb_kits/playbook/pb_table/docs/_table_with_collapsible_with_nested_rows_rails.html.erb +52 -0
  139. data/app/pb_kits/playbook/pb_table/docs/_table_with_collapsible_with_nested_rows_rails.md +3 -0
  140. data/app/pb_kits/playbook/pb_table/docs/_table_with_collapsible_with_nested_table_rails.html.erb +80 -0
  141. data/app/pb_kits/playbook/pb_table/docs/_table_with_collapsible_with_nested_table_rails.md +1 -0
  142. data/app/pb_kits/playbook/pb_table/docs/example.yml +6 -0
  143. data/app/pb_kits/playbook/pb_table/index.ts +187 -88
  144. data/app/pb_kits/playbook/pb_table/styles/_collapsible.scss +12 -0
  145. data/app/pb_kits/playbook/pb_table/styles/_scroll.scss +6 -5
  146. data/app/pb_kits/playbook/pb_table/table.html.erb +1 -1
  147. data/app/pb_kits/playbook/pb_table/table.rb +17 -2
  148. data/app/pb_kits/playbook/pb_table/table_row.html.erb +20 -1
  149. data/app/pb_kits/playbook/pb_table/table_row.rb +5 -0
  150. data/app/pb_kits/playbook/pb_table/utilities/addDataTitle.ts +22 -0
  151. data/app/pb_kits/playbook/pb_text_input/docs/_text_input_mask.html.erb +46 -0
  152. data/app/pb_kits/playbook/pb_text_input/docs/_text_input_mask_rails.md +3 -0
  153. data/app/pb_kits/playbook/pb_text_input/docs/example.yml +2 -1
  154. data/app/pb_kits/playbook/pb_text_input/index.js +103 -0
  155. data/app/pb_kits/playbook/pb_text_input/text_input.html.erb +4 -0
  156. data/app/pb_kits/playbook/pb_text_input/text_input.rb +33 -3
  157. data/app/pb_kits/playbook/pb_timeline/_timeline.scss +30 -30
  158. data/app/pb_kits/playbook/pb_tooltip/_tooltip.tsx +3 -1
  159. data/app/pb_kits/playbook/pb_typeahead/_typeahead.tsx +3 -2
  160. data/app/pb_kits/playbook/pb_typeahead/components/ClearIndicator.tsx +12 -4
  161. data/app/pb_kits/playbook/pb_typeahead/components/Control.tsx +5 -1
  162. data/app/pb_kits/playbook/pb_typeahead/components/IndicatorsContainer.tsx +8 -3
  163. data/app/pb_kits/playbook/pb_typeahead/components/MenuList.tsx +6 -1
  164. data/app/pb_kits/playbook/pb_typeahead/components/Option.tsx +21 -6
  165. data/app/pb_kits/playbook/pb_typeahead/components/Placeholder.tsx +13 -6
  166. data/app/pb_kits/playbook/pb_typeahead/components/ValueContainer.tsx +7 -3
  167. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_custom_menu_list.jsx +2 -0
  168. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_truncated_text.html.erb +19 -0
  169. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_truncated_text.jsx +27 -0
  170. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_truncated_text.md +1 -0
  171. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_with_pills_async.jsx +4 -2
  172. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_with_pills_async_custom_options.jsx +5 -5
  173. data/app/pb_kits/playbook/pb_typeahead/docs/example.yml +2 -0
  174. data/app/pb_kits/playbook/pb_typeahead/docs/index.js +1 -0
  175. data/dist/chunks/_typeahead-BIhRQo8Q.js +36 -0
  176. data/dist/chunks/_weekday_stacked-VKMYuo6-.js +45 -0
  177. data/dist/chunks/lazysizes-B7xYodB-.js +1 -0
  178. data/dist/chunks/{lib-B7sgJtGS.js → lib-kMuhBuU7.js} +2 -2
  179. data/dist/chunks/{pb_form_validation-C5Cc0-1v.js → pb_form_validation-DBJ0wZuS.js} +1 -1
  180. data/dist/chunks/vendor.js +1 -1
  181. data/dist/menu.yml +12 -0
  182. data/dist/playbook-doc.js +1 -1
  183. data/dist/playbook-rails-react-bindings.js +1 -1
  184. data/dist/playbook-rails.js +1 -1
  185. data/dist/playbook.css +1 -1
  186. data/lib/playbook/pb_forms_global_props_helper.rb +136 -0
  187. data/lib/playbook/pb_forms_helper.rb +13 -4
  188. data/lib/playbook/version.rb +2 -2
  189. metadata +88 -11
  190. data/dist/chunks/_typeahead-C2iCBqxQ.js +0 -36
  191. data/dist/chunks/_weekday_stacked-E-5KcEkc.js +0 -45
  192. data/dist/chunks/lazysizes-DHz07jlL.js +0 -1
  193. /data/app/pb_kits/playbook/pb_advanced_table/docs/{_advanced_table_table_props.md → _advanced_table_table_props_react.md} +0 -0
  194. /data/app/pb_kits/playbook/pb_fixed_confirmation_toast/docs/{_fixed_confirmation_toast_auto_close.md → _fixed_confirmation_toast_auto_close_react.md} +0 -0
  195. /data/app/pb_kits/playbook/pb_table/docs/{_table_with_collapsible.md → _table_with_collapsible_react.md} +0 -0
@@ -8,6 +8,11 @@ module Playbook
8
8
  prop :tag, type: Playbook::Props::Enum,
9
9
  values: %w[table div],
10
10
  default: "table"
11
+ prop :collapsible, type: Playbook::Props::Boolean,
12
+ default: false
13
+ prop :collapsible_content
14
+ prop :collapsible_side_highlight, type: Playbook::Props::Boolean,
15
+ default: true
11
16
 
12
17
  def classname
13
18
  generate_classname("pb_table_row_kit", side_highlight_class) + tag_class
@@ -0,0 +1,22 @@
1
+ export const addDataTitle = () => {
2
+ const tables = document.querySelectorAll('.table-responsive-collapse');
3
+ // Each Table
4
+ [].forEach.call(tables, (table: HTMLTableElement) => {
5
+ // Header Titles
6
+ const headers: string[] = [];
7
+ [].forEach.call(table.querySelectorAll('th'), (header: HTMLTableCellElement) => {
8
+ const colSpan = header.colSpan
9
+ for (let i = 0; i < colSpan; i++) {
10
+ headers.push(header.textContent.replace(/\r?\n|\r/, ''));
11
+ }
12
+ });
13
+ // for each row in tbody
14
+ [].forEach.call(table.querySelectorAll('tbody tr'), (row: HTMLTableRowElement) => {
15
+ // for each cell
16
+ [].forEach.call(row.cells, (cell: HTMLTableCellElement, headerIndex: number) => {
17
+ // apply the attribute
18
+ cell.setAttribute('data-title', headers[headerIndex])
19
+ })
20
+ })
21
+ });
22
+ }
@@ -0,0 +1,46 @@
1
+ <%= pb_rails("text_input", props: {
2
+ label: "Currency",
3
+ mask: "currency",
4
+ margin_bottom: "md",
5
+ name: "currency_name",
6
+ placeholder:"$0.00"
7
+ }) %>
8
+
9
+ <%= pb_rails("text_input", props: {
10
+ label: "ZIP Code",
11
+ mask: "zip_code",
12
+ margin_bottom: "md",
13
+ placeholder: "12345"
14
+ }) %>
15
+
16
+ <%= pb_rails("text_input", props: {
17
+ label: "Postal Code",
18
+ mask: "postal_code",
19
+ placeholder: "12345-6789",
20
+ margin_bottom: "md",
21
+ }) %>
22
+
23
+ <%= pb_rails("text_input", props: {
24
+ label: "SSN",
25
+ mask: "ssn",
26
+ margin_bottom: "md",
27
+ placeholder: "123-45-6789"
28
+ }) %>
29
+
30
+ <%= pb_rails("title" , props: {
31
+ text: "Hidden Input Under The Hood",
32
+ padding_bottom: "sm"
33
+ })%>
34
+
35
+ <%= pb_rails("text_input", props: {
36
+ label: "Currency",
37
+ mask: "currency",
38
+ margin_bottom: "md",
39
+ name: "currency_name",
40
+ id: "example-currency",
41
+ placeholder: "$0.00",
42
+ }) %>
43
+
44
+ <style>
45
+ #example-currency-sanitized {display: flex !important;}
46
+ </style>
@@ -0,0 +1,3 @@
1
+ The mask prop lets you style your inputs while maintaining the value that the user typed in.
2
+
3
+ It uses a hidden input field to submit the unformatted value as it will have the proper `name` attribute. It will also copy the id field with a `"#{your-id-sanitized}"`
@@ -8,6 +8,7 @@ examples:
8
8
  - text_input_inline: Inline
9
9
  - text_input_no_label: No Label
10
10
  - text_input_options: Input Options
11
+ - text_input_mask: Mask
11
12
  react:
12
13
  - text_input_default: Default
13
14
  - text_input_error: With Error
@@ -23,4 +24,4 @@ examples:
23
24
  - text_input_error_swift: With Error
24
25
  - text_input_disabled_swift: Disabled
25
26
  - text_input_add_on_swift: Add On
26
- - text_input_props_swift: ""
27
+ - text_input_props_swift: ""
@@ -0,0 +1,103 @@
1
+ export default class PbTextInput {
2
+ static start() {
3
+ const inputElements = document.querySelectorAll('[data-pb-input-mask="true"]');
4
+
5
+ inputElements.forEach((inputElement) => {
6
+ inputElement.addEventListener("input", (event) => {
7
+ const maskType = inputElement.getAttribute("mask");
8
+ const cursorPosition = inputElement.selectionStart;
9
+
10
+ let rawValue = event.target.value;
11
+ let formattedValue = rawValue;
12
+
13
+ // Apply formatting based on the mask type
14
+ switch (maskType) {
15
+ case "currency":
16
+ formattedValue = formatCurrency(rawValue);
17
+ break;
18
+ case "ssn":
19
+ formattedValue = formatSSN(rawValue);
20
+ break;
21
+ case "postal_code":
22
+ formattedValue = formatPostalCode(rawValue);
23
+ break;
24
+ case "zip_code":
25
+ formattedValue = formatZipCode(rawValue);
26
+ break;
27
+ }
28
+
29
+ // Update the sanitized input field in the same wrapper
30
+ const sanitizedInput = inputElement
31
+ .closest(".text_input_wrapper")
32
+ ?.querySelector('[data="sanitized-pb-input"]');
33
+
34
+ if (sanitizedInput) {
35
+ switch (maskType) {
36
+ case "ssn":
37
+ sanitizedInput.value = sanitizeSSN(formattedValue);
38
+ break;
39
+ case "currency":
40
+ sanitizedInput.value = sanitizeCurrency(formattedValue);
41
+ break;
42
+ default:
43
+ sanitizedInput.value = formattedValue;
44
+ }
45
+ }
46
+
47
+ inputElement.value = formattedValue;
48
+ setCursorPosition(inputElement, cursorPosition, rawValue, formattedValue);
49
+ });
50
+ });
51
+
52
+ }
53
+ }
54
+
55
+ function formatCurrency(value) {
56
+ const numericValue = value.replace(/[^0-9]/g, "").slice(0, 15);
57
+
58
+ if (!numericValue) return "";
59
+
60
+ const dollars = parseFloat((parseInt(numericValue) / 100).toFixed(2));
61
+ if (dollars === 0) return "";
62
+
63
+ return new Intl.NumberFormat("en-US", {
64
+ style: "currency",
65
+ currency: "USD",
66
+ maximumFractionDigits: 2,
67
+ }).format(dollars);
68
+ }
69
+
70
+ function formatSSN(value) {
71
+ const cleaned = value.replace(/\D/g, "").slice(0, 9);
72
+ return cleaned
73
+ .replace(/(\d{5})(?=\d)/, "$1-")
74
+ .replace(/(\d{3})(?=\d)/, "$1-");
75
+ }
76
+
77
+ function formatZipCode(value) {
78
+ return value.replace(/\D/g, "").slice(0, 5);
79
+ }
80
+
81
+ function formatPostalCode(value) {
82
+ const cleaned = value.replace(/\D/g, "").slice(0, 9);
83
+ return cleaned.replace(/(\d{5})(?=\d)/, "$1-");
84
+ }
85
+
86
+ function sanitizeSSN(input) {
87
+ return input.replace(/\D/g, "");
88
+ }
89
+
90
+ function sanitizeCurrency(input) {
91
+ return input.replace(/[$,]/g, "");
92
+ }
93
+
94
+ // function to set cursor position
95
+ function setCursorPosition(inputElement, cursorPosition, rawValue, formattedValue) {
96
+ const difference = formattedValue.length - rawValue.length;
97
+
98
+ const newPosition = Math.max(0, cursorPosition + difference);
99
+
100
+ requestAnimationFrame(() => {
101
+ inputElement.setSelectionRange(newPosition, newPosition);
102
+ });
103
+ }
@@ -13,9 +13,13 @@
13
13
  <%= pb_rails("text_input/add_on", props: object.add_on_props) do %>
14
14
  <%= input_tag %>
15
15
  <% end %>
16
+ <% elsif mask.present? %>
17
+ <%= input_tag %>
18
+ <%= tag(:input, data: "sanitized-pb-input", id: sanitized_id, name: object.name, style: "display: none;") %>
16
19
  <% else %>
17
20
  <%= input_tag %>
18
21
  <% end %>
19
22
  <%= pb_rails("body", props: {dark: object.dark, status: "negative", text: object.error}) if object.error %>
20
23
  <% end %>
21
24
  <% end %>
25
+
@@ -4,6 +4,15 @@
4
4
  module Playbook
5
5
  module PbTextInput
6
6
  class TextInput < Playbook::KitBase
7
+ VALID_MASKS = %w[currency zipCode postalCode ssn].freeze
8
+
9
+ MASK_PATTERNS = {
10
+ "currency" => '^\$\d{1,3}(?:,\d{3})*(?:\.\d{2})?$',
11
+ "zip_code" => '\d{5}',
12
+ "postal_code" => '\d{5}-\d{4}',
13
+ "ssn" => '\d{3}-\d{2}-\d{4}',
14
+ }.freeze
15
+
7
16
  prop :autocomplete, type: Playbook::Props::Boolean,
8
17
  default: true
9
18
  prop :disabled, type: Playbook::Props::Boolean,
@@ -25,6 +34,9 @@ module Playbook
25
34
  prop :add_on, type: Playbook::Props::NestedProps,
26
35
  nested_kit: Playbook::PbTextInput::AddOn
27
36
 
37
+ prop :mask, type: Playbook::Props::String,
38
+ default: nil
39
+
28
40
  def classname
29
41
  default_margin_bottom = margin_bottom.present? ? "" : " mb_sm"
30
42
  generate_classname("pb_text_input_kit") + default_margin_bottom + error_class + inline_class
@@ -46,6 +58,10 @@ module Playbook
46
58
  { dark: dark }.merge(add_on || {})
47
59
  end
48
60
 
61
+ def sanitized_id
62
+ "#{object.id}-sanitized" if id.present?
63
+ end
64
+
49
65
  private
50
66
 
51
67
  def all_input_options
@@ -55,12 +71,13 @@ module Playbook
55
71
  data: validation_data,
56
72
  disabled: disabled,
57
73
  id: input_options.dig(:id) || id,
58
- name: name,
59
- pattern: validation_pattern,
74
+ name: mask.present? ? "" : name,
75
+ pattern: validation_pattern || mask_pattern,
60
76
  placeholder: placeholder,
61
77
  required: required,
62
78
  type: type,
63
79
  value: value,
80
+ mask: mask,
64
81
  }.merge(input_options)
65
82
  end
66
83
 
@@ -75,7 +92,7 @@ module Playbook
75
92
  def validation_data
76
93
  fields = input_options.dig(:data) || {}
77
94
  fields[:message] = validation_message unless validation_message.blank?
78
- fields
95
+ mask ? fields.merge(pb_input_mask: true) : fields
79
96
  end
80
97
 
81
98
  def error_class
@@ -85,6 +102,19 @@ module Playbook
85
102
  def inline_class
86
103
  inline ? " inline" : ""
87
104
  end
105
+
106
+ def mask_data
107
+ return {} unless mask
108
+ raise ArgumentError, "mask must be one of: #{VALID_MASKS.join(', ')}" unless VALID_MASKS.include?(mask)
109
+
110
+ { mask: mask }
111
+ end
112
+
113
+ def mask_pattern
114
+ return nil unless mask
115
+
116
+ MASK_PATTERNS[mask]
117
+ end
88
118
  end
89
119
  end
90
120
  end
@@ -50,7 +50,7 @@ $gap_lg: $height_from_top + $space_lg;
50
50
  >div {
51
51
  &:last-child {
52
52
  flex-basis: auto !important;
53
- [class=pb_timeline_item_step] {
53
+ [class^=pb_timeline_item_step] {
54
54
  [class=pb_timeline_item_connector] {
55
55
  opacity: 0;
56
56
  }
@@ -66,29 +66,25 @@ $gap_lg: $height_from_top + $space_lg;
66
66
  [class*=pb_timeline_item_kit] {
67
67
  &[class*=_solid] {
68
68
  flex-basis: 100%;
69
- [class=pb_timeline_item_left_block] {
70
- height: 0px;
71
- }
72
- [class=pb_timeline_item_step] {
69
+ [class^=pb_timeline_item_step] {
73
70
  @include flex_wrapper(row);
71
+ align-items: center;
74
72
  margin-top: $space_xs;
75
73
  margin-bottom: $space_xs;
76
74
  [class=pb_timeline_item_connector] {
77
- @include pb_timeline_line_solid($connector_width, $connector_width, $height_from_top $icon_margin 0 $icon_margin );
75
+ @include pb_timeline_line_solid($connector_width, $connector_width, 0 $icon_margin 0 $icon_margin );
78
76
  }
79
77
  }
80
78
  }
81
79
  &[class*=_dotted] {
82
80
  flex-basis: 100%;
83
- [class=pb_timeline_item_left_block] {
84
- height: 0;
85
- }
86
- [class=pb_timeline_item_step] {
81
+ [class^=pb_timeline_item_step] {
87
82
  @include flex_wrapper(row);
83
+ align-items: center;
88
84
  margin-top: $space_xs;
89
85
  margin-bottom: $space_xs;
90
86
  [class=pb_timeline_item_connector] {
91
- @include pb_timeline_line_dotted_horizontal($connector_width, $connector_width, $height_from_top $icon_margin 0 $icon_margin );
87
+ @include pb_timeline_line_dotted_horizontal($connector_width, $connector_width, 0 $icon_margin 0 $icon_margin );
92
88
  }
93
89
  }
94
90
  }
@@ -99,7 +95,7 @@ $gap_lg: $height_from_top + $space_lg;
99
95
  >div {
100
96
  &:last-child {
101
97
  flex-basis: auto !important;
102
- [class=pb_timeline_item_step] {
98
+ [class^=pb_timeline_item_step] {
103
99
  [class=pb_timeline_item_connector] {
104
100
  opacity: 0;
105
101
  }
@@ -129,12 +125,12 @@ $gap_lg: $height_from_top + $space_lg;
129
125
  }
130
126
  }
131
127
  }
132
- [class=pb_timeline_item_step] {
128
+ [class^=pb_timeline_item_step] {
133
129
  @include flex_wrapper(row);
134
130
  margin-top: $space_xs;
135
131
  margin-bottom: $space_xs;
136
132
  [class=pb_timeline_item_connector] {
137
- @include pb_timeline_line_solid($connector_width, $connector_width, $height_from_top $icon_margin 0 $icon_margin );
133
+ @include pb_timeline_line_solid($connector_width, $connector_width, 0 $icon_margin 0 $icon_margin );
138
134
  }
139
135
  }
140
136
  }
@@ -153,12 +149,12 @@ $gap_lg: $height_from_top + $space_lg;
153
149
  }
154
150
  }
155
151
  }
156
- [class=pb_timeline_item_step] {
152
+ [class^=pb_timeline_item_step] {
157
153
  @include flex_wrapper(row);
158
154
  margin-top: $space_xs;
159
155
  margin-bottom: $space_xs;
160
156
  [class=pb_timeline_item_connector] {
161
- @include pb_timeline_line_dotted_horizontal($connector_width, $connector_width, $height_from_top $icon_margin 0 $icon_margin );
157
+ @include pb_timeline_line_dotted_horizontal($connector_width, $connector_width, 0 $icon_margin 0 $icon_margin );
162
158
  }
163
159
  }
164
160
  }
@@ -170,7 +166,7 @@ $gap_lg: $height_from_top + $space_lg;
170
166
  align-items: flex-start;
171
167
  align-self: auto;
172
168
  >div:last-child {
173
- [class=pb_timeline_item_step] {
169
+ [class^=pb_timeline_item_step] {
174
170
  [class=pb_timeline_item_connector] {
175
171
  opacity: 0;
176
172
  }
@@ -180,13 +176,14 @@ $gap_lg: $height_from_top + $space_lg;
180
176
  @include flex_wrapper(row);
181
177
  &[class*=_solid] {
182
178
  flex-basis: 100%;
183
- [class=pb_timeline_item_step] {
179
+ [class^=pb_timeline_item_step] {
184
180
  @include flex_wrapper(column);
181
+ align-items: center;
185
182
  align-content: flex-start;
186
183
  margin-right: $space_sm;
187
184
  margin-left: $space_sm;
188
185
  [class=pb_timeline_item_connector] {
189
- @include pb_timeline_line_solid($connector_width, $connector_width, $icon_margin 0 $icon_margin $height_from_top);
186
+ @include pb_timeline_line_solid($connector_width, $connector_width, $icon_margin 0 $icon_margin 0);
190
187
  }
191
188
  }
192
189
  [class=pb_timeline_item_left_block] {
@@ -200,12 +197,13 @@ $gap_lg: $height_from_top + $space_lg;
200
197
  }
201
198
  &[class*=_dotted] {
202
199
  flex-basis: 100%;
203
- [class=pb_timeline_item_step] {
200
+ [class^=pb_timeline_item_step] {
204
201
  @include flex_wrapper(column);
202
+ align-items: center;
205
203
  margin-right: $space_sm;
206
204
  margin-left: $space_sm;
207
205
  [class=pb_timeline_item_connector] {
208
- @include pb_timeline_line_dotted_vertical($connector_width, $connector_width, $icon_margin 0 $icon_margin $height_from_top);
206
+ @include pb_timeline_line_dotted_vertical($connector_width, $connector_width, $icon_margin 0 $icon_margin 0);
209
207
  }
210
208
  }
211
209
  [class=pb_timeline_item_left_block] {
@@ -223,7 +221,7 @@ $gap_lg: $height_from_top + $space_lg;
223
221
  align-items: flex-start;
224
222
  align-self: auto;
225
223
  >div:last-child {
226
- [class=pb_timeline_item_step] {
224
+ [class^=pb_timeline_item_step] {
227
225
  [class=pb_timeline_item_connector] {
228
226
  opacity: 0;
229
227
  }
@@ -233,13 +231,14 @@ $gap_lg: $height_from_top + $space_lg;
233
231
  @include flex_wrapper(row);
234
232
  &[class*=_solid] {
235
233
  flex-basis: 100%;
236
- [class=pb_timeline_item_step] {
234
+ [class^=pb_timeline_item_step] {
237
235
  @include flex_wrapper(column);
236
+ align-items: center;
238
237
  align-content: flex-start;
239
238
  margin-right: $space_sm;
240
239
  margin-left: $space_sm;
241
240
  [class=pb_timeline_item_connector] {
242
- @include pb_timeline_line_solid($connector_width, $connector_width, $icon_margin 0 $icon_margin $height_from_top);
241
+ @include pb_timeline_line_solid($connector_width, $connector_width, $icon_margin 0 $icon_margin 0);
243
242
  }
244
243
  }
245
244
  [class=pb_timeline_item_left_block] {
@@ -253,12 +252,13 @@ $gap_lg: $height_from_top + $space_lg;
253
252
  }
254
253
  &[class*=_dotted] {
255
254
  flex-basis: 100%;
256
- [class=pb_timeline_item_step] {
255
+ [class^=pb_timeline_item_step] {
257
256
  @include flex_wrapper(column);
257
+ align-items: center;
258
258
  margin-right: $space_sm;
259
259
  margin-left: $space_sm;
260
260
  [class=pb_timeline_item_connector] {
261
- @include pb_timeline_line_dotted_vertical($connector_width, $connector_width, $icon_margin 0 $icon_margin $height_from_top);
261
+ @include pb_timeline_line_dotted_vertical($connector_width, $connector_width, $icon_margin 0 $icon_margin 0);
262
262
  }
263
263
  }
264
264
  [class=pb_timeline_item_left_block] {
@@ -274,7 +274,7 @@ $gap_lg: $height_from_top + $space_lg;
274
274
  }
275
275
  &[class*=_gap_xs] {
276
276
  [class*=pb_timeline_item_kit] {
277
- [class=pb_timeline_item_step] {
277
+ [class^=pb_timeline_item_step] {
278
278
  [class=pb_timeline_item_connector] {
279
279
  height: $gap_xs !important;
280
280
  }
@@ -283,7 +283,7 @@ $gap_lg: $height_from_top + $space_lg;
283
283
  }
284
284
  &[class*=_gap_sm] {
285
285
  [class*=pb_timeline_item_kit] {
286
- [class=pb_timeline_item_step] {
286
+ [class^=pb_timeline_item_step] {
287
287
  [class=pb_timeline_item_connector] {
288
288
  height: $gap_sm !important;
289
289
  }
@@ -292,7 +292,7 @@ $gap_lg: $height_from_top + $space_lg;
292
292
  }
293
293
  &[class*=_gap_md] {
294
294
  [class*=pb_timeline_item_kit] {
295
- [class=pb_timeline_item_step] {
295
+ [class^=pb_timeline_item_step] {
296
296
  [class=pb_timeline_item_connector] {
297
297
  height: $gap_md !important;
298
298
  }
@@ -301,7 +301,7 @@ $gap_lg: $height_from_top + $space_lg;
301
301
  }
302
302
  &[class*=_gap_lg] {
303
303
  [class*=pb_timeline_item_kit] {
304
- [class=pb_timeline_item_step] {
304
+ [class^=pb_timeline_item_step] {
305
305
  [class=pb_timeline_item_connector] {
306
306
  height: $gap_lg !important;
307
307
  }
@@ -32,6 +32,7 @@ type TooltipProps = {
32
32
  position?: "absolute" | "fixed";
33
33
  text: string,
34
34
  showTooltip?: boolean,
35
+ forceOpenTooltip?: boolean,
35
36
  } & GlobalProps
36
37
 
37
38
  const Tooltip = forwardRef((props: TooltipProps, ref: ForwardedRef<unknown>): React.ReactElement => {
@@ -49,6 +50,7 @@ const Tooltip = forwardRef((props: TooltipProps, ref: ForwardedRef<unknown>): Re
49
50
  text,
50
51
  showTooltip = true,
51
52
  zIndex,
53
+ forceOpenTooltip = false,
52
54
  ...rest
53
55
  } = props
54
56
 
@@ -135,7 +137,7 @@ const Tooltip = forwardRef((props: TooltipProps, ref: ForwardedRef<unknown>): Re
135
137
  >
136
138
  {children}
137
139
  </div>
138
- {open && (
140
+ {(open || forceOpenTooltip) && (
139
141
  <div
140
142
  {...getFloatingProps({
141
143
  className: `tooltip_tooltip ${placement} visible`,
@@ -42,8 +42,8 @@ type TypeaheadProps = {
42
42
  id?: string,
43
43
  label?: string,
44
44
  loadOptions?: string | Noop,
45
- getOptionLabel?: string | (() => any),
46
- getOptionValue?: string | (() => any),
45
+ getOptionLabel?: string | (() => string),
46
+ getOptionValue?: string | (() => string),
47
47
  name?: string,
48
48
  marginBottom?: "none" | "xxs" | "xs" | "sm" | "md" | "lg" | "xl",
49
49
  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",
@@ -109,6 +109,7 @@ const Typeahead = ({
109
109
  multiKit: '',
110
110
  onCreateOption: null as null,
111
111
  plusIcon: false,
112
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
112
113
  onMultiValueClick: (_option: SelectValueType): any => undefined,
113
114
  pillColor: pillColor,
114
115
  ...props,
@@ -1,16 +1,24 @@
1
1
  import React, { useEffect } from 'react'
2
2
  import { components } from 'react-select'
3
3
 
4
- const ClearContainer = (props: any) => {
4
+ type ClearContainerProps = {
5
+ children: React.ReactNode,
6
+ selectProps?: {
7
+ id: string,
8
+ },
9
+ clearValue: () => void,
10
+ }
11
+
12
+ const ClearContainer = (props: ClearContainerProps): React.ReactElement => {
5
13
  const { selectProps, clearValue } = props
6
14
  useEffect(() => {
7
15
  document.addEventListener(`pb-typeahead-kit-${selectProps.id}:clear`, clearValue)
8
- }, [true])
16
+ }, [clearValue, selectProps.id])
9
17
 
10
18
  return (
11
19
  <components.ClearIndicator
12
- className="clear_indicator"
13
- {...props}
20
+ className="clear_indicator"
21
+ {...props}
14
22
  />
15
23
  )
16
24
  }
@@ -5,7 +5,11 @@ import Flex from '../../pb_flex/_flex'
5
5
  import TextInput from '../../pb_text_input/_text_input'
6
6
 
7
7
  type Props = {
8
- selectProps: any,
8
+ selectProps: {
9
+ dark?: boolean,
10
+ label: string,
11
+ error?: string,
12
+ },
9
13
  }
10
14
 
11
15
  const TypeaheadControl = (props: Props) => (
@@ -1,10 +1,15 @@
1
1
  import React from 'react'
2
2
  import { components } from 'react-select'
3
3
 
4
- const IndicatorsContainer = (props: any) => (
4
+ type IndicatorsContainerProps = {
5
+ children: React.ReactNode,
6
+ }
7
+
8
+
9
+ const IndicatorsContainer = (props: IndicatorsContainerProps): React.ReactElement => (
5
10
  <components.IndicatorsContainer
6
- className="text_input_indicators"
7
- {...props}
11
+ className="text_input_indicators"
12
+ {...props}
8
13
  />
9
14
  )
10
15
 
@@ -1,7 +1,12 @@
1
1
  import React from 'react'
2
2
  import { components } from 'react-select'
3
3
 
4
- const MenuList = (props: any) => {
4
+ type MenuListProps = {
5
+ children: React.ReactNode,
6
+ footer: React.ReactNode,
7
+ }
8
+
9
+ const MenuList = (props: MenuListProps): React.ReactElement => {
5
10
  return (
6
11
  <components.MenuList {...props}>
7
12
  {props.children}
@@ -3,7 +3,22 @@ import { components } from 'react-select'
3
3
 
4
4
  import User from '../../pb_user/_user'
5
5
 
6
- const Option = (props: any) => {
6
+ type OptionProps = {
7
+ children: React.ReactNode,
8
+ label?: string,
9
+ data: {
10
+ imageUrl?: string,
11
+ },
12
+ selectProps: {
13
+ dark?: boolean,
14
+ valueComponent?: (data: {
15
+ imageUrl?: string,
16
+ }) => React.ReactNode,
17
+ },
18
+ }
19
+
20
+
21
+ const Option = (props: OptionProps): React.ReactElement => {
7
22
  const {
8
23
  imageUrl,
9
24
  } = props.data
@@ -14,11 +29,11 @@ const Option = (props: any) => {
14
29
  <>
15
30
  {!valueComponent && imageUrl &&
16
31
  <User
17
- align="left"
18
- avatarUrl={imageUrl}
19
- dark={props.selectProps.dark}
20
- name={props.label}
21
- orientation="horizontal"
32
+ align="left"
33
+ avatarUrl={imageUrl}
34
+ dark={props.selectProps.dark}
35
+ name={props.label}
36
+ orientation="horizontal"
22
37
  />
23
38
  }
24
39