playbook_ui 15.5.0 → 15.6.0.pre.alpha.draggableask12906

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 (59) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.scss +96 -6
  3. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_table_props.html.erb +1 -1
  4. data/app/pb_kits/playbook/pb_background/_background.tsx +6 -6
  5. data/app/pb_kits/playbook/pb_background/background.test.js +5 -1
  6. data/app/pb_kits/playbook/pb_background/docs/_background_light.html.erb +1 -1
  7. data/app/pb_kits/playbook/pb_background/docs/_background_light.jsx +0 -1
  8. data/app/pb_kits/playbook/pb_background/docs/_background_light.md +1 -0
  9. data/app/pb_kits/playbook/pb_background/docs/example.yml +2 -2
  10. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_compound_components.html.erb +31 -0
  11. data/app/pb_kits/playbook/pb_draggable/context/index.tsx +399 -7
  12. data/app/pb_kits/playbook/pb_draggable/context/types.ts +8 -3
  13. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_multiple_containers_dropzone.jsx +180 -0
  14. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_multiple_containers_dropzone.md +22 -0
  15. data/app/pb_kits/playbook/pb_draggable/docs/example.yml +3 -2
  16. data/app/pb_kits/playbook/pb_draggable/docs/index.js +2 -1
  17. data/app/pb_kits/playbook/pb_draggable/draggable.test.jsx +77 -1
  18. data/app/pb_kits/playbook/pb_file_upload/_file_upload.scss +4 -4
  19. data/app/pb_kits/playbook/pb_home_address_street/_home_address_street.tsx +34 -22
  20. data/app/pb_kits/playbook/pb_home_address_street/city_emphasis.html.erb +16 -12
  21. data/app/pb_kits/playbook/pb_home_address_street/docs/_home_address_street_default.html.erb +1 -1
  22. data/app/pb_kits/playbook/pb_home_address_street/none_emphasis.html.erb +16 -12
  23. data/app/pb_kits/playbook/pb_home_address_street/street_emphasis.html.erb +16 -12
  24. data/app/pb_kits/playbook/pb_multiple_users/_multiple_users.scss +10 -0
  25. data/app/pb_kits/playbook/pb_multiple_users/_multiple_users.tsx +66 -15
  26. data/app/pb_kits/playbook/pb_multiple_users/docs/_multiple_users_with_tooltip.jsx +42 -0
  27. data/app/pb_kits/playbook/pb_multiple_users/docs/_multiple_users_with_tooltip.md +1 -0
  28. data/app/pb_kits/playbook/pb_multiple_users/docs/example.yml +1 -0
  29. data/app/pb_kits/playbook/pb_multiple_users/docs/index.js +1 -0
  30. data/app/pb_kits/playbook/pb_multiple_users/multiple_users.test.js +25 -0
  31. data/app/pb_kits/playbook/pb_phone_number_input/_phone_number_input.tsx +44 -10
  32. data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_validation.html.erb +34 -4
  33. data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_validation.jsx +16 -7
  34. data/app/pb_kits/playbook/pb_radio/docs/_radio_error.md +1 -1
  35. data/app/pb_kits/playbook/pb_select/docs/_select_error.md +1 -1
  36. data/app/pb_kits/playbook/pb_table/styles/_vertical_border.scss +49 -0
  37. data/app/pb_kits/playbook/pb_text_input/docs/_text_input_error.md +1 -1
  38. data/app/pb_kits/playbook/pb_textarea/docs/_textarea_error.md +1 -1
  39. data/app/pb_kits/playbook/pb_typeahead/_typeahead.test.jsx +15 -0
  40. data/app/pb_kits/playbook/pb_typeahead/_typeahead.tsx +3 -0
  41. data/app/pb_kits/playbook/pb_typeahead/components/ClearIndicator.tsx +13 -2
  42. data/app/pb_kits/playbook/pb_typeahead/components/MultiValue.tsx +6 -1
  43. data/app/pb_kits/playbook/pb_typeahead/components/ValueContainer.tsx +34 -7
  44. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_input_display.html.erb +30 -0
  45. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_input_display.jsx +37 -0
  46. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_input_display.md +3 -0
  47. data/app/pb_kits/playbook/pb_typeahead/docs/example.yml +2 -0
  48. data/app/pb_kits/playbook/pb_typeahead/docs/index.js +2 -1
  49. data/app/pb_kits/playbook/pb_typeahead/typeahead.rb +6 -1
  50. data/dist/chunks/_typeahead-wpGumTwA.js +6 -0
  51. data/dist/chunks/{lib-Dk4GKPut.js → lib-CgpqUb6l.js} +2 -2
  52. data/dist/chunks/vendor.js +2 -2
  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/version.rb +2 -2
  57. metadata +12 -5
  58. data/app/pb_kits/playbook/pb_bar_graph/BarGraphStyles.scss +0 -58
  59. data/dist/chunks/_typeahead-Bx4QsIEU.js +0 -6
@@ -0,0 +1,22 @@
1
+ The multiple container functionality also supports customized dropzone styling as shown here.
2
+
3
+ In addition to this, the `enableCrossContainerPreview` prop can be used on the `DraggableProvider` as shown here to enable dropzone preview for cross-container dragging.
4
+
5
+ With `enableCrossContainerPreview`, the `onDrop` and `onDragEnd` event listeners will also provide several arguments to allow developers more context from the drag event.
6
+
7
+ The `onDrop` callback is triggered when an item is successfully dropped into a container. It provides the following arguments:
8
+
9
+ - `draggedItemId` - The ID of the item that was dragged
10
+ - `droppedContainer` - The container where the item was dropped
11
+ - `originalContainer` - The container where the drag started
12
+ - `item` - The complete item object with all properties (including the updated container)
13
+ - `itemAbove` - The item directly above the dropped item in the final position (null if at the top)
14
+ - `itemBelow` - The item directly below the dropped item in the final position (null if at the bottom)
15
+
16
+ The `onDragEnd` callback is triggered when a drag operation ends, whether it was dropped or cancelled. It provides the following arguments:
17
+
18
+ - `draggedItemId` - The ID of the item that was dragged
19
+ - `finalContainer` - The container where the item ended up (could be same as original if drag was cancelled)
20
+ - `originalContainer` - The container where the drag started
21
+ - `itemAbove` - The item directly above the dragged item in the final position (null if at the top)
22
+ - `itemBelow` - The item directly below the dragged item in the final position (null if at the bottom)
@@ -5,11 +5,12 @@ examples:
5
5
  - draggable_with_selectable_list: Draggable with SelectableList Kit
6
6
  - draggable_with_cards: Draggable with Cards
7
7
  - draggable_with_table: Draggable with Table
8
- - draggable_multiple_containers: Dragging Across Multiple Containers
9
8
  - draggable_drop_zones: Draggable Drop Zones
10
9
  - draggable_drop_zones_colors: Draggable Drop Zones Colors
11
10
  - draggable_drop_zones_line: Draggable Drop Zones Line
12
11
  - draggable_event_listeners: Draggable Event Listeners
12
+ - draggable_multiple_containers: Dragging Across Multiple Containers
13
+ - draggable_multiple_containers_dropzone: Dragging Across Multiple Containers with Dropzones
13
14
 
14
15
  rails:
15
16
  - draggable_default: Default
@@ -17,8 +18,8 @@ examples:
17
18
  - draggable_with_selectable_list: Draggable with SelectableList Kit
18
19
  - draggable_with_cards: Draggable with Cards
19
20
  - draggable_with_table: Draggable with Table
20
- - draggable_multiple_containers: Dragging Across Multiple Containers
21
21
  - draggable_drop_zones: Draggable Drop Zones
22
22
  - draggable_drop_zones_colors: Draggable Drop Zones Colors
23
23
  - draggable_drop_zones_line: Draggable Drop Zones Line
24
24
  - draggable_event_listeners: Draggable Event Listeners
25
+ - draggable_multiple_containers: Dragging Across Multiple Containers
@@ -7,4 +7,5 @@ export { default as DraggableWithTable } from './_draggable_with_table.jsx'
7
7
  export { default as DraggableDropZones } from './_draggable_drop_zones.jsx'
8
8
  export { default as DraggableDropZonesColors } from './_draggable_drop_zones_colors.jsx'
9
9
  export { default as DraggableDropZonesLine } from './_draggable_drop_zones_line.jsx'
10
- export { default as DraggableEventListeners } from './_draggable_event_listeners.jsx'
10
+ export { default as DraggableEventListeners } from './_draggable_event_listeners.jsx'
11
+ export { default as DraggableMultipleContainersDropzone } from './_draggable_multiple_containers_dropzone.jsx'
@@ -255,4 +255,80 @@ test("line dropZone with horizontal direction applies 'line_horizontal' class to
255
255
  const container = kit.querySelector(".pb_draggable_container");
256
256
 
257
257
  expect(container).toHaveClass("line_horizontal");
258
- });
258
+ });
259
+
260
+ // Cross-container drag tests
261
+ const multiContainerData = [
262
+ { id: "1", container: "To Do", text: "Task 1" },
263
+ { id: "2", container: "To Do", text: "Task 2" },
264
+ { id: "3", container: "In Progress", text: "Task 3" },
265
+ { id: "4", container: "Done", text: "Task 4" },
266
+ ];
267
+
268
+ const containers = ["To Do", "In Progress", "Done"];
269
+
270
+ const DraggableMultipleContainers = () => {
271
+ const [initialState, setInitialState] = useState(multiContainerData);
272
+
273
+ return (
274
+ <div data-testid={testId}>
275
+ <DraggableProvider
276
+ dropZone={{ type: "outline" }}
277
+ initialItems={multiContainerData}
278
+ onReorder={(items) => setInitialState(items)}
279
+ >
280
+ {containers.map((container) => (
281
+ <Draggable.Container
282
+ container={container}
283
+ data={{testid:`container-${container}`}}
284
+ key={container}
285
+ >
286
+ {initialState
287
+ .filter((item) => item.container === container)
288
+ .map(({ id, text }) => (
289
+ <Draggable.Item
290
+ container={container}
291
+ data-testid={`item-${id}`}
292
+ dragId={id}
293
+ key={id}
294
+ >
295
+ {text}
296
+ </Draggable.Item>
297
+ ))}
298
+ </Draggable.Container>
299
+ ))}
300
+ </DraggableProvider>
301
+ </div>
302
+ );
303
+ };
304
+
305
+ test("renders multiple containers with correct items", () => {
306
+ render(<DraggableMultipleContainers />);
307
+
308
+ const kit = screen.getByTestId(testId);
309
+ expect(kit).toBeInTheDocument();
310
+
311
+ containers.forEach((container) => {
312
+ const containerEl = kit.querySelector(`[data-testid="container-${container}"]`);
313
+ expect(containerEl).toBeInTheDocument();
314
+ });
315
+
316
+ // Check items are in correct containers
317
+ expect(screen.getByText("Task 1")).toBeInTheDocument();
318
+ expect(screen.getByText("Task 2")).toBeInTheDocument();
319
+ expect(screen.getByText("Task 3")).toBeInTheDocument();
320
+ expect(screen.getByText("Task 4")).toBeInTheDocument();
321
+ });
322
+
323
+ test("items have correct container association", () => {
324
+ const { container } = render(<DraggableMultipleContainers />);
325
+
326
+ // items rendered within their respective containers
327
+ const todoContainer = container.querySelector('[data-testid="container-To Do"]');
328
+ const inProgressContainer = container.querySelector('[data-testid="container-In Progress"]');
329
+ const doneContainer = container.querySelector('[data-testid="container-Done"]');
330
+
331
+ expect(todoContainer.querySelectorAll('.pb_draggable_item')).toHaveLength(2);
332
+ expect(inProgressContainer.querySelectorAll('.pb_draggable_item')).toHaveLength(1);
333
+ expect(doneContainer.querySelectorAll('.pb_draggable_item')).toHaveLength(1);
334
+ })
@@ -1,5 +1,5 @@
1
1
  .pb_file_upload_kit {
2
- .pb_card_kit_deselected_border_radius_md {
2
+ .pb_card_kit {
3
3
  border: 1px #ccc dashed;
4
4
  text-align: center;
5
5
  }
@@ -11,7 +11,7 @@
11
11
  }
12
12
  &.error,
13
13
  &.pb_file_upload_kit_error {
14
- .pb_card_kit_deselected_border_radius_md {
14
+ .pb_card_kit {
15
15
  border-color: $error;
16
16
  }
17
17
  .pb_body_kit_negative {
@@ -30,12 +30,12 @@
30
30
  }
31
31
 
32
32
  .dark .pb_file_upload_kit {
33
- .pb_card_kit_deselected_border_radius_md {
33
+ .pb_card_kit {
34
34
  border: 1px $text_dk_lighter dashed;
35
35
  }
36
36
  &.error,
37
37
  &.pb_file_upload_kit_error {
38
- .pb_card_kit_deselected_border_radius_md {
38
+ .pb_card_kit {
39
39
  border-color: $error_dark;
40
40
  }
41
41
  }
@@ -96,20 +96,24 @@ const HomeAddressStreet = (props: HomeAddressStreetProps): React.ReactElement =>
96
96
  {hasAllEmptyProps && '—'}
97
97
  {emphasis == 'street' && !hasAllEmptyProps &&
98
98
  <div>
99
- <Title
100
- className="pb_home_address_street_address"
101
- dark={dark}
102
- size={4}
103
- >
104
- {joinPresent([formatStreetAdr(address), houseStyle], ' · ')}
105
- </Title>
106
- <Title
107
- className="pb_home_address_street_address"
108
- dark={dark}
109
- size={4}
110
- >
111
- {titleize(addressCont)}
112
- </Title>
99
+ {(address || houseStyle) && (
100
+ <Title
101
+ className="pb_home_address_street_address"
102
+ dark={dark}
103
+ size={4}
104
+ >
105
+ {joinPresent([formatStreetAdr(address), houseStyle], ' · ')}
106
+ </Title>
107
+ )}
108
+ {addressCont && (
109
+ <Title
110
+ className="pb_home_address_street_address"
111
+ dark={dark}
112
+ size={4}
113
+ >
114
+ {titleize(addressCont)}
115
+ </Title>
116
+ )}
113
117
  <Body color="light">
114
118
  {`${city ? `${titleize(city)}, ` : ''}${uppercaseState}${zipcode ? ` ${zipcode}` : ''}`}
115
119
  </Body>
@@ -117,10 +121,14 @@ const HomeAddressStreet = (props: HomeAddressStreetProps): React.ReactElement =>
117
121
  }
118
122
  {emphasis == 'city' && !hasAllEmptyProps &&
119
123
  <div>
120
- <Body color="light">
121
- {joinPresent([formatStreetAdr(address), houseStyle], ' · ')}
122
- </Body>
123
- <Body color="light">{titleize(addressCont)}</Body>
124
+ {(address || houseStyle) && (
125
+ <Body color="light">
126
+ {joinPresent([formatStreetAdr(address), houseStyle], ' · ')}
127
+ </Body>
128
+ )}
129
+ {addressCont && (
130
+ <Body color="light">{titleize(addressCont)}</Body>
131
+ )}
124
132
  <div>
125
133
  <Title
126
134
  className="pb_home_address_street_address"
@@ -141,10 +149,14 @@ const HomeAddressStreet = (props: HomeAddressStreetProps): React.ReactElement =>
141
149
  }
142
150
  {emphasis == 'none' && !hasAllEmptyProps &&
143
151
  <div>
144
- <Body dark={dark}>
145
- {joinPresent([formatStreetAdr(address), houseStyle], ' · ')}
146
- </Body>
147
- <Body dark={dark}>{formatStreetAdr(addressCont)}</Body>
152
+ {(address || houseStyle) && (
153
+ <Body dark={dark}>
154
+ {joinPresent([formatStreetAdr(address), houseStyle], ' · ')}
155
+ </Body>
156
+ )}
157
+ {addressCont && (
158
+ <Body dark={dark}>{formatStreetAdr(addressCont)}</Body>
159
+ )}
148
160
  <div>
149
161
  <Body
150
162
  color="light"
@@ -1,15 +1,19 @@
1
- <%= pb_rails "body", props: {
2
- classname: "pb_home_address_street_address",
3
- color: "light",
4
- text: object.address_house_style,
5
- dark: object.dark
6
- } %>
7
- <%= pb_rails "body", props: {
8
- classname: "pb_home_address_street_address",
9
- color: "light",
10
- text: object.address_house_style2,
11
- dark: object.dark
12
- } %>
1
+ <% if object.address_house_style.present? %>
2
+ <%= pb_rails "body", props: {
3
+ classname: "pb_home_address_street_address",
4
+ color: "light",
5
+ text: object.address_house_style,
6
+ dark: object.dark
7
+ } %>
8
+ <% end %>
9
+ <% if object.address_house_style2.present? %>
10
+ <%= pb_rails "body", props: {
11
+ classname: "pb_home_address_street_address",
12
+ color: "light",
13
+ text: object.address_house_style2,
14
+ dark: object.dark
15
+ } %>
16
+ <% end %>
13
17
  <div>
14
18
  <%= pb_rails "title", props: {
15
19
  tag: "span",
@@ -8,4 +8,4 @@
8
8
  state: "PA",
9
9
  zipcode: "19382",
10
10
  territory: "PHL",
11
- }) %>
11
+ }) %>
@@ -1,15 +1,19 @@
1
- <%= pb_rails "body", props: {
2
- classname: "pb_home_address_street_address",
3
- size: 4,
4
- text: object.address_house_style,
5
- dark: object.dark
6
- } %>
7
- <%= pb_rails "body", props: {
8
- classname: "pb_home_address_street_address",
9
- size: 4,
10
- text: object.address_house_style2,
11
- dark: object.dark
12
- } %>
1
+ <% if object.address_house_style.present? %>
2
+ <%= pb_rails "body", props: {
3
+ classname: "pb_home_address_street_address",
4
+ size: 4,
5
+ text: object.address_house_style,
6
+ dark: object.dark
7
+ } %>
8
+ <% end %>
9
+ <% if object.address_house_style2.present? %>
10
+ <%= pb_rails "body", props: {
11
+ classname: "pb_home_address_street_address",
12
+ size: 4,
13
+ text: object.address_house_style2,
14
+ dark: object.dark
15
+ } %>
16
+ <% end %>
13
17
  <%= pb_rails "body", props: {
14
18
  color: "light",
15
19
  text: object.city_state_zip,
@@ -1,15 +1,19 @@
1
- <%= pb_rails "title", props: {
2
- classname: "pb_home_address_street_address",
3
- size: 4,
4
- text: object.address_house_style,
5
- dark: object.dark
6
- } %>
7
- <%= pb_rails "title", props: {
8
- classname: "pb_home_address_street_address",
9
- size: 4,
10
- text: object.address_house_style2,
11
- dark: object.dark
12
- } %>
1
+ <% if object.address_house_style.present? %>
2
+ <%= pb_rails "title", props: {
3
+ classname: "pb_home_address_street_address",
4
+ size: 4,
5
+ text: object.address_house_style,
6
+ dark: object.dark
7
+ } %>
8
+ <% end %>
9
+ <% if object.address_house_style2.present? %>
10
+ <%= pb_rails "title", props: {
11
+ classname: "pb_home_address_street_address",
12
+ size: 4,
13
+ text: object.address_house_style2,
14
+ dark: object.dark
15
+ } %>
16
+ <% end %>
13
17
  <%= pb_rails "body", props: {
14
18
  color: "light",
15
19
  text: object.city_state_zip,
@@ -36,6 +36,16 @@ $pb_multiple_users_size_xxs: map-get($avatar-sizes, "xxs");
36
36
  height: $pb_multiple_users_size_xxs;
37
37
  }
38
38
 
39
+
40
+ .user_tooltip {
41
+ margin-left: $pb_multiple_users_overlap !important;
42
+ }
43
+
44
+ .user_count_tooltip {
45
+ margin-left: $pb_multiple_users_overlap !important;
46
+ position: relative;
47
+ }
48
+
39
49
  .pb_multiple_users_item {
40
50
  margin-left: $pb_multiple_users_overlap;
41
51
  margin-right: 0;
@@ -5,17 +5,19 @@ import { buildAriaProps, buildCss, buildDataProps, buildHtmlProps } from '../uti
5
5
  import { globalProps } from '../utilities/globalProps'
6
6
 
7
7
  import Avatar from '../pb_avatar/_avatar'
8
+ import Tooltip from '../pb_tooltip/_tooltip'
8
9
 
9
10
  type MultipleUsersProps = {
10
11
  aria?: { [key: string]: string },
11
12
  className?: string,
12
13
  dark?: boolean,
13
14
  data?: { [key: string]: string },
14
- htmlOptions?: {[key: string]: string | number | boolean | (() => void)},
15
+ htmlOptions?: { [key: string]: string | number | boolean | (() => void) },
15
16
  id?: string,
16
17
  maxDisplayedUsers?: number,
17
18
  reverse?: boolean,
18
19
  size?: "md" | "lg" | "sm" | "xl" | "xs" | "xxs",
20
+ withTooltip?: boolean,
19
21
  users: Array<{ [key: string]: string }>,
20
22
  }
21
23
 
@@ -30,6 +32,7 @@ const MultipleUsers = (props: MultipleUsersProps): React.ReactElement => {
30
32
  maxDisplayedUsers = 4,
31
33
  reverse = false,
32
34
  size = 'xs',
35
+ withTooltip = false,
33
36
  users,
34
37
  } = props
35
38
 
@@ -62,22 +65,70 @@ const MultipleUsers = (props: MultipleUsersProps): React.ReactElement => {
62
65
  className={classes}
63
66
  id={id}
64
67
  >
65
- {usersToDisplay.map((avatarData, index) => (
66
- <Avatar
67
- {...avatarData}
68
- className="pb_multiple_users_item"
69
- dark={dark}
70
- imageAlt={avatarData.name}
71
- key={index}
72
- size={size}
73
- />
74
- ))}
68
+ {withTooltip ?
69
+ <>
70
+ {usersToDisplay.map((avatarData, index) => (
71
+ <Tooltip
72
+ key={"user_tooltip_" + index}
73
+ placement='top'
74
+ text={avatarData.tooltip ? avatarData.tooltip : ''}
75
+ zIndex={10}
76
+ >
77
+ <Avatar
78
+ {...avatarData}
79
+ className={"pb_multiple_users_item" + (withTooltip ? " user_tooltip" : "")}
80
+ dark={dark}
81
+ imageAlt={avatarData.name}
82
+ key={index}
83
+ size={size}
84
+ />
85
+ </Tooltip>
86
+ ))}
75
87
 
76
- { users.length > maxDisplayedUsers &&
77
- <div className={itemClasses}>
78
- {`+${users.length - 3}`}
79
- </div>
88
+ {users.length > maxDisplayedUsers &&
89
+ <Tooltip
90
+ placement='top'
91
+ text={
92
+ <div>
93
+ {
94
+ usersToDisplay.length < users.length ?
95
+ users.slice(displayCount).map((u, i) => (
96
+ <div key={i}>{u.tooltip}</div>
97
+ ))
98
+ :
99
+ ''
100
+ }
101
+ </div>
102
+ }
103
+ zIndex={10}
104
+ >
105
+ <div className={itemClasses + (withTooltip ? " user_count_tooltip" : "")}>
106
+ {`+${users.length - displayCount}`}
107
+ </div>
108
+ </Tooltip>
109
+ }
110
+ </>
111
+ :
112
+ <>
113
+ {usersToDisplay.map((avatarData, index) => (
114
+ <Avatar
115
+ {...avatarData}
116
+ className="pb_multiple_users_item"
117
+ dark={dark}
118
+ imageAlt={avatarData.name}
119
+ key={index}
120
+ size={size}
121
+ />
122
+ ))}
123
+
124
+ {users.length > maxDisplayedUsers &&
125
+ <div className={itemClasses}>
126
+ {`+${users.length - 3}`}
127
+ </div>
128
+ }
129
+ </>
80
130
  }
131
+
81
132
  </div>
82
133
  )
83
134
  }
@@ -0,0 +1,42 @@
1
+ import React from 'react'
2
+ import MultipleUsers from '../../pb_multiple_users/_multiple_users'
3
+
4
+ const MultipleUsersWithTooltip = (props) => {
5
+ return (
6
+ <div>
7
+ <MultipleUsers
8
+ users={[
9
+ {
10
+ name: 'Patrick Welch',
11
+ imageUrl: 'https://randomuser.me/api/portraits/men/9.jpg',
12
+ tooltip: "Patrick Welch - Online"
13
+ },
14
+ {
15
+ name: 'Lucille Sanchez',
16
+ imageUrl: 'https://randomuser.me/api/portraits/women/6.jpg',
17
+ tooltip: "Lucille Sanchez - Offline"
18
+ },
19
+ {
20
+ name: 'Beverly Reyes',
21
+ imageUrl: 'https://randomuser.me/api/portraits/women/74.jpg',
22
+ tooltip: "Beverly Reyes - Online"
23
+ },
24
+ {
25
+ name: 'Keith Craig',
26
+ imageUrl: 'https://randomuser.me/api/portraits/men/40.jpg',
27
+ tooltip: "Keith Craig - Away"
28
+ },
29
+ {
30
+ name: 'Alicia Cooper',
31
+ imageUrl: 'https://randomuser.me/api/portraits/women/46.jpg',
32
+ tooltip: "Alicia Cooper - Busy"
33
+ },
34
+ ]}
35
+ withTooltip
36
+ {...props}
37
+ />
38
+ </div>
39
+ )
40
+ }
41
+ ``
42
+ export default MultipleUsersWithTooltip
@@ -0,0 +1 @@
1
+ Use the `withTooltip` boolean prop to enable setting user-specific tooltip content via the `tooltip` property in the users array.
@@ -10,6 +10,7 @@ examples:
10
10
  - multiple_users_default: Default
11
11
  - multiple_users_reverse: Reverse
12
12
  - multiple_users_size: Size
13
+ - multiple_users_with_tooltip: With Tooltip
13
14
 
14
15
  swift:
15
16
  - multiple_users_default_swift: Default
@@ -1,3 +1,4 @@
1
1
  export { default as MultipleUsersDefault } from './_multiple_users_default.jsx'
2
2
  export { default as MultipleUsersReverse } from './_multiple_users_reverse.jsx'
3
3
  export { default as MultipleUsersSize } from './_multiple_users_size.jsx'
4
+ export { default as MultipleUsersWithTooltip } from './_multiple_users_with_tooltip.jsx'
@@ -49,4 +49,29 @@ test('should render aria-label', () => {
49
49
 
50
50
  const kit = screen.getByTestId(testId)
51
51
  expect(kit).toHaveAttribute('aria-label', testId)
52
+ })
53
+
54
+ test('should render withTooltip prop', () => {
55
+ render(
56
+ <MultipleUsers
57
+ data={{ testid: testId }}
58
+ users={[
59
+ {
60
+ name: 'Patrick Welch',
61
+ imageUrl: 'https://randomuser.me/api/portraits/men/9.jpg',
62
+ tooltip: "Patrick Welch - Online"
63
+ },
64
+ {
65
+ name: 'Lucille Sanchez',
66
+ imageUrl: 'https://randomuser.me/api/portraits/women/6.jpg',
67
+ tooltip: "Lucille Sanchez - Offline"
68
+ },
69
+ ]}
70
+ withTooltip
71
+ />
72
+ )
73
+
74
+ const kit = screen.getByTestId(testId)
75
+ const childWithTooltip = kit.querySelector('.pb_tooltip_kit')
76
+ expect(childWithTooltip).not.toBeNull()
52
77
  })