playbook_ui 13.28.0.pre.alpha.PLAY13592980 → 13.28.0.pre.alpha.pbntr312tableheaderflexremoval3019

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/_playbook.scss +2 -3
  3. data/app/pb_kits/playbook/index.js +2 -0
  4. data/app/pb_kits/playbook/pb_bar_graph/_bar_graph.tsx +4 -1
  5. data/app/pb_kits/playbook/pb_bar_graph/barGraph.test.js +31 -0
  6. data/app/pb_kits/playbook/pb_bar_graph/bar_graph.rb +16 -0
  7. data/app/pb_kits/playbook/pb_circle_chart/_circle_chart.tsx +5 -2
  8. data/app/pb_kits/playbook/pb_circle_chart/circleChart.test.js +45 -0
  9. data/app/pb_kits/playbook/pb_circle_chart/circle_chart.rb +16 -0
  10. data/app/pb_kits/playbook/pb_collapsible/__snapshots__/collapsible.test.js.snap +53 -0
  11. data/app/pb_kits/playbook/pb_collapsible/_collapsible.tsx +14 -8
  12. data/app/pb_kits/playbook/pb_collapsible/collapsible.test.js +24 -0
  13. data/app/pb_kits/playbook/pb_dashboard/pbChartsDarkTheme.ts +7 -1
  14. data/app/pb_kits/playbook/pb_dashboard/pbChartsLightTheme.ts +9 -1
  15. data/app/pb_kits/playbook/pb_draggable/_draggable.scss +10 -0
  16. data/app/pb_kits/playbook/pb_draggable/_draggable.tsx +53 -0
  17. data/app/pb_kits/playbook/pb_draggable/context/index.tsx +92 -0
  18. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_default.jsx +53 -0
  19. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_multiple_containers.jsx +159 -0
  20. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_with_cards.jsx +121 -0
  21. data/app/pb_kits/playbook/pb_draggable/docs/example.yml +9 -0
  22. data/app/pb_kits/playbook/pb_draggable/docs/index.js +3 -0
  23. data/app/pb_kits/playbook/pb_draggable/draggable.test.jsx +65 -0
  24. data/app/pb_kits/playbook/pb_draggable/subcomponents/DraggableContainer.tsx +54 -0
  25. data/app/pb_kits/playbook/pb_draggable/subcomponents/DraggableItem.tsx +57 -0
  26. data/app/pb_kits/playbook/pb_form_group/_form_group.scss +2 -2
  27. data/app/pb_kits/playbook/pb_gauge/gauge.test.js +35 -0
  28. data/app/pb_kits/playbook/pb_icon/icon.rb +2 -3
  29. data/app/pb_kits/playbook/pb_line_graph/_line_graph.tsx +4 -1
  30. data/app/pb_kits/playbook/pb_line_graph/lineGraph.test.js +52 -0
  31. data/app/pb_kits/playbook/pb_line_graph/line_graph.rb +16 -0
  32. data/app/pb_kits/playbook/pb_table/_table.tsx +5 -0
  33. data/app/pb_kits/playbook/pb_table/docs/_table_alignment_column.jsx +33 -32
  34. data/app/pb_kits/playbook/pb_table/docs/_table_alignment_column.md +1 -1
  35. data/app/pb_kits/playbook/pb_table/docs/_table_alignment_column_rails.html.erb +33 -0
  36. data/app/pb_kits/playbook/pb_table/docs/_table_alignment_column_rails.md +2 -0
  37. data/app/pb_kits/playbook/pb_table/docs/_table_alignment_row.jsx +33 -33
  38. data/app/pb_kits/playbook/pb_table/docs/_table_alignment_row.md +1 -1
  39. data/app/pb_kits/playbook/pb_table/docs/_table_alignment_row_rails.html.erb +34 -0
  40. data/app/pb_kits/playbook/pb_table/docs/_table_alignment_row_rails.md +2 -0
  41. data/app/pb_kits/playbook/pb_table/docs/_table_alignment_shift_data.jsx +51 -50
  42. data/app/pb_kits/playbook/pb_table/docs/_table_alignment_shift_data.md +1 -1
  43. data/app/pb_kits/playbook/pb_table/docs/_table_alignment_shift_data_rails.html.erb +54 -0
  44. data/app/pb_kits/playbook/pb_table/docs/_table_alignment_shift_data_rails.md +2 -0
  45. data/app/pb_kits/playbook/pb_table/docs/_table_alignment_shift_row.jsx +37 -38
  46. data/app/pb_kits/playbook/pb_table/docs/_table_alignment_shift_row.md +1 -0
  47. data/app/pb_kits/playbook/pb_table/docs/_table_alignment_shift_row_rails.html.erb +53 -0
  48. data/app/pb_kits/playbook/pb_table/docs/_table_alignment_shift_row_rails.md +1 -0
  49. data/app/pb_kits/playbook/pb_table/docs/{_table_alignment_row.html.erb → _table_outer_padding.html.erb} +7 -7
  50. data/app/pb_kits/playbook/pb_table/docs/_table_outer_padding.jsx +76 -0
  51. data/app/pb_kits/playbook/pb_table/docs/_table_outer_padding.md +1 -0
  52. data/app/pb_kits/playbook/pb_table/docs/example.yml +9 -9
  53. data/app/pb_kits/playbook/pb_table/docs/index.js +1 -0
  54. data/app/pb_kits/playbook/pb_table/styles/_all.scss +1 -0
  55. data/app/pb_kits/playbook/pb_table/styles/_outer_padding.scss +21 -0
  56. data/app/pb_kits/playbook/pb_table/table.rb +14 -1
  57. data/app/pb_kits/playbook/pb_table/table.test.js +5 -1
  58. data/app/pb_kits/playbook/pb_table/table_header.html.erb +0 -2
  59. data/app/pb_kits/playbook/pb_treemap_chart/treemapChart.test.js +61 -0
  60. data/app/pb_kits/playbook/playbook-doc.js +2 -0
  61. data/app/pb_kits/playbook/tokens/_vertical_align.scss +18 -0
  62. data/app/pb_kits/playbook/utilities/_vertical_align.scss +16 -0
  63. data/app/pb_kits/playbook/utilities/globalProps.ts +12 -1
  64. data/dist/menu.yml +5 -2
  65. data/dist/playbook-rails.js +6 -6
  66. data/lib/playbook/classnames.rb +1 -0
  67. data/lib/playbook/kit_base.rb +2 -0
  68. data/lib/playbook/version.rb +1 -1
  69. data/lib/playbook/vertical_align.rb +37 -0
  70. metadata +35 -6
  71. data/app/pb_kits/playbook/pb_table/docs/_table_alignment_column.html.erb +0 -34
  72. data/app/pb_kits/playbook/pb_table/docs/_table_alignment_shift_data.html.erb +0 -63
  73. data/app/pb_kits/playbook/pb_table/docs/_table_alignment_shift_row.html.erb +0 -52
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 92568f129e159a335286fea16a09cde1f875a7078f29f93a52529df80b721799
4
- data.tar.gz: 45eb715f867daffffb657f0acd08ead48c67a83cb8d99afa543d074ae6f900aa
3
+ metadata.gz: d9c78fc4581891bf1187d4a38fb387d210e9994ccc37993b6f6c2ff10124b895
4
+ data.tar.gz: '03539fc54dbbb2809c7899e1d452b5578159f6725cae9a1638365c88b2b6c29c'
5
5
  SHA512:
6
- metadata.gz: dff4947e668a926470d8582708cba1e3b7bf62f7e35a2321328bfe0fabb6726464cff7534cbbdd3ef80b3aba9c30c62af05d91d95c232e3d3e257ceabdf71f2d
7
- data.tar.gz: 3e43e9a72ff98dbe31bea3481a45eec9471d703b9f07966fcf1d5513d5d43cfa57c7899d3bb2f57b89b63a703ae3ed409b10cccb224b8a4fdcec75af84f6eb06
6
+ metadata.gz: 96950131978879d4e45dbd5e8cd204f7a45a0f57d6d69034ab40732958fa4460bb9464fa99aa54ff8ed51e79d15d988f19653d16f7125a4b477500987969e7dd
7
+ data.tar.gz: 7cffbe91d7528dda2964fd5f10625949a96ffcf71cbda60dcf1f632e8842bdedf5f1f602fd3ebe3deea391be4a6e107b597bded8119729aa06893cb6961f0c92
@@ -1,6 +1,3 @@
1
-
2
-
3
-
4
1
  @import 'pb_advanced_table/advanced_table';
5
2
  @import 'pb_avatar/avatar';
6
3
  @import 'pb_avatar_action_button/avatar_action_button';
@@ -31,6 +28,7 @@
31
28
  @import 'pb_detail/detail';
32
29
  @import 'pb_dialog/dialog';
33
30
  @import 'pb_distribution_bar/distribution_bar';
31
+ @import 'pb_draggable/draggable';
34
32
  @import 'pb_dropdown/dropdown';
35
33
  @import 'pb_file_upload/file_upload';
36
34
  @import 'pb_filter/filter';
@@ -121,3 +119,4 @@
121
119
  @import './utilities/text_align';
122
120
  @import './utilities/overflow';
123
121
  @import './utilities/truncate';
122
+ @import './utilities/vertical_align';
@@ -35,6 +35,8 @@ export { default as DateYearStacked } from './pb_date_year_stacked/_date_year_st
35
35
  export { default as Detail} from './pb_detail/_detail'
36
36
  export { default as Dialog } from './pb_dialog/_dialog'
37
37
  export { default as DistributionBar } from './pb_distribution_bar/_distribution_bar'
38
+ export { default as Draggable} from './pb_draggable/_draggable'
39
+ export { DraggableProvider} from './pb_draggable/context'
38
40
  export { default as Dropdown} from './pb_dropdown/_dropdown'
39
41
  export { default as FileUpload } from './pb_file_upload/_file_upload'
40
42
  export { default as Filter } from './pb_filter/_filter'
@@ -163,6 +163,9 @@ if (Array.isArray(axisTitle) && axisTitle.length > 1 && axisTitle[1].name) {
163
163
  staticOptions.plotOptions.series.events = { legendItemClick: () => false };
164
164
  }
165
165
 
166
+ const filteredProps: any = {...props};
167
+ delete filteredProps.verticalAlign;
168
+
166
169
  const [options, setOptions] = useState({});
167
170
 
168
171
  useEffect(() => {
@@ -172,7 +175,7 @@ if (Array.isArray(axisTitle) && axisTitle.length > 1 && axisTitle[1].name) {
172
175
  return (
173
176
  <HighchartsReact
174
177
  containerProps={{
175
- className: classnames(globalProps(props), className),
178
+ className: classnames(globalProps(filteredProps), className),
176
179
  id: id,
177
180
  ...ariaProps,
178
181
  ...dataProps,
@@ -0,0 +1,31 @@
1
+ import React from 'react';
2
+ import { render, screen } from '../utilities/test-utils';
3
+ import BarGraph from './_bar_graph';
4
+
5
+ beforeEach(() => {
6
+ // Silences error logs within the test suite.
7
+ jest.spyOn(console, 'error');
8
+ jest.spyOn(console, 'warn');
9
+ console.error.mockImplementation(() => {});
10
+ console.warn.mockImplementation(() => {});
11
+ });
12
+
13
+ afterEach(() => {
14
+ console.error.mockRestore();
15
+ console.warn.mockRestore();
16
+ });
17
+
18
+ const testId = 'bargraph1';
19
+
20
+ test('bargraph uses exact classname', () => {
21
+ render(
22
+ <BarGraph
23
+ className='super_important_class'
24
+ data={{ testid: testId }}
25
+ id='bar-default'
26
+ />
27
+ );
28
+
29
+ const kit = screen.getByTestId(testId);
30
+ expect(kit).toHaveClass('super_important_class');
31
+ });
@@ -74,6 +74,22 @@ module Playbook
74
74
  standard_options.deep_merge(custom_options)
75
75
  end
76
76
 
77
+ def vertical_align_props
78
+ if vertical_align
79
+ if object.vertical_align
80
+ original_result = super
81
+ class_to_remove = "vertical_align_#{object.vertical_align}"
82
+
83
+ modified_result = original_result.gsub(class_to_remove, "").strip
84
+ modified_result.empty? ? nil : modified_result
85
+ else
86
+ super
87
+ end
88
+ else
89
+ super
90
+ end
91
+ end
92
+
77
93
  def classname
78
94
  generate_classname("pb_bar_graph")
79
95
  end
@@ -115,6 +115,9 @@ const CircleChart = ({
115
115
  innerSizes[size];
116
116
 
117
117
 
118
+ const filteredProps: any = {...props};
119
+ delete filteredProps.verticalAlign;
120
+
118
121
  const [options, setOptions] = useState({});
119
122
 
120
123
  useEffect(() => {
@@ -181,7 +184,7 @@ const CircleChart = ({
181
184
  <div id={`wrapper-circle-chart-${id}`}>
182
185
  <HighchartsReact
183
186
  containerProps={{
184
- className: classnames("pb_circle_chart", globalProps(props)),
187
+ className: classnames("pb_circle_chart", globalProps(filteredProps)),
185
188
  id: id,
186
189
  ...ariaProps,
187
190
  ...dataProps,
@@ -195,7 +198,7 @@ const CircleChart = ({
195
198
  ) : (
196
199
  <HighchartsReact
197
200
  containerProps={{
198
- className: classnames("pb_circle_chart", globalProps(props)),
201
+ className: classnames("pb_circle_chart", globalProps(filteredProps)),
199
202
  id: id,
200
203
  ...ariaProps,
201
204
  ...dataProps,
@@ -0,0 +1,45 @@
1
+ import React from 'react';
2
+ import { render, screen } from '../utilities/test-utils';
3
+ import CircleChart from './_circle_chart';
4
+
5
+ beforeEach(() => {
6
+ // Silences error logs within the test suite.
7
+ jest.spyOn(console, 'error');
8
+ jest.spyOn(console, 'warn');
9
+ console.error.mockImplementation(() => {});
10
+ console.warn.mockImplementation(() => {});
11
+ });
12
+
13
+ afterEach(() => {
14
+ console.error.mockRestore();
15
+ console.warn.mockRestore();
16
+ });
17
+
18
+ const testId = 'circlechart1';
19
+
20
+ test('uses exact classname', () => {
21
+ const data = [
22
+ {
23
+ name: 'Waiting for Calls',
24
+ value: 41,
25
+ },
26
+ {
27
+ name: 'On Call',
28
+ value: 49,
29
+ },
30
+ {
31
+ name: 'After call',
32
+ value: 10,
33
+ },
34
+ ]
35
+ render(
36
+ <CircleChart
37
+ chartData={data}
38
+ data={{ testid: testId }}
39
+ id='circlechartid'
40
+ />
41
+ );
42
+
43
+ const kit = screen.getByTestId(testId);
44
+ expect(kit).toHaveClass('pb_circle_chart');
45
+ });
@@ -68,6 +68,22 @@ module Playbook
68
68
  }
69
69
  end
70
70
 
71
+ def vertical_align_props
72
+ if vertical_align
73
+ if object.vertical_align
74
+ original_result = super
75
+ class_to_remove = "vertical_align_#{object.vertical_align}"
76
+
77
+ modified_result = original_result.gsub(class_to_remove, "").strip
78
+ modified_result.empty? ? nil : modified_result
79
+ else
80
+ super
81
+ end
82
+ else
83
+ super
84
+ end
85
+ end
86
+
71
87
  def classname
72
88
  generate_classname("pb_circle_chart")
73
89
  end
@@ -0,0 +1,53 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`html structure is correct 1`] = `
4
+ <div>
5
+ <div
6
+ class="pb_collapsible_kit additional_class"
7
+ data-testid="collapsible1"
8
+ >
9
+ <div
10
+ class="pb_collapsible_main_kit cursor_pointer"
11
+ >
12
+ <div>
13
+ <div
14
+ class="pb_flex_kit_orientation_row_justify_content_left_align_items_center_spacing_between"
15
+ >
16
+ <div
17
+ class="pb_flex_item_kit"
18
+ >
19
+ <div>
20
+ Main Section
21
+ </div>
22
+ </div>
23
+ <div
24
+ class="pb_flex_item_kit"
25
+ >
26
+ <div
27
+ class="icon_wrapper"
28
+ style="vertical-align: middle; color: rgb(193, 205, 214);"
29
+ >
30
+ <i
31
+ class="pb_icon_kit far fa-fw fa-lg fa-chevron-down"
32
+ />
33
+ <span
34
+ aria-label="chevron-down icon"
35
+ hidden=""
36
+ />
37
+ </div>
38
+ </div>
39
+ </div>
40
+ </div>
41
+ </div>
42
+ <div
43
+ class="pb_collapsible_content_kit toggle-content"
44
+ data-collapsible-content="true"
45
+ style="height: 0px;"
46
+ >
47
+ <div>
48
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. In vel erat sed purus hendrerit viverra. Duis et vestibulum metus. Sed consequat ut ante non vehicula. Etiam nunc massa, pharetra vel quam id, posuere rhoncus quam. Quisque imperdiet arcu enim, nec aliquet justo auctor eget. Curabitur in metus nec nunc rhoncus faucibus vitae ac elit. Nulla facilisi. Vestibulum quis pretium nulla. Nulla ut accumsan velit. Duis varius urna sed sem tempor, sit amet fermentum nibh auctor. Praesent lorem arcu, egestas non ante quis, placerat pellentesque lectus.Vestibulum lacinia ipsum quis venenatis tristique. Vivamus suscipit, libero eu fringilla egestas, orci urna commodo arcu, vel gravida turpis ipsum molestie nibh. Donec cursus eu ante sagittis ultrices. Phasellus id sagittis risus. Mauris dapibus neque faucibus, tempor ligula vel, cursus ante. Donec faucibus gravida porta. Nullam egestas est quis aliquam feugiat. Sed eget metus diam. Cras eget placerat libero.
49
+ </div>
50
+ </div>
51
+ </div>
52
+ </div>
53
+ `;
@@ -1,4 +1,4 @@
1
- import React, { useEffect } from 'react'
1
+ import React, { useEffect, ReactElement } from 'react'
2
2
  import classnames from 'classnames'
3
3
  import useCollapsible from './useCollapsible'
4
4
 
@@ -11,9 +11,16 @@ import CollapsibleContext from './context'
11
11
  import { IconSizes } from "../pb_icon/_icon"
12
12
  import CollapsibleIcon from './child_kits/CollapsibleIcon'
13
13
 
14
+ type CollapsibleMainProps = {
15
+ children: React.ReactNode
16
+ }
17
+
18
+ type CollapsibleContentProps = {
19
+ children: React.ReactNode
20
+ }
14
21
 
15
22
  type CollapsibleProps = {
16
- children?: React.ReactElement | [] | any,
23
+ children?: [ReactElement<CollapsibleMainProps>, ReactElement<CollapsibleContentProps>],
17
24
  aria?: {[key: string]: string},
18
25
  className?: string,
19
26
  collapsed?: boolean,
@@ -30,7 +37,7 @@ type CollapsibleProps = {
30
37
  const Collapsible = ({
31
38
  aria = {},
32
39
  className,
33
- children = [],
40
+ children,
34
41
  collapsed = true,
35
42
  data = {},
36
43
  htmlOptions = {},
@@ -48,13 +55,12 @@ const Collapsible = ({
48
55
  setIsCollapsed(collapsed)
49
56
  },[collapsed])
50
57
 
51
- const CollapsibleParent = React.Children.toArray(children) as React.ReactElement[]
52
-
53
- if (CollapsibleParent.length !== 2) {
58
+ if (children.length !== 2) {
54
59
  throw new Error('Collapsible requires <CollapsibleMain> and <CollapsibleContent> to function properly.')
55
60
  }
56
- const FirstChild = CollapsibleParent[0]
57
- const SecondChild = CollapsibleParent[1]
61
+
62
+ const FirstChild = children[0]
63
+ const SecondChild = children[1]
58
64
 
59
65
  const Main = FirstChild.type === CollapsibleMain ? FirstChild : null
60
66
  const Content = SecondChild.type === CollapsibleContent ? SecondChild : null
@@ -48,3 +48,27 @@ test('returns namespaced additional_class class name', () => {
48
48
  const kit = screen.getByTestId(testId)
49
49
  expect(kit).toHaveClass(`${kitClass} additional_class`)
50
50
  })
51
+
52
+ test('html structure is correct', () => {
53
+ const { container } = render(
54
+ <Collapsible
55
+ className="additional_class"
56
+ data={{ testid: testId }}
57
+ iconColor='lighter'
58
+ iconSize="lg"
59
+ >
60
+ <Collapsible.Main>
61
+ <div>{'Main Section'}</div>
62
+ </Collapsible.Main>
63
+ <Collapsible.Content>
64
+ <div>
65
+ {
66
+ 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. In vel erat sed purus hendrerit viverra. Duis et vestibulum metus. Sed consequat ut ante non vehicula. Etiam nunc massa, pharetra vel quam id, posuere rhoncus quam. Quisque imperdiet arcu enim, nec aliquet justo auctor eget. Curabitur in metus nec nunc rhoncus faucibus vitae ac elit. Nulla facilisi. Vestibulum quis pretium nulla. Nulla ut accumsan velit. Duis varius urna sed sem tempor, sit amet fermentum nibh auctor. Praesent lorem arcu, egestas non ante quis, placerat pellentesque lectus.Vestibulum lacinia ipsum quis venenatis tristique. Vivamus suscipit, libero eu fringilla egestas, orci urna commodo arcu, vel gravida turpis ipsum molestie nibh. Donec cursus eu ante sagittis ultrices. Phasellus id sagittis risus. Mauris dapibus neque faucibus, tempor ligula vel, cursus ante. Donec faucibus gravida porta. Nullam egestas est quis aliquam feugiat. Sed eget metus diam. Cras eget placerat libero.'
67
+ }
68
+ </div>
69
+ </Collapsible.Content>
70
+ </Collapsible>
71
+ )
72
+
73
+ expect(container).toMatchSnapshot()
74
+ })
@@ -3,6 +3,12 @@ import typography from '../tokens/exports/_typography.scss'
3
3
 
4
4
  import { ThemeProps } from './themeTypes'
5
5
 
6
+ interface CustomTreemapOptions extends Highcharts.SeriesTreemapOptions {
7
+ traverseUpButton?: {
8
+ position: { y: number };
9
+ };
10
+ }
11
+
6
12
  const highchartsDarkTheme: ThemeProps = {
7
13
  lang: {
8
14
  thousandsSep: ',',
@@ -200,7 +206,7 @@ const highchartsDarkTheme: ThemeProps = {
200
206
  traverseUpButton: {
201
207
  position: { y: -50 },
202
208
  },
203
- },
209
+ } as CustomTreemapOptions,
204
210
  },
205
211
  credits: {
206
212
  enabled: false
@@ -3,6 +3,13 @@ import typography from '../tokens/exports/_typography.scss'
3
3
 
4
4
  import { ThemeProps } from './themeTypes'
5
5
 
6
+ interface CustomTreemapOptions extends Highcharts.SeriesTreemapOptions {
7
+ traverseUpButton?: {
8
+ position: { y: number };
9
+ };
10
+ }
11
+
12
+
6
13
  const highchartsTheme: ThemeProps = {
7
14
  lang: {
8
15
  thousandsSep: ',',
@@ -150,6 +157,7 @@ const highchartsTheme: ThemeProps = {
150
157
  fontSize: typography.text_smaller,
151
158
  color: colors.text_lt_light,
152
159
  fontWeight: typography.regular,
160
+ textOutline: '2px $white',
153
161
  },
154
162
  },
155
163
  },
@@ -198,7 +206,7 @@ const highchartsTheme: ThemeProps = {
198
206
  traverseUpButton: {
199
207
  position: { y: -50 },
200
208
  },
201
- },
209
+ } as CustomTreemapOptions,
202
210
  },
203
211
  credits: {
204
212
  enabled: false
@@ -0,0 +1,10 @@
1
+ @import "../tokens/colors";
2
+
3
+ .pb_draggable {
4
+ .is_dragging {
5
+ opacity: 40%;
6
+ }
7
+ .active {
8
+ opacity: 60%;
9
+ }
10
+ }
@@ -0,0 +1,53 @@
1
+ import React from "react";
2
+ import classnames from "classnames";
3
+ import { buildAriaProps, buildCss, buildDataProps, buildHtmlProps } from "../utilities/props";
4
+ import { globalProps } from "../utilities/globalProps";
5
+ import DraggableContainer from "./subcomponents/DraggableContainer";
6
+ import DraggableItem from "./subcomponents/DraggableItem";
7
+
8
+ type DraggableProps = {
9
+ aria?: { [key: string]: string };
10
+ className?: string;
11
+ children?: React.ReactNode;
12
+ data?: { [key: string]: string };
13
+ htmlOptions?: {[key: string]: string | number | boolean | (() => void)},
14
+ id?: string;
15
+ };
16
+
17
+ const Draggable = (props: DraggableProps) => {
18
+ const {
19
+ aria = {},
20
+ className,
21
+ children,
22
+ data = {},
23
+ htmlOptions = {},
24
+ id,
25
+ } = props;
26
+
27
+
28
+ const ariaProps = buildAriaProps(aria);
29
+ const dataProps = buildDataProps(data);
30
+ const htmlProps = buildHtmlProps(htmlOptions);
31
+
32
+ const classes = classnames(
33
+ buildCss("pb_draggable"),
34
+ globalProps(props),
35
+ className
36
+ );
37
+
38
+ return (
39
+ <div {...ariaProps}
40
+ {...dataProps}
41
+ {...htmlProps}
42
+ className={classes}
43
+ id={id}
44
+ >
45
+ {children}
46
+ </div>
47
+ );
48
+ };
49
+
50
+ Draggable.Container = DraggableContainer;
51
+ Draggable.Item = DraggableItem;
52
+
53
+ export default Draggable;
@@ -0,0 +1,92 @@
1
+ import React, { createContext, useState, useContext, useEffect } from "react";
2
+
3
+ const DragContext = createContext<any>({});
4
+
5
+ export const DraggableContext = () => {
6
+ return useContext(DragContext);
7
+ };
8
+
9
+ export const DraggableProvider = ({ children, initialItems, onChange }: any) => {
10
+ const [items, setItems] = useState([]);
11
+ const [dragData, setDragData] = useState<{ [key: string]: any }>({});
12
+ const [isDragging, setIsDragging] = useState("");
13
+ const [activeContainer, setActiveContainer] = useState("");
14
+
15
+ useEffect(() => {
16
+ setItems(initialItems);
17
+ }, [initialItems]);
18
+
19
+ useEffect(() => {
20
+ onChange(items);
21
+ }, [items]);
22
+
23
+ const handleDragStart = (id: string, container: string) => {
24
+ setDragData({ id: id, initialGroup: container });
25
+ setIsDragging(id);
26
+ };
27
+
28
+ const handleDragEnter = (id: string, container: string) => {
29
+ if (dragData?.id !== id) {
30
+ const newItems = [...items];
31
+ const draggedItem = newItems.find((item) => item.id === dragData.id);
32
+ const draggedIndex = newItems.indexOf(draggedItem);
33
+ const targetIndex = newItems.findIndex((item) => item.id === id);
34
+
35
+ newItems.splice(draggedIndex, 1);
36
+ newItems.splice(targetIndex, 0, draggedItem);
37
+
38
+ setItems(newItems);
39
+ setDragData({ id: dragData.id, initialGroup: container });
40
+ }
41
+ };
42
+
43
+ const handleDragEnd = () => {
44
+ setIsDragging("");
45
+ setActiveContainer("");
46
+ };
47
+
48
+ const changeCategory = (itemId: string, container: string) => {
49
+ const updatedItems = items.map((item) => {
50
+ if (item.id === itemId) {
51
+ return { ...item, container: container };
52
+ }
53
+ return item;
54
+ });
55
+
56
+ setItems(updatedItems);
57
+ };
58
+
59
+ const handleDrop = (container: string) => {
60
+ setIsDragging("");
61
+ setActiveContainer("");
62
+ const selected = dragData.id;
63
+ changeCategory(selected, container);
64
+ };
65
+
66
+ const handleDragOver = (e: Event, container: string) => {
67
+ e.preventDefault();
68
+ setActiveContainer(container);
69
+ };
70
+
71
+
72
+
73
+ const contextValue = {
74
+ items,
75
+ setItems,
76
+ dragData,
77
+ setDragData,
78
+ isDragging,
79
+ setIsDragging,
80
+ activeContainer,
81
+ setActiveContainer,
82
+ handleDragStart,
83
+ handleDragEnter,
84
+ handleDragEnd,
85
+ handleDrop,
86
+ handleDragOver,
87
+ };
88
+
89
+ return (
90
+ <DragContext.Provider value={contextValue}>{children}</DragContext.Provider>
91
+ );
92
+ };
@@ -0,0 +1,53 @@
1
+ import React, { useState } from "react";
2
+ import { SelectableList, Draggable, DraggableProvider } from "../../";
3
+
4
+ // Initial items to be dragged
5
+ const data = [
6
+ {
7
+ id: "1",
8
+ text: "Task 1",
9
+ },
10
+ {
11
+ id: "2",
12
+ text: "Task 2",
13
+ },
14
+ {
15
+ id: "3",
16
+ text: "Task 3",
17
+ },
18
+ {
19
+ id: "4",
20
+ text: "Task 4",
21
+ },
22
+ ];
23
+
24
+ const DraggableDefault = (props) => {
25
+ const [initialState, setInitialState] = useState(data);
26
+
27
+ return (
28
+ <DraggableProvider initialItems={data}
29
+ onChange={(items) => setInitialState(items)}
30
+ >
31
+ <Draggable
32
+ {...props}
33
+ >
34
+ <Draggable.Container>
35
+ <SelectableList variant="checkbox">
36
+ {initialState.map(({ id, text }) => (
37
+ <Draggable.Item id={id}
38
+ key={id}
39
+ >
40
+ <SelectableList.Item label={text}
41
+ name={id}
42
+ value={id}
43
+ />
44
+ </Draggable.Item>
45
+ ))}
46
+ </SelectableList>
47
+ </Draggable.Container>
48
+ </Draggable>
49
+ </DraggableProvider>
50
+ );
51
+ };
52
+
53
+ export default DraggableDefault;