playbook_ui 14.6.2.pre.alpha.PLAY15814384 → 14.7.0.pre.alpha.PBNTR637quickpickdefaultdate4478

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/_playbook.scss +1 -1
  3. data/app/pb_kits/playbook/pb_advanced_table/Components/CustomCell.tsx +8 -1
  4. data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.tsx +21 -28
  5. data/app/pb_kits/playbook/pb_advanced_table/advanced_table.test.jsx +37 -1
  6. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_custom_cell.jsx +13 -2
  7. data/app/pb_kits/playbook/pb_card/docs/_card_light.md +1 -1
  8. data/app/pb_kits/playbook/pb_date/_date.scss +3 -0
  9. data/app/pb_kits/playbook/pb_date_picker/date_picker_helper.ts +1 -1
  10. data/app/pb_kits/playbook/pb_date_picker/plugins/quickPick.tsx +16 -1
  11. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_default_rails.html.erb +26 -0
  12. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_default_rails.md +7 -0
  13. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_with_cards_rails.html.erb +38 -0
  14. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_with_cards_rails.md +0 -0
  15. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_with_list_rails.html.erb +19 -0
  16. data/app/pb_kits/playbook/pb_draggable/docs/example.yml +6 -0
  17. data/app/pb_kits/playbook/pb_draggable/draggable.html.erb +3 -0
  18. data/app/pb_kits/playbook/pb_draggable/draggable.rb +18 -0
  19. data/app/pb_kits/playbook/pb_draggable/draggable_container.html.erb +3 -0
  20. data/app/pb_kits/playbook/pb_draggable/draggable_container.rb +15 -0
  21. data/app/pb_kits/playbook/pb_draggable/draggable_item.html.erb +7 -0
  22. data/app/pb_kits/playbook/pb_draggable/draggable_item.rb +18 -0
  23. data/app/pb_kits/playbook/pb_draggable/index.js +125 -0
  24. data/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx +8 -7
  25. data/app/pb_kits/playbook/pb_skeleton_loading/_skeleton_loading.scss +37 -0
  26. data/app/pb_kits/playbook/pb_skeleton_loading/_skeleton_loading.tsx +67 -0
  27. data/app/pb_kits/playbook/pb_skeleton_loading/_skeleton_loading_mixins.scss +40 -0
  28. data/app/pb_kits/playbook/pb_skeleton_loading/docs/_skeleton_loading_border_radius.jsx +51 -0
  29. data/app/pb_kits/playbook/pb_skeleton_loading/docs/_skeleton_loading_border_radius.md +1 -0
  30. data/app/pb_kits/playbook/pb_skeleton_loading/docs/_skeleton_loading_color.jsx +26 -0
  31. data/app/pb_kits/playbook/pb_skeleton_loading/docs/_skeleton_loading_color.md +1 -0
  32. data/app/pb_kits/playbook/pb_skeleton_loading/docs/_skeleton_loading_default.html.erb +1 -0
  33. data/app/pb_kits/playbook/pb_skeleton_loading/docs/_skeleton_loading_default.jsx +11 -0
  34. data/app/pb_kits/playbook/pb_skeleton_loading/docs/_skeleton_loading_height_width.jsx +59 -0
  35. data/app/pb_kits/playbook/pb_skeleton_loading/docs/_skeleton_loading_height_width.md +3 -0
  36. data/app/pb_kits/playbook/pb_skeleton_loading/docs/_skeleton_loading_layout.jsx +20 -0
  37. data/app/pb_kits/playbook/pb_skeleton_loading/docs/_skeleton_loading_layout.md +3 -0
  38. data/app/pb_kits/playbook/pb_skeleton_loading/docs/example.yml +13 -0
  39. data/app/pb_kits/playbook/pb_skeleton_loading/docs/index.js +5 -0
  40. data/app/pb_kits/playbook/pb_skeleton_loading/skeleton_loading.html.erb +12 -0
  41. data/app/pb_kits/playbook/pb_skeleton_loading/skeleton_loading.rb +8 -0
  42. data/app/pb_kits/playbook/pb_skeleton_loading/skeleton_loading.test.jsx +81 -0
  43. data/app/pb_kits/playbook/utilities/_hover.scss +46 -43
  44. data/app/pb_kits/playbook/utilities/globalPropNames.mjs +1 -0
  45. data/app/pb_kits/playbook/utilities/globalProps.ts +5 -0
  46. data/dist/chunks/{_typeahead-C-6MLSyC.js → _typeahead-BXzFhaTy.js} +2 -2
  47. data/dist/chunks/_weekday_stacked-CWQekIDV.js +45 -0
  48. data/dist/chunks/{lib-D-mTv-kp.js → lib-lcEbe0vX.js} +1 -1
  49. data/dist/chunks/{pb_form_validation-BkWGwJsl.js → pb_form_validation-yoi2KCvh.js} +1 -1
  50. data/dist/chunks/vendor.js +1 -1
  51. data/dist/menu.yml +5 -2
  52. data/dist/playbook-doc.js +1 -1
  53. data/dist/playbook-rails-react-bindings.js +1 -1
  54. data/dist/playbook-rails.js +1 -1
  55. data/dist/playbook.css +1 -1
  56. data/lib/playbook/hover.rb +4 -1
  57. data/lib/playbook/version.rb +2 -2
  58. metadata +36 -6
  59. data/dist/chunks/_weekday_stacked-CFhGhr9V.js +0 -45
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 99a985521715b9d9f16885c5dc378e0d7ef8eebcbad2a611a07b1d64430497ca
4
- data.tar.gz: 746ddd3bb48bac086703ef46dc0733126e3a192ea50be712662ebf9c2db4d77b
3
+ metadata.gz: 2aae8481b1aab6e16592bdb4bb4c51a95c3665e6eb162ffa93180861eb8f603d
4
+ data.tar.gz: f55172cd776c9df9cc82e7a71218fdbef4a511a3f2703c7cff4ca50c48c49072
5
5
  SHA512:
6
- metadata.gz: 1b78546cabdd8d4372db3fa8031a6d738d1357ddb8d0e860ed080b2f12fcdafc8ede1cfe0bbc8454465c488fdff6a373be95d70a81cca91711a966b0152cbb08
7
- data.tar.gz: 9fa3a3f4a1beb10625b7bd7774c9b9029436487c75b817d9e71667d3876fdd16c611cb3bbfed67ddec48e9d46ff260c795344df9d35a94f3b7bc11ef58360ddb
6
+ metadata.gz: fe7c3e42f5cc9e3f9c00f6b107dc5f2b3580213b1fd162c86766a3be1d5c0f5adc023a3b986bbe5179562d789d86cef414384b0e360fd5d6e35e0281c6176b10
7
+ data.tar.gz: e63e60cbe652a2c2f652376a29d2b1543afca464f0d8ca79ce25f0637fa399385698711c45a513ce36860b036c6de234a15fb2a9745284aa42d356c94837d5d8
@@ -1,4 +1,3 @@
1
-
2
1
  @import 'pb_advanced_table/advanced_table';
3
2
  @import 'pb_avatar/avatar';
4
3
  @import 'pb_avatar_action_button/avatar_action_button';
@@ -85,6 +84,7 @@
85
84
  @import 'pb_selectable_card_icon/selectable_card_icon';
86
85
  @import 'pb_selectable_icon/selectable_icon';
87
86
  @import 'pb_selectable_list/selectable_list';
87
+ @import 'pb_skeleton_loading/skeleton_loading';
88
88
  @import 'pb_source/source';
89
89
  @import 'pb_star_rating/star_rating';
90
90
  @import 'pb_stat_change/stat_change';
@@ -16,6 +16,7 @@ interface CustomCellProps {
16
16
  onRowToggleClick?: (arg: Row<GenericObject>) => void
17
17
  row: Row<GenericObject>
18
18
  value?: string
19
+ customRenderer?: (row: Row<GenericObject>, value: string | undefined) => React.ReactNode
19
20
  }
20
21
 
21
22
  export const CustomCell = ({
@@ -23,6 +24,7 @@ export const CustomCell = ({
23
24
  onRowToggleClick,
24
25
  row,
25
26
  value,
27
+ customRenderer,
26
28
  }: CustomCellProps & GlobalProps) => {
27
29
  const { setExpanded, expanded, expandedControl, inlineRowLoading } = useContext(AdvancedTableContext);
28
30
 
@@ -61,7 +63,12 @@ export const CustomCell = ({
61
63
  </button>
62
64
  ) : null}
63
65
  <FlexItem paddingLeft={renderButton? "none" : "xs"}>
64
- {row.depth === 0 ? getValue() : value}
66
+ {row.depth === 0 ? (
67
+ customRenderer ? customRenderer(row, getValue()) : getValue()
68
+ ) :(
69
+ customRenderer ? customRenderer(row, value) : value
70
+ )
71
+ }
65
72
  </FlexItem>
66
73
  </Flex>
67
74
  </div>
@@ -90,8 +90,8 @@ const AdvancedTable = (props: AdvancedTableProps) => {
90
90
 
91
91
  const columnHelper = createColumnHelper()
92
92
 
93
- //Create cells for first columns
94
- const createCellFunction = (cellAccessors: string[], customRenderer?: (row: Row<GenericObject>, value: any) => JSX.Element) => {
93
+ //Create cells for columns, with customization for first column
94
+ const createCellFunction = (cellAccessors: string[], customRenderer?: (row: Row<GenericObject>, value: any) => JSX.Element, index?: number) => {
95
95
  const columnCells = ({
96
96
  row,
97
97
  getValue,
@@ -101,19 +101,16 @@ const AdvancedTable = (props: AdvancedTableProps) => {
101
101
  }) => {
102
102
  const rowData = row.original
103
103
 
104
- // Use customRenderer if provided, otherwise default rendering
105
- if (customRenderer) {
106
- return customRenderer(row, getValue())
107
- }
108
-
104
+ if (index === 0) {
109
105
  switch (row.depth) {
110
106
  case 0: {
111
107
  return (
112
- <CustomCell
113
- getValue={getValue}
114
- onRowToggleClick={onRowToggleClick}
115
- row={row}
116
- />
108
+ <CustomCell
109
+ customRenderer={customRenderer}
110
+ getValue={getValue}
111
+ onRowToggleClick={onRowToggleClick}
112
+ row={row}
113
+ />
117
114
  )
118
115
  }
119
116
  default: {
@@ -122,6 +119,7 @@ const AdvancedTable = (props: AdvancedTableProps) => {
122
119
  const accessorValue = rowData[depthAccessor]
123
120
  return accessorValue ? (
124
121
  <CustomCell
122
+ customRenderer={customRenderer}
125
123
  onRowToggleClick={onRowToggleClick}
126
124
  row={row}
127
125
  value={accessorValue}
@@ -132,11 +130,13 @@ const AdvancedTable = (props: AdvancedTableProps) => {
132
130
  }
133
131
  }
134
132
  }
135
-
133
+ return customRenderer
134
+ ? customRenderer(row, getValue())
135
+ : getValue()
136
+ }
136
137
  return columnCells
137
138
  }
138
-
139
- //Create column array in format needed by Tanstack
139
+ //Create column array in format needed by Tanstack
140
140
  const columns =
141
141
  columnDefinitions &&
142
142
  columnDefinitions.map((column, index) => {
@@ -147,19 +147,12 @@ const AdvancedTable = (props: AdvancedTableProps) => {
147
147
  }),
148
148
  }
149
149
 
150
- // Use the custom renderer if provided, EXCEPT for the first column
151
- if (index !== 0) {
152
- if (column.cellAccessors || column.customRenderer) {
153
- columnStructure.cell = createCellFunction(
154
- column.cellAccessors,
155
- column.customRenderer
156
- )
157
- }
158
- } else {
159
- // For the first column, apply createCellFunction without customRenderer
160
- if (column.cellAccessors) {
161
- columnStructure.cell = createCellFunction(column.cellAccessors)
162
- }
150
+ if (column.cellAccessors || column.customRenderer) {
151
+ columnStructure.cell = createCellFunction(
152
+ column.cellAccessors,
153
+ column.customRenderer,
154
+ index
155
+ )
163
156
  }
164
157
 
165
158
  return columnStructure
@@ -1,7 +1,7 @@
1
1
  import React, {useState} from "react"
2
2
  import { render, screen, waitFor } from "../utilities/test-utils"
3
3
 
4
- import { AdvancedTable } from "playbook-ui"
4
+ import { AdvancedTable, Pill } from "playbook-ui"
5
5
 
6
6
  const MOCK_DATA = [
7
7
  {
@@ -88,6 +88,28 @@ const columnDefinitions = [
88
88
  },
89
89
  ]
90
90
 
91
+ const columnDefinitionsCustomRenderer = [
92
+ {
93
+ accessor: "year",
94
+ label: "Year",
95
+ cellAccessors: ["quarter", "month", "day"],
96
+ },
97
+ {
98
+ accessor: "newEnrollments",
99
+ label: "New Enrollments",
100
+ customRenderer: (row, value) => (
101
+ <Pill text={value}
102
+ variant="success"
103
+ />
104
+ ),
105
+ },
106
+ {
107
+ accessor: "scheduledMeetings",
108
+ label: "Scheduled Meetings",
109
+ },
110
+ ]
111
+
112
+
91
113
  const subRowHeaders = ["Quarter"]
92
114
 
93
115
  const testId = "advanced_table"
@@ -463,3 +485,17 @@ test("responsive none prop functions as expected", () => {
463
485
  const kit = screen.getByTestId(testId)
464
486
  expect(kit).toHaveClass("pb_advanced_table table-responsive-none")
465
487
  })
488
+
489
+ test("customRenderer prop functions as expected", () => {
490
+ render(
491
+ <AdvancedTable
492
+ columnDefinitions={columnDefinitionsCustomRenderer}
493
+ data={{ testid: testId }}
494
+ tableData={MOCK_DATA}
495
+ />
496
+ )
497
+
498
+ const kit = screen.getByTestId(testId)
499
+ const pill = kit.querySelector(".pb_pill_kit_success_lowercase")
500
+ expect(pill).toBeInTheDocument()
501
+ })
@@ -1,5 +1,5 @@
1
1
  import React from "react"
2
- import { AdvancedTable, Pill, Body, Flex, Detail, Caption } from "playbook-ui"
2
+ import { AdvancedTable, Pill, Body, Flex, Detail, Caption, Badge, Title } from "playbook-ui"
3
3
  import MOCK_DATA from "./advanced_table_mock_data.json"
4
4
 
5
5
  const AdvancedTableCustomCell = (props) => {
@@ -8,7 +8,18 @@ const AdvancedTableCustomCell = (props) => {
8
8
  accessor: "year",
9
9
  label: "Year",
10
10
  cellAccessors: ["quarter", "month", "day"],
11
-
11
+ customRenderer: (row, value) => (
12
+ <Flex>
13
+ <Title size={4}
14
+ text={value}
15
+ />
16
+ <Badge dark
17
+ marginLeft="xxs"
18
+ text={row.original.newEnrollments > 20 ? "High" : "Low"}
19
+ variant="neutral"
20
+ />
21
+ </Flex>
22
+ ),
12
23
  },
13
24
  {
14
25
  accessor: "newEnrollments",
@@ -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>
@@ -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
@@ -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, defaultDateLabel
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,13 @@ const quickPickPlugin = (thisRangesEndToday: boolean, customQuickPickDates: cust
201
203
  fp.close();
202
204
  }
203
205
  });
206
+
207
+ if (defaultDate) {
208
+ if (label.toLowerCase() === defaultDate.toLowerCase()) {
209
+ defaultDateRange = range
210
+ defaultDateLabel = label
211
+ }
212
+ }
204
213
  }
205
214
  // conditional to check if there is a dropdown to add it to the calendar container and get it the classes it needs
206
215
  if (pluginData.rangesNav.children.length > 0) {
@@ -216,6 +225,12 @@ const quickPickPlugin = (thisRangesEndToday: boolean, customQuickPickDates: cust
216
225
  // function to give the active button the active class
217
226
  selectActiveRangeButton(selectedDates);
218
227
  }
228
+
229
+ if (defaultDateRange && defaultDateLabel) {
230
+ fp.setDate(defaultDateRange, false);
231
+ activeLabel = defaultDateLabel
232
+ selectActiveRangeButton(defaultDateRange);
233
+ }
219
234
  },
220
235
  onValueUpdate(selectedDates: Array<Date>) {
221
236
  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
+ }
@@ -47,7 +47,7 @@ interface DropdownComponent
47
47
  Container: typeof DropdownContainer;
48
48
  }
49
49
 
50
- const Dropdown = forwardRef((props: DropdownProps, ref: any) => {
50
+ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
51
51
  const {
52
52
  aria = {},
53
53
  autocomplete = false,
@@ -260,7 +260,7 @@ const Dropdown = forwardRef((props: DropdownProps, ref: any) => {
260
260
  <DropdownContainer>
261
261
  {optionsWithBlankSelection &&
262
262
  optionsWithBlankSelection?.map((option: GenericObject) => (
263
- <Dropdown.Option key={option.id}
263
+ <DropdownOption key={option.id}
264
264
  option={option}
265
265
  />
266
266
  ))}
@@ -278,11 +278,12 @@ const Dropdown = forwardRef((props: DropdownProps, ref: any) => {
278
278
  </DropdownContext.Provider>
279
279
  </div>
280
280
  )
281
- }) as DropdownComponent
281
+ }
282
282
 
283
- Dropdown.displayName = "Dropdown";
284
- Dropdown.Option = DropdownOption;
285
- Dropdown.Trigger = DropdownTrigger;
286
- Dropdown.Container = DropdownContainer;
283
+ Dropdown = forwardRef(Dropdown) as unknown as DropdownComponent;
284
+ (Dropdown as DropdownComponent).displayName = "Dropdown";
285
+ (Dropdown as DropdownComponent).Option = DropdownOption;
286
+ (Dropdown as DropdownComponent).Trigger = DropdownTrigger;
287
+ (Dropdown as DropdownComponent).Container = DropdownContainer;
287
288
 
288
289
  export default Dropdown;