playbook_ui 14.7.0 → 14.8.0.pre.alpha.PBNTR713dropdowncustomtriggerbug4696

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/_playbook.scss +1 -0
  3. data/app/pb_kits/playbook/pb_card/docs/_card_light.md +1 -1
  4. data/app/pb_kits/playbook/pb_checkbox/checkbox.html.erb +2 -2
  5. data/app/pb_kits/playbook/pb_checkbox/checkbox.rb +0 -4
  6. data/app/pb_kits/playbook/pb_checkbox/docs/_checkbox_indeterminate.html.erb +84 -7
  7. data/app/pb_kits/playbook/pb_date/_date.scss +3 -0
  8. data/app/pb_kits/playbook/pb_date_picker/date_picker_helper.ts +1 -1
  9. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_quick_pick_default_date.html.erb +42 -0
  10. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_quick_pick_default_date.jsx +44 -0
  11. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_quick_pick_default_date.md +1 -0
  12. data/app/pb_kits/playbook/pb_date_picker/docs/example.yml +2 -0
  13. data/app/pb_kits/playbook/pb_date_picker/docs/index.js +1 -0
  14. data/app/pb_kits/playbook/pb_date_picker/plugins/quickPick.tsx +17 -1
  15. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_default_rails.html.erb +26 -0
  16. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_default_rails.md +7 -0
  17. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_with_cards_rails.html.erb +38 -0
  18. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_with_cards_rails.md +0 -0
  19. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_with_list_rails.html.erb +19 -0
  20. data/app/pb_kits/playbook/pb_draggable/docs/example.yml +6 -0
  21. data/app/pb_kits/playbook/pb_draggable/draggable.html.erb +3 -0
  22. data/app/pb_kits/playbook/pb_draggable/draggable.rb +18 -0
  23. data/app/pb_kits/playbook/pb_draggable/draggable_container.html.erb +3 -0
  24. data/app/pb_kits/playbook/pb_draggable/draggable_container.rb +15 -0
  25. data/app/pb_kits/playbook/pb_draggable/draggable_item.html.erb +7 -0
  26. data/app/pb_kits/playbook/pb_draggable/draggable_item.rb +18 -0
  27. data/app/pb_kits/playbook/pb_draggable/index.js +125 -0
  28. data/app/pb_kits/playbook/pb_drawer/_drawer.scss +88 -175
  29. data/app/pb_kits/playbook/pb_drawer/_drawer.tsx +79 -47
  30. data/app/pb_kits/playbook/pb_drawer/drawer.test.jsx +20 -16
  31. data/app/pb_kits/playbook/pb_dropdown/_dropdown.scss +1 -0
  32. data/app/pb_kits/playbook/pb_dropdown/dropdown_container.html.erb +0 -1
  33. data/app/pb_kits/playbook/pb_dropdown/dropdown_container.rb +0 -4
  34. data/app/pb_kits/playbook/pb_dropdown/utilities/subComponentHelper.tsx +13 -2
  35. data/app/pb_kits/playbook/pb_form/docs/_form_form_with.html.erb +2 -2
  36. data/app/pb_kits/playbook/pb_form/docs/_form_form_with_loading.html.erb +1 -1
  37. data/app/pb_kits/playbook/pb_form/docs/_form_form_with_validate.html.erb +63 -12
  38. data/app/pb_kits/playbook/pb_selectable_card/docs/_selectable_card_default.html.erb +2 -1
  39. data/app/pb_kits/playbook/pb_table/_table.tsx +103 -24
  40. data/app/pb_kits/playbook/pb_table/docs/_table_sticky_left_columns.jsx +87 -0
  41. data/app/pb_kits/playbook/pb_table/docs/_table_sticky_left_columns_react.md +2 -0
  42. data/app/pb_kits/playbook/pb_table/docs/index.js +1 -0
  43. data/app/pb_kits/playbook/pb_table/styles/_all.scss +2 -0
  44. data/app/pb_kits/playbook/pb_table/styles/_scroll.scss +4 -0
  45. data/app/pb_kits/playbook/pb_table/styles/_sticky_columns.scss +18 -0
  46. data/app/pb_kits/playbook/pb_timeline/_timeline.scss +43 -1
  47. data/app/pb_kits/playbook/pb_timeline/_timeline.tsx +6 -2
  48. data/app/pb_kits/playbook/pb_timeline/docs/_timeline_with_children.html.erb +47 -0
  49. data/app/pb_kits/playbook/pb_timeline/docs/_timeline_with_children.jsx +59 -0
  50. data/app/pb_kits/playbook/pb_timeline/docs/_timeline_with_gap.html.erb +94 -0
  51. data/app/pb_kits/playbook/pb_timeline/docs/_timeline_with_gap.jsx +180 -0
  52. data/app/pb_kits/playbook/pb_timeline/docs/_timeline_with_gap.md +1 -0
  53. data/app/pb_kits/playbook/pb_timeline/docs/example.yml +5 -3
  54. data/app/pb_kits/playbook/pb_timeline/docs/index.js +2 -0
  55. data/app/pb_kits/playbook/pb_timeline/timeline.rb +11 -1
  56. data/app/pb_kits/playbook/pb_timeline/timeline.test.js +4 -4
  57. data/app/pb_kits/playbook/pb_typeahead/_typeahead.scss +3 -0
  58. data/app/pb_kits/playbook/pb_typeahead/index.ts +29 -3
  59. data/app/pb_kits/playbook/pb_typeahead/typeahead.html.erb +5 -2
  60. data/app/pb_kits/playbook/pb_typeahead/typeahead.rb +4 -0
  61. data/app/pb_kits/playbook/tokens/_height.scss +19 -0
  62. data/app/pb_kits/playbook/tokens/exports/_height.module.scss +37 -0
  63. data/app/pb_kits/playbook/utilities/_height.scss +33 -0
  64. data/app/pb_kits/playbook/utilities/_hover.scss +40 -27
  65. data/app/pb_kits/playbook/utilities/_max_width.scss +4 -0
  66. data/app/pb_kits/playbook/utilities/_min_width.scss +1 -1
  67. data/app/pb_kits/playbook/utilities/globalPropNames.mjs +0 -1
  68. data/app/pb_kits/playbook/utilities/globalProps.ts +29 -3
  69. data/app/pb_kits/playbook/utilities/test/globalProps/hover.test.js +79 -0
  70. data/dist/chunks/_typeahead-C8Q_fFYF.js +22 -0
  71. data/dist/chunks/_weekday_stacked-CUJfwh5E.js +45 -0
  72. data/dist/chunks/lazysizes-B7xYodB-.js +1 -0
  73. data/dist/chunks/{lib-D-mTv-kp.js → lib-SyD3buPZ.js} +1 -1
  74. data/dist/chunks/{pb_form_validation-BkWGwJsl.js → pb_form_validation-Dt8UJgrJ.js} +1 -1
  75. data/dist/chunks/vendor.js +1 -1
  76. data/dist/menu.yml +322 -1
  77. data/dist/playbook-doc.js +1 -1
  78. data/dist/playbook-rails-react-bindings.js +1 -1
  79. data/dist/playbook-rails.js +1 -1
  80. data/dist/playbook.css +1 -1
  81. data/lib/playbook/classnames.rb +3 -0
  82. data/lib/playbook/forms/builder/typeahead_field.rb +13 -0
  83. data/lib/playbook/height.rb +29 -0
  84. data/lib/playbook/hover.rb +1 -1
  85. data/lib/playbook/kit_base.rb +16 -1
  86. data/lib/playbook/max_height.rb +29 -0
  87. data/lib/playbook/min_height.rb +29 -0
  88. data/lib/playbook/version.rb +2 -2
  89. metadata +39 -10
  90. data/dist/chunks/_typeahead-DhLic2Fe.js +0 -22
  91. data/dist/chunks/_weekday_stacked-CHPFjl8J.js +0 -45
  92. data/dist/chunks/lazysizes-DHz07jlL.js +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bbcb00498c9dc4a636179bd7186dd8212f9fed6f9d096d615f63b93861fba2c7
4
- data.tar.gz: b30eca9b5879d8346fe092421ec5070e3259e2f096792145e5d53c04902d0463
3
+ metadata.gz: 7776c1f464d6ba8dfb924b88a819e7d8ffaa73a2e5bb8c634d842d74e518b181
4
+ data.tar.gz: 426631d54aa230c2730bd84e2f100ddc1bdabd7ac2e665d1b467a7be5e5ea1e3
5
5
  SHA512:
6
- metadata.gz: '09475c887b1c4e75768fb5435c13ce28584456eaf67bb039acfbf211c7b627e4cb56feb85e0cb83c49a05f6c016ceb0282b0f426d9cadf4ec703cdfa97f084c2'
7
- data.tar.gz: 7f46c632e40e670b7456ade4b36105db7cb995d7801e80f156536b118a18e65738c3ef3a0ef9a9df280c3e98da5c3be3e283e4da2d9b9494ecf906f5680783c0
6
+ metadata.gz: d0eff8fe9fecb531b16b97bf63c76c1bb6c0746e3542f5a401947cf1d62e4b314700d0ed23e616d00faa36d057e8d39a06734db7b54322625c295339b0fe5af3
7
+ data.tar.gz: a2807364db12b9e5594df46d76931e33d4602f6b74892ae578efd465a46c9f7ef93e947e2e6c969c6c96518900cbe9f6fbfb25cc8dee868376197ee165050f1d
@@ -126,3 +126,4 @@
126
126
  @import 'utilities/overflow';
127
127
  @import 'utilities/truncate';
128
128
  @import 'utilities/vertical_align';
129
+ @import 'utilities/height';
@@ -1 +1 @@
1
- Card can leverage the max-width property. Learn more in our <a href="https://playbook.powerapp.cloud/visual_guidelines" target="_blank">visual guidelines.</a>
1
+ Card can leverage the max-width property. Learn more in our <a href="https://playbook.powerapp.cloud/visual_guidelines" target="_blank">visual guidelines.</a>
@@ -6,12 +6,12 @@
6
6
  ) do %>
7
7
  <%= content.presence || object.input %>
8
8
  <% if object.indeterminate %>
9
- <span class="pb_checkbox_indeterminate">
9
+ <span data-pb-checkbox-icon-span="true" class="pb_checkbox_indeterminate">
10
10
  <%= pb_rails("icon", props: { icon: "minus", classname: "indeterminate_icon", fixed_width: true}) %>
11
11
  <%= pb_rails("icon", props: { icon: "check", classname: "check_icon hidden", fixed_width: true}) %>
12
12
  </span>
13
13
  <% else %>
14
- <span class="pb_checkbox_checkmark">
14
+ <span data-pb-checkbox-icon-span="true" class="pb_checkbox_checkmark">
15
15
  <%= pb_rails("icon", props: { icon: "check", classname: "check_icon", fixed_width: true}) %>
16
16
  <%= pb_rails("icon", props: { icon: "minus", classname: "indeterminate_icon hidden", fixed_width: true}) %>
17
17
  </span>
@@ -18,10 +18,6 @@ module Playbook
18
18
  prop :form_spacing, type: Playbook::Props::Boolean,
19
19
  default: false
20
20
 
21
- def checked_html
22
- checked ? "checked='true'" : nil
23
- end
24
-
25
21
  def classname
26
22
  generate_classname("pb_checkbox_kit", checked_class) + indeterminate_class + error_class
27
23
  end
@@ -1,7 +1,84 @@
1
- <%= pb_rails("checkbox" , props: {
2
- text: "Select ",
3
- value: "checkbox-value",
4
- name: "main",
5
- indeterminate: true,
6
- id: "test-indeterminate-js"
7
- }) %>
1
+ <% checkboxes = [
2
+ { name: 'Coffee', id: 'coffee', checked: false },
3
+ { name: 'Ice Cream', id: 'ice-cream', checked: false },
4
+ { name: 'Chocolate', id: 'chocolate', checked: true }
5
+ ] %>
6
+
7
+ <%= pb_rails("table", props: { container: false, size: "md" }) do %>
8
+ <thead>
9
+ <tr>
10
+ <th>
11
+ <%= pb_rails("checkbox", props: {
12
+ checked: true,
13
+ text: "Uncheck All",
14
+ value: "checkbox-value",
15
+ name: "main-checkbox",
16
+ indeterminate: true,
17
+ id: "indeterminate-checkbox"
18
+ }) %>
19
+ </th>
20
+ </tr>
21
+ </thead>
22
+
23
+ <tbody>
24
+ <% checkboxes.each do |checkbox| %>
25
+ <tr>
26
+ <td>
27
+ <%= pb_rails("checkbox", props: {
28
+ checked: checkbox[:checked],
29
+ text: checkbox[:name],
30
+ value: checkbox[:id],
31
+ name: "#{checkbox[:id]}-indeterminate-checkbox",
32
+ id: "#{checkbox[:id]}-indeterminate-checkbox",
33
+ }) %>
34
+ </td>
35
+ </tr>
36
+ <% end %>
37
+ </tbody>
38
+ <% end %>
39
+
40
+ <script>
41
+ document.addEventListener('DOMContentLoaded', function() {
42
+ const mainCheckboxWrapper = document.getElementById('indeterminate-checkbox');
43
+ const mainCheckbox = document.getElementsByName("main-checkbox")[0];
44
+ const childCheckboxes = document.querySelectorAll('input[type="checkbox"][id$="indeterminate-checkbox"]');
45
+
46
+ const updateMainCheckbox = () => {
47
+ // Count the number of checked child checkboxes
48
+ const checkedCount = Array.from(childCheckboxes).filter(cb => cb.checked).length;
49
+ // Determine if the main checkbox should be in an indeterminate state
50
+ const indeterminate = checkedCount > 0 && checkedCount < childCheckboxes.length;
51
+
52
+ // Set the main checkbox states
53
+ mainCheckbox.indeterminate = indeterminate;
54
+ mainCheckbox.checked = checkedCount > 0;
55
+
56
+ // Determine the main checkbox label based on the number of checked checkboxes
57
+ const text = checkedCount === 0 ? 'Check All' : 'Uncheck All';
58
+
59
+ // Determine the icon class to add and remove based on the number of checked checkboxes
60
+ const iconClassToAdd = checkedCount === 0 ? 'pb_checkbox_checkmark' : 'pb_checkbox_indeterminate';
61
+ const iconClassToRemove = checkedCount === 0 ? 'pb_checkbox_indeterminate' : 'pb_checkbox_checkmark';
62
+
63
+ // Update main checkbox label
64
+ mainCheckboxWrapper.getElementsByClassName('pb_body_kit')[0].textContent = text;
65
+
66
+ // Add and remove the icon class to the main checkbox wrapper
67
+ mainCheckboxWrapper.querySelector('[data-pb-checkbox-icon-span]').classList.add(iconClassToAdd);
68
+ mainCheckboxWrapper.querySelector('[data-pb-checkbox-icon-span]').classList.remove(iconClassToRemove);
69
+
70
+ // Toggle the visibility of the checkbox icon based on the indeterminate state
71
+ mainCheckboxWrapper.getElementsByClassName("indeterminate_icon")[0].classList.toggle('hidden', !indeterminate);
72
+ mainCheckboxWrapper.getElementsByClassName("check_icon")[0].classList.toggle('hidden', indeterminate);
73
+ };
74
+
75
+ mainCheckbox.addEventListener('change', function() {
76
+ childCheckboxes.forEach(cb => cb.checked = this.checked);
77
+ updateMainCheckbox();
78
+ });
79
+
80
+ childCheckboxes.forEach(cb => {
81
+ cb.addEventListener('change', updateMainCheckbox);
82
+ });
83
+ });
84
+ </script>
@@ -28,5 +28,8 @@
28
28
  [class^=pb_title_kit] {
29
29
  color: $text_dk_default !important;
30
30
  }
31
+ [class^=pb_body_kit], [class^=pb_caption_kit] {
32
+ color: $text_dk_light !important;
33
+ }
31
34
  }
32
35
  }
@@ -143,7 +143,7 @@ const datePickerHelper = (config: DatePickerConfig, scrollContainer: string | HT
143
143
 
144
144
  } else if (selectionType === "quickpick") {
145
145
  //------- QUICKPICK VARIANT PLUGIN -------------//
146
- pluginList.push(quickPickPlugin(thisRangesEndToday, customQuickPickDates))
146
+ pluginList.push(quickPickPlugin(thisRangesEndToday, customQuickPickDates, defaultDate as string))
147
147
  }
148
148
 
149
149
  // time selection
@@ -0,0 +1,42 @@
1
+ <%= pb_rails("date_picker", props: {
2
+ allow_input: true,
3
+ default_date: "This month",
4
+ end_date_id: "quick-pick-end-date",
5
+ end_date_name: "quick-pick-end-date",
6
+ mode: "range",
7
+ picker_id: "quick-pick-default-date",
8
+ placeholder: "mm/dd/yyyy to mm/dd/yyyy",
9
+ selection_type: "quickpick",
10
+ start_date_id: "quick-pick-start-date",
11
+ start_date_name: "quick-pick-start-date"
12
+ }) %>
13
+
14
+ <%= pb_rails("date_picker", props: {
15
+ allow_input: true,
16
+ custom_quick_pick_dates: {
17
+ dates: [
18
+ {
19
+ label: "Last 15 months",
20
+ value: {
21
+ timePeriod: "months",
22
+ amount: 15,
23
+ },
24
+ },
25
+ {
26
+ label: "First Week of June 2022",
27
+ value: ["06/01/2022", "06/07/2022"],
28
+ },
29
+ ],
30
+ },
31
+ default_date: "First Week of June 2022",
32
+ end_date_id: "quick-pick-end-date",
33
+ end_date_name: "quick-pick-end-date",
34
+ label: "Custom Date Picker",
35
+ mode: "range",
36
+ picker_id: "custom-quick-pick-default-date",
37
+ placeholder: "mm/dd/yyyy to mm/dd/yyyy",
38
+ selection_type: "quickpick",
39
+ start_date_id: "quick-pick-start-date",
40
+ start_date_name: "quick-pick-start-date"
41
+ }) %>
42
+
@@ -0,0 +1,44 @@
1
+ import React from "react"
2
+ import DatePicker from "../_date_picker"
3
+
4
+ const DatePickerQuickPickDefaultDate = (props) => (
5
+ <>
6
+ <DatePicker
7
+ allowInput
8
+ defaultDate="This month"
9
+ mode="range"
10
+ pickerId="quick-pick-default-date"
11
+ placeholder="mm/dd/yyyy to mm/dd/yyyy"
12
+ selectionType="quickpick"
13
+ {...props}
14
+ />
15
+
16
+ <DatePicker
17
+ allowInput
18
+ customQuickPickDates={{
19
+ dates: [
20
+ {
21
+ label: "Last 15 months",
22
+ value: {
23
+ timePeriod: "months",
24
+ amount: 15,
25
+ },
26
+ },
27
+ {
28
+ label: "First Week of June 2022",
29
+ value: ["06/01/2022", "06/07/2022"],
30
+ },
31
+ ],
32
+ }}
33
+ defaultDate="First Week of June 2022"
34
+ label="Custom Date Picker"
35
+ mode="range"
36
+ pickerId="custom-quick-pick-default-date"
37
+ placeholder="mm/dd/yyyy to mm/dd/yyyy"
38
+ selectionType="quickpick"
39
+ {...props}
40
+ />
41
+ </>
42
+ )
43
+
44
+ export default DatePickerQuickPickDefaultDate
@@ -0,0 +1 @@
1
+ To set a default value using Quick Pick, use the `defaultDate` or `default_date` prop. This prop should match one of the labels displayed in the UI of the dropdown menu.
@@ -12,6 +12,7 @@ examples:
12
12
  - date_picker_quick_pick_range_limit: Range (Quick Pick w/ “This” Range limit)
13
13
  - date_picker_quick_pick_custom: Custom Quick Pick Dates
14
14
  - date_picker_quick_pick_custom_override: Custom Quick Pick Dates (append to defaults)
15
+ - date_picker_quick_pick_default_date: Range (Quick Pick w/ Default Date)
15
16
  - date_picker_format: Format
16
17
  - date_picker_disabled: Disabled Dates
17
18
  - date_picker_min_max: Min Max
@@ -42,6 +43,7 @@ examples:
42
43
  - date_picker_quick_pick_range_limit: Range (Quick Pick w/ “This” Range limit)
43
44
  - date_picker_quick_pick_custom: Custom Quick Pick Dates
44
45
  - date_picker_quick_pick_custom_override: Custom Quick Pick Dates (append to defaults)
46
+ - date_picker_quick_pick_default_date: Range (Quick Pick w/ Default Date)
45
47
  - date_picker_format: Format
46
48
  - date_picker_disabled: Disabled Dates
47
49
  - date_picker_min_max: Min Max
@@ -25,3 +25,4 @@ export { default as DatePickerQuickPickRangeLimit } from './_date_picker_quick_p
25
25
  export { default as DatePickerOnClose } from './_date_picker_on_close.jsx'
26
26
  export { default as DatePickerQuickPickCustom } from './_date_picker_quick_pick_custom'
27
27
  export { default as DatePickerQuickPickCustomOverride } from './_date_picker_quick_pick_custom_override'
28
+ export { default as DatePickerQuickPickDefaultDate } from './_date_picker_quick_pick_default_date'
@@ -26,7 +26,7 @@ type customQuickPickDatesType = {
26
26
 
27
27
  let activeLabel = ""
28
28
 
29
- const quickPickPlugin = (thisRangesEndToday: boolean, customQuickPickDates: customQuickPickDatesType | undefined) => {
29
+ const quickPickPlugin = (thisRangesEndToday: boolean, customQuickPickDates: customQuickPickDatesType | undefined, defaultDate: string) => {
30
30
  return function (fp: FpTypes & any): any {
31
31
  const today = new Date()
32
32
  const yesterday = DateTime.getYesterdayDate(new Date())
@@ -185,6 +185,8 @@ const quickPickPlugin = (thisRangesEndToday: boolean, customQuickPickDates: cust
185
185
  return {
186
186
  // onReady is a hook from flatpickr that runs when calendar is in a ready state
187
187
  onReady(selectedDates: Array<Date>) {
188
+ let defaultDateRange
189
+
188
190
  // loop through the ranges and create an anchor tag for each range and add an event listener to set the date when user clicks on a date range
189
191
  for (const [label, range] of Object.entries(pluginData.ranges)) {
190
192
  addRangeButton(label).addEventListener('click', function () {
@@ -201,6 +203,14 @@ const quickPickPlugin = (thisRangesEndToday: boolean, customQuickPickDates: cust
201
203
  fp.close();
202
204
  }
203
205
  });
206
+
207
+ // check if there is a default date and set the default date range and label for quick pick
208
+ if (defaultDate) {
209
+ if (label.toLowerCase() === defaultDate.toLowerCase()) {
210
+ activeLabel = label
211
+ defaultDateRange = range
212
+ }
213
+ }
204
214
  }
205
215
  // conditional to check if there is a dropdown to add it to the calendar container and get it the classes it needs
206
216
  if (pluginData.rangesNav.children.length > 0) {
@@ -216,6 +226,12 @@ const quickPickPlugin = (thisRangesEndToday: boolean, customQuickPickDates: cust
216
226
  // function to give the active button the active class
217
227
  selectActiveRangeButton(selectedDates);
218
228
  }
229
+
230
+ // set the default date range if there is one and select the active button
231
+ if (defaultDateRange) {
232
+ fp.setDate(defaultDateRange, false);
233
+ selectActiveRangeButton(defaultDateRange);
234
+ }
219
235
  },
220
236
  onValueUpdate(selectedDates: Array<Date>) {
221
237
  selectActiveRangeButton(selectedDates)
@@ -0,0 +1,26 @@
1
+ <% initial_items = [
2
+ {
3
+ id: "1",
4
+ url: "https://unsplash.it/500/400/?image=633",
5
+ },
6
+ {
7
+ id: "2",
8
+ url: "https://unsplash.it/500/400/?image=634",
9
+ },
10
+ {
11
+ id: "3",
12
+ url: "https://unsplash.it/500/400/?image=637",
13
+ },
14
+ ] %>
15
+
16
+ <%= pb_rails("draggable", props: {initial_items: initial_items}) do %>
17
+ <%= pb_rails("draggable/draggable_container") do %>
18
+ <%= pb_rails("flex") do %>
19
+ <% initial_items.each do |item| %>
20
+ <%= pb_rails("draggable/draggable_item", props:{drag_id: item[:id]}) do %>
21
+ <%= pb_rails("image", props: { alt: item[:id], size: "md", url: item[:url], margin: "xs" }) %>
22
+ <% end %>
23
+ <% end %>
24
+ <% end %>
25
+ <% end %>
26
+ <% end %>
@@ -0,0 +1,7 @@
1
+ The `draggable` kit gives you a full subcomponent structure that allows it to be used with almost any kit.
2
+
3
+ `initial_items` is a REQUIRED prop, which is the array of objects that contains data for the the draggable items.
4
+
5
+ `draggable/draggable_container` = This specifies the container within which items can be dropped.
6
+
7
+ `draggable/draggable_item` = This specifies the items that can be dragged and dropped. `drag_id` is a REQUIRED prop for draggable_item and must match the id on the items within `initial_items`.
@@ -0,0 +1,38 @@
1
+ <% initial_items = [
2
+ { id: "21", name: "Joe Black" },
3
+ { id: "22", name: "Nancy White" },
4
+ { id: "23", name: "Bill Green" },
5
+ ] %>
6
+
7
+ <%= pb_rails("draggable", props: {initial_items: initial_items}) do %>
8
+ <%= pb_rails("draggable/draggable_container") do %>
9
+ <% initial_items.each do |item| %>
10
+ <%= pb_rails("draggable/draggable_item", props:{drag_id: item[:id]}) do %>
11
+ <%= pb_rails("card", props: {highlight: {position: "side", color:"primary"}, margin_bottom: "xs", padding: "xs"}) do %>
12
+ <%= pb_rails("flex", props:{align_items: "stretch", flex_direction:"column"}) do %>
13
+ <%= pb_rails("flex", props:{gap: "xs"}) do %>
14
+ <%= pb_rails("title", props: { text: item[:name], tag: "h4", size: 4 }) %>
15
+ <%= pb_rails("badge", props: {text:"35-12345" ,variant: "primary"}) %>
16
+ <% end %>
17
+ <%= pb_rails("caption", props: { size: "xs", text: "8:00A • Township Name • 90210" }) %>
18
+ <%= pb_rails("flex", props:{gap: "xxs", spacing:"between"}) do %>
19
+ <%= pb_rails("flex", props:{gap: "xxs"}) do %>
20
+ <%= pb_rails("caption", props: { size: "xs" , color: "error" }) do %>
21
+ <%= pb_rails("icon", props: { icon: "house-circle-exclamation", fixed_width: true }) %>
22
+ <% end %>
23
+ <%= pb_rails("caption", props: { size: "xs" , color: "success" }) do %>
24
+ <%= pb_rails("icon", props: { icon: "file-circle-check", fixed_width: true }) %>
25
+ <% end %>
26
+ <% end %>
27
+ <%= pb_rails("flex") do %>
28
+ <%= pb_rails("badge", props: {text:"Schedule QA" ,variant: "warning", rounded: true}) %>
29
+ <%= pb_rails("badge", props: {text:"Flex" ,variant: "primary", rounded: true}) %>
30
+ <%= pb_rails("badge", props: {text:"R99" ,variant: "primary", rounded: true}) %>
31
+ <% end %>
32
+ <% end %>
33
+ <% end %>
34
+ <% end %>
35
+ <% end %>
36
+ <% end %>
37
+ <% end %>
38
+ <% end %>
@@ -0,0 +1,19 @@
1
+ <% initial_items = [
2
+ { id: "31", name: "Philadelphia" },
3
+ { id: "32", name: "New Jersey" },
4
+ { id: "33", name: "Maryland" },
5
+ { id: "34", name: "Connecticut" },
6
+
7
+ ] %>
8
+
9
+ <%= pb_rails("draggable", props: {initial_items: initial_items}) do %>
10
+ <%= pb_rails("draggable/draggable_container") do %>
11
+ <%= pb_rails("list", props: {ordered: false}) do %>
12
+ <% initial_items.each do |item| %>
13
+ <%= pb_rails("draggable/draggable_item", props:{drag_id: item[:id]}) do %>
14
+ <%= pb_rails("list/item") do %><%= item[:name] %><% end %>
15
+ <% end %>
16
+ <% end %>
17
+ <% end %>
18
+ <% end %>
19
+ <% end %>
@@ -8,4 +8,10 @@ examples:
8
8
  - draggable_with_cards: Draggable with Cards
9
9
  - draggable_multiple_containers: Dragging Across Multiple Containers
10
10
 
11
+ rails:
12
+ - draggable_default_rails: Default
13
+ - draggable_with_list_rails: Draggable with List Kit
14
+ - draggable_with_cards_rails: Draggable with Cards
15
+
16
+
11
17
 
@@ -0,0 +1,3 @@
1
+ <%= pb_content_tag do %>
2
+ <%= content.presence %>
3
+ <% end %>
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Playbook
4
+ module PbDraggable
5
+ class Draggable < ::Playbook::KitBase
6
+ prop :initial_items, type: Playbook::Props::Array,
7
+ default: []
8
+
9
+ def data
10
+ Hash(prop(:data)).merge(pb_draggable: true)
11
+ end
12
+
13
+ def classname
14
+ generate_classname("pb_draggable")
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,3 @@
1
+ <%= pb_content_tag do %>
2
+ <%= content.presence %>
3
+ <% end %>
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Playbook
4
+ module PbDraggable
5
+ class DraggableContainer < ::Playbook::KitBase
6
+ def data
7
+ Hash(prop(:data)).merge(pb_draggable_container: true)
8
+ end
9
+
10
+ def classname
11
+ generate_classname("pb_draggable_container")
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,7 @@
1
+ <%= pb_content_tag(:div, {
2
+ id: "item_#{object.drag_id}",
3
+ draggable: true
4
+ }) do %>
5
+ <%= content.presence %>
6
+ <% end %>
7
+
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Playbook
4
+ module PbDraggable
5
+ class DraggableItem < ::Playbook::KitBase
6
+ prop :drag_id, type: Playbook::Props::String,
7
+ default: ""
8
+
9
+ def data
10
+ Hash(prop(:data)).merge(pb_draggable_item: true)
11
+ end
12
+
13
+ def classname
14
+ generate_classname("pb_draggable_item")
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,125 @@
1
+ import PbEnhancedElement from "../pb_enhanced_element";
2
+
3
+ const DRAGGABLE_SELECTOR = "[data-pb-draggable]";
4
+ const DRAGGABLE_CONTAINER = ".pb_draggable_container";
5
+
6
+ export default class PbDraggable extends PbEnhancedElement {
7
+ static get selector() {
8
+ return DRAGGABLE_SELECTOR;
9
+ }
10
+
11
+ connect() {
12
+ this.draggedItem = null;
13
+ this.draggedItemId = null;
14
+ document.addEventListener("DOMContentLoaded", () => this.bindEventListeners());
15
+ }
16
+
17
+ bindEventListeners() {
18
+ // Needed to prevent images within draggable items from being independently draggable
19
+ // Needed if using Image kit in draggable items
20
+ this.element.querySelectorAll(".pb_draggable_item img").forEach(img => {
21
+ img.setAttribute("draggable", "false");
22
+ });
23
+
24
+ this.element.querySelectorAll(".pb_draggable_item").forEach(item => {
25
+ item.addEventListener("dragstart", this.handleDragStart.bind(this));
26
+ item.addEventListener("dragend", this.handleDragEnd.bind(this));
27
+ item.addEventListener("dragenter", this.handleDragEnter.bind(this));
28
+ });
29
+
30
+ const container = this.element.querySelector(DRAGGABLE_CONTAINER);
31
+ if (container) {
32
+ container.addEventListener("dragover", this.handleDragOver.bind(this));
33
+ container.addEventListener("drop", this.handleDrop.bind(this));
34
+ }
35
+ }
36
+
37
+ handleDragStart(event) {
38
+ // Needed to prevent images within draggable items from being independently draggable
39
+ // Needed if using Image kit in draggable items
40
+ if (event.target.tagName.toLowerCase() === 'img') {
41
+ event.preventDefault();
42
+ return;
43
+ }
44
+
45
+ this.draggedItem = event.target;
46
+ this.draggedItemId = event.target.id;
47
+ event.target.classList.add("is_dragging");
48
+
49
+ if (event.dataTransfer) {
50
+ event.dataTransfer.effectAllowed = 'move';
51
+ event.dataTransfer.setData('text/plain', this.draggedItemId);
52
+ }
53
+
54
+ setTimeout(() => {
55
+ event.target.style.opacity = '0.5';
56
+ }, 0);
57
+ }
58
+
59
+ handleDragEnter(event) {
60
+ if (!this.draggedItem || event.target === this.draggedItem) return;
61
+
62
+ const targetItem = event.target.closest('.pb_draggable_item');
63
+ if (!targetItem) return;
64
+
65
+ const container = targetItem.parentNode;
66
+ const items = Array.from(container.children);
67
+ const draggedIndex = items.indexOf(this.draggedItem);
68
+ const targetIndex = items.indexOf(targetItem);
69
+
70
+ if (draggedIndex > targetIndex) {
71
+ container.insertBefore(this.draggedItem, targetItem);
72
+ } else {
73
+ container.insertBefore(this.draggedItem, targetItem.nextSibling);
74
+ }
75
+ }
76
+
77
+ handleDragOver(event) {
78
+ event.preventDefault();
79
+ const container = event.target.closest(DRAGGABLE_CONTAINER);
80
+
81
+ if (container) {
82
+ container.classList.add("active_container");
83
+ }
84
+ }
85
+
86
+ handleDrop(event) {
87
+ event.preventDefault();
88
+ const container = event.target.closest(DRAGGABLE_CONTAINER);
89
+ if (!container || !this.draggedItem) return;
90
+
91
+ container.classList.remove("active_container");
92
+ this.draggedItem.style.opacity = '1';
93
+
94
+ // Updated order of items as an array of item IDs
95
+ const reorderedItems = Array.from(container.children)
96
+ .filter(item => item.classList.contains("pb_draggable_item"))
97
+ .map(item => item.id.replace("item_", ""));
98
+
99
+ // Store reordered items in a data attribute on the container
100
+ container.setAttribute("data-reordered-items", JSON.stringify(reorderedItems));
101
+
102
+ const customEvent = new CustomEvent('pb-draggable-reorder', {
103
+ detail: {
104
+ reorderedItems,
105
+ containerId: container.id,
106
+ }
107
+ });
108
+ this.element.dispatchEvent(customEvent);
109
+
110
+ this.draggedItem = null;
111
+ this.draggedItemId = null;
112
+ }
113
+
114
+
115
+ handleDragEnd(event) {
116
+ event.target.classList.remove("is_dragging");
117
+ event.target.style.opacity = '1';
118
+ this.draggedItem = null;
119
+ this.draggedItemId = null;
120
+
121
+ this.element.querySelectorAll(DRAGGABLE_CONTAINER).forEach(container => {
122
+ container.classList.remove("active_container");
123
+ });
124
+ }
125
+ }