playbook_ui 14.11.1 → 14.12.0.pre.alpha.PBNTR720railscarddraggable5649

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 (159) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/_playbook.scss +2 -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 +1 -1
  10. data/app/pb_kits/playbook/pb_advanced_table/advanced_table.rb +2 -0
  11. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_no_subrows.jsx +50 -0
  12. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_pagination.jsx +1 -0
  13. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_pagination_with_props.jsx +1 -0
  14. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows.jsx +60 -0
  15. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows.md +5 -0
  16. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows_actions.jsx +78 -0
  17. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows_actions.md +1 -0
  18. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows_header.jsx +53 -0
  19. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows_header.md +1 -0
  20. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows_no_subrows.jsx +52 -0
  21. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows_no_subrows.md +1 -0
  22. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_sort_control.md +2 -2
  23. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_table_props.html.erb +33 -0
  24. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_table_props_rails.md +1 -0
  25. data/app/pb_kits/playbook/pb_advanced_table/docs/advanced_table_mock_data_no_subrows.json +42 -0
  26. data/app/pb_kits/playbook/pb_advanced_table/docs/advanced_table_mock_data_with_id.json +299 -0
  27. data/app/pb_kits/playbook/pb_advanced_table/docs/example.yml +6 -0
  28. data/app/pb_kits/playbook/pb_advanced_table/docs/index.js +6 -1
  29. data/app/pb_kits/playbook/pb_button/button.html.erb +2 -3
  30. data/app/pb_kits/playbook/pb_card/card.html.erb +21 -2
  31. data/app/pb_kits/playbook/pb_card/card.rb +7 -0
  32. data/app/pb_kits/playbook/pb_checkbox/checkbox.html.erb +1 -6
  33. data/app/pb_kits/playbook/pb_collapsible/collapsible.html.erb +3 -1
  34. data/app/pb_kits/playbook/pb_collapsible/collapsible.rb +3 -0
  35. data/app/pb_kits/playbook/pb_date_picker/date_picker.html.erb +24 -16
  36. data/app/pb_kits/playbook/pb_date_picker/date_picker.rb +2 -0
  37. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_default_date.md +1 -1
  38. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_turbo_frames.html.erb +13 -0
  39. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_turbo_frames_rails.md +3 -0
  40. data/app/pb_kits/playbook/pb_date_picker/docs/example.yml +1 -0
  41. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_with_cards_rails.html.erb +1 -3
  42. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_with_cards_rails.md +7 -0
  43. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_with_list_rails.html.erb +3 -9
  44. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_with_list_rails.md +5 -0
  45. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_with_selectable_list_rails.html.erb +38 -0
  46. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_with_selectable_list_rails.md +3 -0
  47. data/app/pb_kits/playbook/pb_draggable/docs/example.yml +1 -0
  48. data/app/pb_kits/playbook/pb_drawer/_drawer.scss +145 -183
  49. data/app/pb_kits/playbook/pb_drawer/_drawer.tsx +158 -268
  50. data/app/pb_kits/playbook/pb_drawer/context.ts +11 -0
  51. data/app/pb_kits/playbook/pb_drawer/docs/_drawer_behavior.jsx +38 -0
  52. data/app/pb_kits/playbook/pb_drawer/docs/_drawer_borders.jsx +3 -45
  53. data/app/pb_kits/playbook/pb_drawer/docs/_drawer_breakpoints.jsx +0 -1
  54. data/app/pb_kits/playbook/pb_drawer/docs/_drawer_default.jsx +9 -16
  55. data/app/pb_kits/playbook/pb_drawer/docs/_drawer_menu.jsx +44 -19
  56. data/app/pb_kits/playbook/pb_drawer/docs/_drawer_menu.md +21 -3
  57. data/app/pb_kits/playbook/pb_drawer/docs/_drawer_overlay.jsx +16 -21
  58. data/app/pb_kits/playbook/pb_drawer/docs/_drawer_sizes.jsx +2 -19
  59. data/app/pb_kits/playbook/pb_drawer/docs/example.yml +2 -1
  60. data/app/pb_kits/playbook/pb_drawer/docs/index.js +1 -0
  61. data/app/pb_kits/playbook/pb_drawer/drawer.test.jsx +5 -5
  62. data/app/pb_kits/playbook/pb_drawer/hooks/useBreakpoint.tsx +60 -0
  63. data/app/pb_kits/playbook/pb_drawer/hooks/useDrawerAnimation.tsx +21 -0
  64. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_subtle_variant.md +1 -1
  65. data/app/pb_kits/playbook/pb_dropdown/dropdown.html.erb +7 -12
  66. data/app/pb_kits/playbook/pb_dropdown/dropdown_container.html.erb +9 -14
  67. data/app/pb_kits/playbook/pb_dropdown/dropdown_option.html.erb +6 -11
  68. data/app/pb_kits/playbook/pb_dropdown/dropdown_trigger.html.erb +8 -14
  69. data/app/pb_kits/playbook/pb_icon_button/_icon_button.scss +78 -0
  70. data/app/pb_kits/playbook/pb_icon_button/docs/_icon_button_default.html.erb +3 -0
  71. data/app/pb_kits/playbook/pb_icon_button/docs/example.yml +7 -0
  72. data/app/pb_kits/playbook/pb_icon_button/icon_button.html.erb +16 -0
  73. data/app/pb_kits/playbook/pb_icon_button/icon_button.rb +22 -0
  74. data/app/pb_kits/playbook/pb_list/item.html.erb +30 -8
  75. data/app/pb_kits/playbook/pb_list/item.rb +7 -0
  76. data/app/pb_kits/playbook/pb_list/list.html.erb +31 -11
  77. data/app/pb_kits/playbook/pb_list/list.rb +4 -0
  78. data/app/pb_kits/playbook/pb_loading_inline/_loading_inline.tsx +6 -1
  79. data/app/pb_kits/playbook/pb_multiple_users/_multiple_users.scss +4 -0
  80. data/app/pb_kits/playbook/pb_multiple_users/_multiple_users.tsx +1 -0
  81. data/app/pb_kits/playbook/pb_multiple_users/multiple_users.html.erb +1 -1
  82. data/app/pb_kits/playbook/pb_phone_number_input/_phone_number_input.tsx +30 -12
  83. data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_format.html.erb +15 -0
  84. data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_format.jsx +24 -0
  85. data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_format.md +1 -0
  86. data/app/pb_kits/playbook/pb_phone_number_input/docs/example.yml +3 -1
  87. data/app/pb_kits/playbook/pb_phone_number_input/docs/index.js +1 -0
  88. data/app/pb_kits/playbook/pb_phone_number_input/phone_number_input.rb +3 -0
  89. data/app/pb_kits/playbook/pb_phone_number_input/phone_number_input.test.js +20 -1
  90. data/app/pb_kits/playbook/pb_radio/_radio.scss +12 -8
  91. data/app/pb_kits/playbook/pb_radio/docs/_radio_custom_children.jsx +8 -3
  92. data/app/pb_kits/playbook/pb_select/_select.scss +3 -5
  93. data/app/pb_kits/playbook/pb_select/_select.tsx +5 -1
  94. data/app/pb_kits/playbook/pb_select/select.html.erb +2 -2
  95. data/app/pb_kits/playbook/pb_selectable_icon/_selectable_icon.tsx +9 -1
  96. data/app/pb_kits/playbook/pb_selectable_icon/docs/_selectable_icon_default.jsx +4 -1
  97. data/app/pb_kits/playbook/pb_selectable_icon/docs/_selectable_icon_single_select.jsx +4 -1
  98. data/app/pb_kits/playbook/pb_selectable_list/selectable_list.html.erb +17 -3
  99. data/app/pb_kits/playbook/pb_selectable_list/selectable_list.rb +3 -0
  100. data/app/pb_kits/playbook/pb_selectable_list/selectable_list_item.html.erb +11 -4
  101. data/app/pb_kits/playbook/pb_selectable_list/selectable_list_item.rb +3 -0
  102. data/app/pb_kits/playbook/pb_table/_table.tsx +2 -3
  103. data/app/pb_kits/playbook/pb_table/docs/_table_sticky_columns.html.erb +74 -0
  104. data/app/pb_kits/playbook/pb_table/docs/_table_sticky_columns_rails.md +3 -0
  105. data/app/pb_kits/playbook/pb_table/docs/_table_sticky_left_columns_rails.md +2 -2
  106. data/app/pb_kits/playbook/pb_table/docs/_table_sticky_right_columns.html.erb +74 -0
  107. data/app/pb_kits/playbook/pb_table/docs/_table_sticky_right_columns_rails.md +3 -0
  108. data/app/pb_kits/playbook/pb_table/docs/_table_with_collapsible.html.erb +47 -0
  109. data/app/pb_kits/playbook/pb_table/docs/_table_with_collapsible_rails.md +2 -0
  110. data/app/pb_kits/playbook/pb_table/docs/example.yml +3 -0
  111. data/app/pb_kits/playbook/pb_table/index.ts +187 -88
  112. data/app/pb_kits/playbook/pb_table/styles/_collapsible.scss +12 -0
  113. data/app/pb_kits/playbook/pb_table/styles/_scroll.scss +6 -5
  114. data/app/pb_kits/playbook/pb_table/table.html.erb +1 -1
  115. data/app/pb_kits/playbook/pb_table/table.rb +17 -2
  116. data/app/pb_kits/playbook/pb_table/table_row.html.erb +20 -1
  117. data/app/pb_kits/playbook/pb_table/table_row.rb +5 -0
  118. data/app/pb_kits/playbook/pb_table/utilities/addDataTitle.ts +22 -0
  119. data/app/pb_kits/playbook/pb_text_input/docs/_text_input_mask.html.erb +46 -0
  120. data/app/pb_kits/playbook/pb_text_input/docs/_text_input_mask_rails.md +3 -0
  121. data/app/pb_kits/playbook/pb_text_input/docs/example.yml +2 -1
  122. data/app/pb_kits/playbook/pb_text_input/index.js +103 -0
  123. data/app/pb_kits/playbook/pb_text_input/text_input.html.erb +4 -0
  124. data/app/pb_kits/playbook/pb_text_input/text_input.rb +33 -3
  125. data/app/pb_kits/playbook/pb_timeline/_timeline.scss +30 -30
  126. data/app/pb_kits/playbook/pb_typeahead/_typeahead.tsx +3 -2
  127. data/app/pb_kits/playbook/pb_typeahead/components/ClearIndicator.tsx +12 -4
  128. data/app/pb_kits/playbook/pb_typeahead/components/Control.tsx +5 -1
  129. data/app/pb_kits/playbook/pb_typeahead/components/IndicatorsContainer.tsx +8 -3
  130. data/app/pb_kits/playbook/pb_typeahead/components/MenuList.tsx +6 -1
  131. data/app/pb_kits/playbook/pb_typeahead/components/Option.tsx +21 -6
  132. data/app/pb_kits/playbook/pb_typeahead/components/Placeholder.tsx +13 -6
  133. data/app/pb_kits/playbook/pb_typeahead/components/ValueContainer.tsx +7 -3
  134. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_custom_menu_list.jsx +2 -0
  135. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_truncated_text.html.erb +19 -0
  136. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_truncated_text.jsx +27 -0
  137. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_truncated_text.md +1 -0
  138. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_with_pills_async.jsx +4 -2
  139. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_with_pills_async_custom_options.jsx +5 -5
  140. data/app/pb_kits/playbook/pb_typeahead/docs/example.yml +2 -0
  141. data/app/pb_kits/playbook/pb_typeahead/docs/index.js +1 -0
  142. data/dist/chunks/_typeahead-BWwaAo_0.js +36 -0
  143. data/dist/chunks/_weekday_stacked-zyBCd1s8.js +45 -0
  144. data/dist/chunks/lazysizes-B7xYodB-.js +1 -0
  145. data/dist/chunks/{lib-B7sgJtGS.js → lib-kMuhBuU7.js} +2 -2
  146. data/dist/chunks/{pb_form_validation-C5Cc0-1v.js → pb_form_validation-DBJ0wZuS.js} +1 -1
  147. data/dist/chunks/vendor.js +1 -1
  148. data/dist/menu.yml +6 -0
  149. data/dist/playbook-doc.js +1 -1
  150. data/dist/playbook-rails-react-bindings.js +1 -1
  151. data/dist/playbook-rails.js +1 -1
  152. data/dist/playbook.css +1 -1
  153. data/lib/playbook/version.rb +2 -2
  154. metadata +66 -9
  155. data/dist/chunks/_typeahead-C2iCBqxQ.js +0 -36
  156. data/dist/chunks/_weekday_stacked-E-5KcEkc.js +0 -45
  157. data/dist/chunks/lazysizes-DHz07jlL.js +0 -1
  158. /data/app/pb_kits/playbook/pb_advanced_table/docs/{_advanced_table_table_props.md → _advanced_table_table_props_react.md} +0 -0
  159. /data/app/pb_kits/playbook/pb_table/docs/{_table_with_collapsible.md → _table_with_collapsible_react.md} +0 -0
@@ -0,0 +1,16 @@
1
+ <%= pb_content_tag do %>
2
+ <%= pb_rails("button", props: { type: object.type,
3
+ link: object.link,
4
+ new_window:object.new_window,
5
+ target: object.target,
6
+ dark: object.dark,
7
+ border_radius: "lg" }) do %>
8
+ <%= pb_rails("icon", props: { icon: object.icon,
9
+ fixed_width: true,
10
+ dark: object.dark,
11
+ size: "2x",
12
+ color: "text_lt_default",
13
+ classname: "icon_button_icon",
14
+ padding_x: "xxs", padding_y: "xs" }) %>
15
+ <% end %>
16
+ <% end %>
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Playbook
4
+ module PbIconButton
5
+ class IconButton < ::Playbook::KitBase
6
+ prop :type, type: Playbook::Props::Enum,
7
+ values: %w[button submit reset],
8
+ default: "button"
9
+ prop :icon, required: false, default: "bars"
10
+ prop :link
11
+ prop :new_window, type: Playbook::Props::Boolean,
12
+ default: false
13
+ prop :target
14
+ prop :variant, type: Playbook::Props::Enum,
15
+ values: %w[default link],
16
+ default: "default"
17
+ def classname
18
+ generate_classname("pb_icon_button_kit", variant)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -1,10 +1,32 @@
1
- <%= content_tag(:li,
2
- aria: object.aria,
3
- class: object.classname,
4
- data: object.data,
5
- id: object.id,
6
- tabindex: object.tabindex,
7
- **combined_html_options
8
- ) do %>
1
+ <% if object.draggable? %>
2
+ <%= pb_rails("draggable/draggable_item", props:{drag_id: object.drag_id}) do %>
3
+ <%= content_tag(:li,
4
+ aria: object.aria,
5
+ class: object.classname,
6
+ data: object.data,
7
+ id: object.id,
8
+ tabindex: object.tabindex,
9
+ **combined_html_options
10
+ ) do %>
11
+ <% if object.drag_handle %>
12
+ <span style="vertical-align: middle;">
13
+ <%= pb_rails("body") do %>
14
+ <svg width="auto" height="auto" viewBox="0 0 31 25" fill="none" xmlns="http://www.w3.org/2000/svg" color="currentColor" class="pb_custom_icon svg-inline--fa vertical_align_middle svg_fw"><path d="M12.904 6.355a1.48 1.48 0 01-1.5-1.5c0-.796.656-1.5 1.5-1.5.797 0 1.5.704 1.5 1.5 0 .844-.703 1.5-1.5 1.5zm0 7.5a1.48 1.48 0 01-1.5-1.5c0-.796.656-1.5 1.5-1.5.797 0 1.5.704 1.5 1.5 0 .844-.703 1.5-1.5 1.5zm1.5 6c0 .844-.703 1.5-1.5 1.5a1.48 1.48 0 01-1.5-1.5c0-.796.656-1.5 1.5-1.5.797 0 1.5.704 1.5 1.5zm4.5-13.5a1.48 1.48 0 01-1.5-1.5c0-.796.657-1.5 1.5-1.5.797 0 1.5.704 1.5 1.5 0 .844-.703 1.5-1.5 1.5zm1.5 6c0 .844-.703 1.5-1.5 1.5a1.48 1.48 0 01-1.5-1.5c0-.796.657-1.5 1.5-1.5.797 0 1.5.704 1.5 1.5zm-1.5 9a1.48 1.48 0 01-1.5-1.5c0-.796.657-1.5 1.5-1.5.797 0 1.5.704 1.5 1.5 0 .844-.703 1.5-1.5 1.5z" fill="#242B42"></path></svg>
15
+ <% end %>
16
+ </span>
17
+ <% end %>
18
+ <%= content.presence %>
19
+ <% end %>
20
+ <% end %>
21
+ <% else %>
22
+ <%= content_tag(:li,
23
+ aria: object.aria,
24
+ class: object.classname,
25
+ data: object.data,
26
+ id: object.id,
27
+ tabindex: object.tabindex,
28
+ **combined_html_options
29
+ ) do %>
9
30
  <%= content.presence %>
31
+ <% end %>
10
32
  <% end %>
@@ -3,11 +3,18 @@
3
3
  module Playbook
4
4
  module PbList
5
5
  class Item < Playbook::KitBase
6
+ prop :drag_handle, type: Playbook::Props::Boolean,
7
+ default: true
8
+ prop :drag_id, type: Playbook::Props::String
6
9
  prop :tabindex
7
10
 
8
11
  def classname
9
12
  generate_classname("pb_item_kit")
10
13
  end
14
+
15
+ def draggable?
16
+ drag_id.present?
17
+ end
11
18
  end
12
19
  end
13
20
  end
@@ -1,13 +1,33 @@
1
- <%= content_tag(:div, class: object.list_classname) do %>
2
- <%= content_tag(:"#{object.ordered_class}",
3
- aria: object.aria,
4
- class: object.classname,
5
- data: object.data,
6
- id: object.id,
7
- role: object.role,
8
- tabindex: object.tabindex,
9
- **combined_html_options
10
- ) do %>
11
- <%= content.presence %>
1
+ <% if object.enable_drag %>
2
+ <%= pb_rails("draggable", props: {initial_items: object.items}) do %>
3
+ <%= pb_rails("draggable/draggable_container") do %>
4
+ <%= content_tag(:div, class: object.list_classname) do %>
5
+ <%= content_tag(:"#{object.ordered_class}",
6
+ aria: object.aria,
7
+ class: object.classname,
8
+ data: object.data,
9
+ id: object.id,
10
+ role: object.role,
11
+ tabindex: object.tabindex,
12
+ **combined_html_options
13
+ ) do %>
14
+ <%= content.presence %>
15
+ <% end %>
16
+ <% end %>
17
+ <% end %>
18
+ <% end %>
19
+ <% else %>
20
+ <%= content_tag(:div, class: object.list_classname) do %>
21
+ <%= content_tag(:"#{object.ordered_class}",
22
+ aria: object.aria,
23
+ class: object.classname,
24
+ data: object.data,
25
+ id: object.id,
26
+ role: object.role,
27
+ tabindex: object.tabindex,
28
+ **combined_html_options
29
+ ) do %>
30
+ <%= content.presence %>
31
+ <% end %>
12
32
  <% end %>
13
33
  <% end %>
@@ -7,6 +7,10 @@ module Playbook
7
7
  default: false
8
8
  prop :dark, type: Playbook::Props::Boolean,
9
9
  default: false
10
+ prop :enable_drag, type: Playbook::Props::Boolean,
11
+ default: false
12
+ prop :items, type: Playbook::Props::Array,
13
+ default: []
10
14
  prop :layout, type: Playbook::Props::Enum,
11
15
  values: ["left", "right", ""],
12
16
  default: ""
@@ -12,6 +12,7 @@ type LoadingInlineProps = {
12
12
  aria?: { [key: string]: string },
13
13
  className?: string,
14
14
  data?: { [key: string]: string },
15
+ dark?: boolean,
15
16
  htmlOptions?: {[key: string]: string | number | boolean | (() => void)},
16
17
  id?: string,
17
18
  text?: string,
@@ -23,6 +24,7 @@ const LoadingInline = (props: LoadingInlineProps) => {
23
24
  aria = {},
24
25
  className,
25
26
  data = {},
27
+ dark = false,
26
28
  htmlOptions = {},
27
29
  id,
28
30
  text = ' Loading',
@@ -45,7 +47,10 @@ const LoadingInline = (props: LoadingInlineProps) => {
45
47
  className={classes}
46
48
  id={id}
47
49
  >
48
- <Body color="light">
50
+ <Body
51
+ color="light"
52
+ dark={dark}
53
+ >
49
54
  <Icon
50
55
  aria={{ label: 'loading icon' }}
51
56
  fixedWidth
@@ -24,6 +24,10 @@ $pb_multiple_users_size_xxs: map-get($avatar-sizes, "xxs");
24
24
  color: $primary;
25
25
  font-weight: $bold;
26
26
  font-size: $font_smallest - 1;
27
+
28
+ &.dark {
29
+ border: $pb_multiple_users_border_size solid $bg_dark;
30
+ }
27
31
  }
28
32
 
29
33
  .multiple_users_badge_xxs {
@@ -50,6 +50,7 @@ const MultipleUsers = (props: MultipleUsersProps): React.ReactElement => {
50
50
 
51
51
  const itemClasses = classnames(
52
52
  'pb_multiple_users_item',
53
+ dark && 'dark',
53
54
  buildCss('multiple_users_badge', avatarSizeClass)
54
55
  )
55
56
 
@@ -4,7 +4,7 @@
4
4
  <% end %>
5
5
 
6
6
  <% if object.more_than_four %>
7
- <div class="pb_multiple_users_item multiple_users_badge_<%= object.size %>">
7
+ <div class="pb_multiple_users_item multiple_users_badge_<%= object.size %><%= object.dark ? " dark" : "" %>">
8
8
  <%= "+#{object.users.count - object.display_count}" %>
9
9
  </div>
10
10
  <% end %>
@@ -35,6 +35,7 @@ type PhoneNumberInputProps = {
35
35
  preferredCountries?: string[],
36
36
  required?: boolean,
37
37
  value?: string,
38
+ formatAsYouType?: boolean,
38
39
  }
39
40
 
40
41
  enum ValidationError {
@@ -87,6 +88,7 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.MutableRefOb
87
88
  required = false,
88
89
  preferredCountries = [],
89
90
  value = "",
91
+ formatAsYouType = false,
90
92
  } = props
91
93
 
92
94
  const ariaProps = buildAriaProps(aria)
@@ -99,8 +101,8 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.MutableRefOb
99
101
  )
100
102
 
101
103
  const inputRef = useRef<HTMLInputElement>()
104
+ const itiRef = useRef<any>(null);
102
105
  const [inputValue, setInputValue] = useState(value)
103
- const [itiInit, setItiInit] = useState<any>()
104
106
  const [error, setError] = useState(props.error)
105
107
  const [dropDownIsOpen, setDropDownIsOpen] = useState(false)
106
108
  const [selectedData, setSelectedData] = useState()
@@ -130,8 +132,12 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.MutableRefOb
130
132
  }
131
133
  })
132
134
 
135
+ const unformatNumber = (formattedNumber: any) => {
136
+ return formattedNumber.replace(/\D/g, "")
137
+ }
138
+
133
139
  const showFormattedError = (reason = '') => {
134
- const countryName = itiInit.getSelectedCountryData().name
140
+ const countryName = itiRef.current.getSelectedCountryData().name
135
141
  const reasonText = reason.length > 0 ? ` (${reason})` : ''
136
142
  setError(`Invalid ${countryName} phone number${reasonText}`)
137
143
  return true
@@ -189,12 +195,12 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.MutableRefOb
189
195
  }
190
196
 
191
197
  const validateErrors = () => {
192
- if (itiInit) isValid(itiInit.isValidNumber())
193
- if (validateOnlyNumbers(itiInit)) return
194
- if (validateTooLongNumber(itiInit)) return
195
- if (validateTooShortNumber(itiInit)) return
196
- if (validateUnhandledError(itiInit)) return
197
- if (validateMissingAreaCode(itiInit)) return
198
+ if (itiRef.current) isValid(itiRef.current.isValidNumber())
199
+ if (validateOnlyNumbers(itiRef.current)) return
200
+ if (validateTooLongNumber(itiRef.current)) return
201
+ if (validateTooShortNumber(itiRef.current)) return
202
+ if (validateUnhandledError(itiRef.current)) return
203
+ if (validateMissingAreaCode(itiRef.current)) return
198
204
  }
199
205
 
200
206
  const getCurrentSelectedData = (itiInit: any, inputValue: string) => {
@@ -203,10 +209,16 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.MutableRefOb
203
209
 
204
210
  const handleOnChange = (evt: React.ChangeEvent<HTMLInputElement>) => {
205
211
  setInputValue(evt.target.value)
206
- const phoneNumberData = getCurrentSelectedData(itiInit, evt.target.value)
212
+ let phoneNumberData
213
+ if (formatAsYouType) {
214
+ const formattedPhoneNumberData = getCurrentSelectedData(itiRef.current, evt.target.value)
215
+ phoneNumberData = {...formattedPhoneNumberData, number: unformatNumber(formattedPhoneNumberData.number)}
216
+ } else {
217
+ phoneNumberData = getCurrentSelectedData(itiRef.current, evt.target.value)
218
+ }
207
219
  setSelectedData(phoneNumberData)
208
220
  onChange(phoneNumberData)
209
- isValid(itiInit.isValidNumber())
221
+ isValid(itiRef.current.isValidNumber())
210
222
  }
211
223
 
212
224
  // Separating Concerns as React Docs Recommend
@@ -230,9 +242,11 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.MutableRefOb
230
242
  onlyCountries,
231
243
  countrySearch: false,
232
244
  fixDropdownWidth: false,
233
- formatAsYouType: false,
245
+ formatAsYouType: formatAsYouType,
234
246
  })
235
247
 
248
+ itiRef.current = telInputInit;
249
+
236
250
  inputRef.current.addEventListener("countrychange", (evt: Event) => {
237
251
  const phoneNumberData = getCurrentSelectedData(telInputInit, (evt.target as HTMLInputElement).value)
238
252
  setSelectedData(phoneNumberData)
@@ -243,7 +257,11 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.MutableRefOb
243
257
  inputRef.current.addEventListener("open:countrydropdown", () => setDropDownIsOpen(true))
244
258
  inputRef.current.addEventListener("close:countrydropdown", () => setDropDownIsOpen(false))
245
259
 
246
- setItiInit(telInputInit)
260
+ if (formatAsYouType) {
261
+ inputRef.current?.addEventListener("input", (evt) => {
262
+ handleOnChange(evt as unknown as React.ChangeEvent<HTMLInputElement>);
263
+ });
264
+ }
247
265
  }, [])
248
266
 
249
267
  let textInputProps: {[key: string]: any} = {
@@ -0,0 +1,15 @@
1
+ <%= pb_rails("phone_number_input", props: {
2
+ id: "phone_number_input",
3
+ format_as_you_type: true
4
+ }) %>
5
+
6
+ <%= pb_rails("button", props: {id: "clickable", text: "Save Phone Number"}) %>
7
+
8
+ <%= javascript_tag do %>
9
+ document.querySelector('#clickable').addEventListener('click', () => {
10
+ const formattedPhoneNumber = document.querySelector('#phone_number_input').value
11
+ const unformattedPhoneNumber = formattedPhoneNumber.replace(/\D/g, "")
12
+
13
+ alert(`Formatted: ${formattedPhoneNumber}. Unformatted: ${unformattedPhoneNumber}`)
14
+ })
15
+ <% end %>
@@ -0,0 +1,24 @@
1
+ import React, { useState } from "react";
2
+ import { PhoneNumberInput, Body } from "playbook-ui";
3
+
4
+ const PhoneNumberInputFormat = (props) => {
5
+ const [phoneNumber, setPhoneNumber] = useState("");
6
+
7
+ const handleOnChange = ({ number }) => {
8
+ setPhoneNumber(number);
9
+ };
10
+
11
+ return (
12
+ <>
13
+ <PhoneNumberInput
14
+ formatAsYouType
15
+ id="format"
16
+ onChange={handleOnChange}
17
+ {...props}
18
+ />
19
+ {phoneNumber && <Body>Unformatted number: {phoneNumber}</Body>}
20
+ </>
21
+ );
22
+ };
23
+
24
+ export default PhoneNumberInputFormat;
@@ -0,0 +1 @@
1
+ NOTE: the `number` in the React `onChange` event will not include formatting (no spaces, dashes, and parentheses). For Rails, the `value` will include formatting and its value must be sanitized manually.
@@ -8,10 +8,12 @@ examples:
8
8
  - phone_number_input_validation: Form Validation
9
9
  - phone_number_input_clear_field: Clearing the Input Field
10
10
  - phone_number_input_access_input_element: Accessing the Input Element
11
+ - phone_number_input_format: Format as You Type
11
12
 
12
13
  rails:
13
14
  - phone_number_input_default: Default
14
15
  - phone_number_input_preferred_countries: Preferred Countries
15
16
  - phone_number_input_initial_country: Initial Country
16
17
  - phone_number_input_only_countries: Limited Countries
17
- - phone_number_input_validation: Form Validation
18
+ - phone_number_input_validation: Form Validation
19
+ - phone_number_input_format: Format as You Type
@@ -5,3 +5,4 @@ export { default as PhoneNumberInputOnlyCountries } from './_phone_number_input_
5
5
  export { default as PhoneNumberInputValidation } from './_phone_number_input_validation'
6
6
  export { default as PhoneNumberInputClearField } from './_phone_number_input_clear_field'
7
7
  export { default as PhoneNumberInputAccessInputElement } from './_phone_number_input_access_input_element'
8
+ export { default as PhoneNumberInputFormat } from './_phone_number_input_format'
@@ -21,6 +21,8 @@ module Playbook
21
21
  default: ""
22
22
  prop :value, type: Playbook::Props::String,
23
23
  default: ""
24
+ prop :format_as_you_type, type: Playbook::Props::Boolean,
25
+ default: false
24
26
 
25
27
  def classname
26
28
  generate_classname("pb_phone_number_input")
@@ -32,6 +34,7 @@ module Playbook
32
34
  dark: dark,
33
35
  disabled: disabled,
34
36
  error: error,
37
+ formatAsYouType: format_as_you_type,
35
38
  initialCountry: initial_country,
36
39
  label: label,
37
40
  name: name,
@@ -1,5 +1,5 @@
1
1
  import React from "react";
2
- import { render, screen } from "../utilities/test-utils";
2
+ import { render, screen, act } from "../utilities/test-utils";
3
3
  import PhoneNumberInput from "./_phone_number_input";
4
4
 
5
5
  const testId = "phoneNumberInput";
@@ -120,3 +120,22 @@ test("should trigger callback", () => {
120
120
 
121
121
  expect(handleOnValidate).toBeCalledWith(true)
122
122
  });
123
+
124
+ test("should format phone number as '555-555-5555' with formatAsYouType and 'us' country", () => {
125
+ const props = {
126
+ initialCountry: 'us',
127
+ formatAsYouType: true,
128
+ id: testId,
129
+ };
130
+
131
+ render(<PhoneNumberInput {...props} />);
132
+
133
+ const input = screen.getByRole("textbox");
134
+
135
+ act(() => {
136
+ input.value = "5555555555";
137
+ input.dispatchEvent(new Event('input', { bubbles: true }));
138
+ });
139
+
140
+ expect(input.value).toBe("555-555-5555");
141
+ });
@@ -4,7 +4,7 @@
4
4
  @import "../pb_body/body";
5
5
  @import "../tokens/transition";
6
6
 
7
- [class^=pb_radio_kit] {
7
+ [class^="pb_radio_kit"] {
8
8
  display: inline-flex;
9
9
  cursor: pointer;
10
10
 
@@ -16,10 +16,11 @@
16
16
  border-radius: 1000px;
17
17
  border: 2px solid $border_light;
18
18
  margin-right: $space_xs;
19
- transition: background $transition_default ease, box-shadow $transition_default ease, border-color $transition_default ease;
19
+ transition: background $transition_default ease,
20
+ box-shadow $transition_default ease, border-color $transition_default ease;
20
21
  }
21
22
 
22
- @media (hover:hover) {
23
+ @media (hover: hover) {
23
24
  &:hover .pb_radio_button {
24
25
  background-color: $bg_light;
25
26
  border-color: $border_light;
@@ -52,14 +53,14 @@
52
53
  }
53
54
  }
54
55
 
55
- &:disabled:checked + .pb_radio_button{
56
+ &:disabled:checked + .pb_radio_button {
56
57
  cursor: not-allowed;
57
58
  background-color: $white;
58
59
  border: 6px solid $neutral;
59
60
  }
60
61
  }
61
62
 
62
- &[class*=vertical] {
63
+ &[class*="vertical"] {
63
64
  flex-direction: column;
64
65
  align-items: center;
65
66
  .pb_radio_button {
@@ -80,7 +81,7 @@
80
81
  }
81
82
  &:checked {
82
83
  & ~ .pb_radio_button {
83
- border: 6px solid $primary;
84
+ border: 6px solid $active_dark;
84
85
  }
85
86
  }
86
87
 
@@ -103,10 +104,10 @@
103
104
  }
104
105
  }
105
106
 
106
- @media (hover:hover) {
107
+ @media (hover: hover) {
107
108
  &:hover {
108
109
  .pb_radio_button {
109
- background-color: rgba($white,.10);
110
+ background-color: rgba($white, 0.1);
110
111
  border-color: $border_dark;
111
112
  }
112
113
  }
@@ -115,6 +116,9 @@
115
116
  > .pb_radio_button {
116
117
  border-color: $error_dark;
117
118
  }
119
+ > .pb_body_kit_negative {
120
+ color: $error_dark;
121
+ }
118
122
  }
119
123
  }
120
124
  &.error {
@@ -29,6 +29,7 @@ const RadioChildren = (props) => {
29
29
  marginBottom="none"
30
30
  minWidth="xs"
31
31
  options={options}
32
+ {...props}
32
33
  />
33
34
  </Radio>
34
35
  <Radio
@@ -40,10 +41,11 @@ const RadioChildren = (props) => {
40
41
  value="Typeahead"
41
42
  {...props}
42
43
  >
43
- <Typeahead
44
+ <Typeahead
44
45
  marginBottom="none"
45
46
  minWidth="xs"
46
47
  options={options}
48
+ {...props}
47
49
  />
48
50
  </Radio>
49
51
  <Radio
@@ -54,9 +56,12 @@ const RadioChildren = (props) => {
54
56
  value="Typography"
55
57
  {...props}
56
58
  >
57
- <Title text="Custom Typography" />
59
+ <Title
60
+ text="Custom Typography"
61
+ {...props}
62
+ />
58
63
  </Radio>
59
64
  </div>
60
65
  )
61
66
  }
62
- export default RadioChildren
67
+ export default RadioChildren
@@ -209,10 +209,8 @@
209
209
  }
210
210
  .pb_select_kit_wrapper {
211
211
  &.error {
212
- .pb_select_kit_wrapper {
213
- > select:first-child {
214
- border-color: $error_dark;
215
- }
212
+ > select {
213
+ border-color: $error_dark;
216
214
  }
217
215
  }
218
216
  }
@@ -228,7 +226,7 @@
228
226
  &:hover {
229
227
  select {
230
228
  color: $white !important;
231
- background: rgba(0,130,255,0.1);
229
+ background: $focus_input_dark;
232
230
  }
233
231
  svg {
234
232
  color: $primary !important;
@@ -127,7 +127,10 @@ const Select = ({
127
127
  className="pb_select_kit_label"
128
128
  htmlFor={name}
129
129
  >
130
- <Caption text={label} />
130
+ <Caption
131
+ dark={props.dark}
132
+ text={label}
133
+ />
131
134
  </label>
132
135
  }
133
136
  <label
@@ -146,6 +149,7 @@ const Select = ({
146
149
  }
147
150
  {error &&
148
151
  <Body
152
+ dark={props.dark}
149
153
  status="negative"
150
154
  text={error}
151
155
  />
@@ -5,7 +5,7 @@
5
5
  **combined_html_options) do %>
6
6
  <% if object.label %>
7
7
  <label class="pb_select_kit_label" for="<%= object.name %>">
8
- <%= pb_rails("caption", props: { text: object.label }) %>
8
+ <%= pb_rails("caption", props: { text: object.label, dark: object.dark }) %>
9
9
  </label>
10
10
  <% end %>
11
11
  <label class="<%= object.select_wrapper_class %>" for="<%= object.name %>">
@@ -23,7 +23,7 @@
23
23
  object.all_attributes
24
24
  )
25
25
  %>
26
- <%= pb_rails("body", props: { status: "negative", text: object.error }) %>
26
+ <%= pb_rails("body", props: { status: "negative", text: object.error, dark: object.dark }) %>
27
27
  <% end %>
28
28
  <% if object.multiple != true %>
29
29
  <%= pb_rails("icon", props: { custom_icon: Playbook::Engine::root.join(angle_down_path), fixed_width: true, classname: "pb_select_kit_caret"}) %>
@@ -16,6 +16,7 @@ type SelectableIconProps = {
16
16
  checked?: boolean,
17
17
  className?: string,
18
18
  customIcon?: {[key: string] :SVGElement},
19
+ dark?: boolean,
19
20
  disabled?: boolean,
20
21
  data?: GenericObject,
21
22
  htmlOptions?: {[key: string]: string | number | boolean | (() => void)},
@@ -33,6 +34,7 @@ const SelectableIcon = ({
33
34
  className,
34
35
  checked = false,
35
36
  customIcon,
37
+ dark = false,
36
38
  data = {},
37
39
  disabled = false,
38
40
  htmlOptions = {},
@@ -52,10 +54,12 @@ const SelectableIcon = ({
52
54
  const classes = classnames(
53
55
  buildCss('pb_selectable_icon_kit', {
54
56
  checked: checked,
57
+ dark: dark,
55
58
  disabled: disabled,
56
59
  enabled: !disabled,
57
60
  }),
58
61
  globalProps(props),
62
+ dark ? 'dark' : '',
59
63
  className
60
64
  )
61
65
 
@@ -73,17 +77,19 @@ const SelectableIcon = ({
73
77
  <>
74
78
  <Icon
75
79
  customIcon={customIcon}
80
+ dark={dark}
76
81
  icon={icon}
77
82
  size="2x"
78
83
  />
79
84
  <Title
85
+ dark={dark}
80
86
  size={4}
81
87
  tag="h4"
82
88
  text={text}
83
89
  />
84
90
  </>
85
91
  )}
86
-
92
+
87
93
  {inputs === 'enabled' && (
88
94
  <>
89
95
  <input
@@ -98,10 +104,12 @@ const SelectableIcon = ({
98
104
  <label htmlFor={inputIdPresent}>
99
105
  <Icon
100
106
  customIcon={customIcon}
107
+ dark={dark}
101
108
  icon={icon}
102
109
  size="2x"
103
110
  />
104
111
  <Title
112
+ dark={dark}
105
113
  size={4}
106
114
  tag="h4"
107
115
  text={text}