playbook_ui 18.3.0.pre.rc.1 → 18.3.0.pre.rc.2

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 (116) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/pb_advanced_table/table_header.rb +1 -1
  3. data/app/pb_kits/playbook/pb_avatar/_avatar.tsx +3 -1
  4. data/app/pb_kits/playbook/pb_avatar/kit.schema.json +1 -0
  5. data/app/pb_kits/playbook/pb_contact/_contact.tsx +4 -1
  6. data/app/pb_kits/playbook/pb_contact/kit.schema.json +1 -0
  7. data/app/pb_kits/playbook/pb_date/_date.tsx +3 -1
  8. data/app/pb_kits/playbook/pb_date/kit.schema.json +1 -0
  9. data/app/pb_kits/playbook/pb_date_range_inline/_date_range_inline.tsx +3 -1
  10. data/app/pb_kits/playbook/pb_date_range_inline/kit.schema.json +1 -0
  11. data/app/pb_kits/playbook/pb_date_range_stacked/_date_range_stacked.tsx +3 -1
  12. data/app/pb_kits/playbook/pb_date_range_stacked/kit.schema.json +1 -0
  13. data/app/pb_kits/playbook/pb_date_stacked/_date_stacked.tsx +4 -1
  14. data/app/pb_kits/playbook/pb_date_stacked/kit.schema.json +1 -0
  15. data/app/pb_kits/playbook/pb_date_time/_date_time.tsx +3 -1
  16. data/app/pb_kits/playbook/pb_date_time/kit.schema.json +1 -0
  17. data/app/pb_kits/playbook/pb_date_time_stacked/_date_time_stacked.tsx +2 -1
  18. data/app/pb_kits/playbook/pb_date_time_stacked/kit.schema.json +1 -0
  19. data/app/pb_kits/playbook/pb_date_year_stacked/_date_year_stacked.tsx +3 -1
  20. data/app/pb_kits/playbook/pb_date_year_stacked/kit.schema.json +1 -0
  21. data/app/pb_kits/playbook/pb_draggable/utilities/touchDrag.ts +10 -0
  22. data/app/pb_kits/playbook/pb_dropdown/_dropdown.scss +112 -0
  23. data/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx +11 -0
  24. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_draggable_pills.html.erb +51 -0
  25. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_draggable_pills.jsx +62 -0
  26. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_draggable_pills_rails.md +9 -0
  27. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_draggable_pills_react.md +9 -0
  28. data/app/pb_kits/playbook/pb_dropdown/docs/_playground.json +16 -1
  29. data/app/pb_kits/playbook/pb_dropdown/docs/_playground.overrides.json +7 -1
  30. data/app/pb_kits/playbook/pb_dropdown/docs/example.yml +2 -0
  31. data/app/pb_kits/playbook/pb_dropdown/docs/index.js +1 -0
  32. data/app/pb_kits/playbook/pb_dropdown/dropdown.rb +10 -1
  33. data/app/pb_kits/playbook/pb_dropdown/dropdown.test.jsx +194 -0
  34. data/app/pb_kits/playbook/pb_dropdown/dropdown_index.test.js +254 -0
  35. data/app/pb_kits/playbook/pb_dropdown/index.js +166 -7
  36. data/app/pb_kits/playbook/pb_dropdown/kit.schema.json +24 -0
  37. data/app/pb_kits/playbook/pb_dropdown/subcomponents/MultiSelectTriggerDisplay.tsx +336 -31
  38. data/app/pb_kits/playbook/pb_dropdown/utilities/pillReorder.js +281 -0
  39. data/app/pb_kits/playbook/pb_dropdown/utilities/usePillDropIndicator.ts +144 -0
  40. data/app/pb_kits/playbook/pb_form/pb_form_validation.js +1 -0
  41. data/app/pb_kits/playbook/pb_form_group/_form_group.scss +1 -4
  42. data/app/pb_kits/playbook/pb_image/_image.tsx +3 -1
  43. data/app/pb_kits/playbook/pb_image/kit.schema.json +1 -0
  44. data/app/pb_kits/playbook/pb_list/_list_item.tsx +6 -3
  45. data/app/pb_kits/playbook/pb_map/docs/_map_default.md +22 -3
  46. data/app/pb_kits/playbook/pb_person/_person.tsx +3 -1
  47. data/app/pb_kits/playbook/pb_person/kit.schema.json +1 -0
  48. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_playground.json +1 -1
  49. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_playground.overrides.json +1 -1
  50. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_rails_default.md +3 -4
  51. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_rails_extensions.md +1 -1
  52. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_rails_markdown_support.md +1 -1
  53. data/app/pb_kits/playbook/pb_rich_text_editor/rich_text_editor.html.erb +0 -6
  54. data/app/pb_kits/playbook/pb_rich_text_editor/rich_text_editor_rails.js +26 -21
  55. data/app/pb_kits/playbook/pb_rich_text_editor/rich_text_editor_rails.test.js +85 -1
  56. data/app/pb_kits/playbook/pb_selectable_card_icon/_selectable_card_icon.scss +0 -9
  57. data/app/pb_kits/playbook/pb_selectable_card_icon/docs/_selectable_card_icon_custom.jsx +1 -1
  58. data/app/pb_kits/playbook/pb_selectable_icon/_selectable_icon.scss +0 -7
  59. data/app/pb_kits/playbook/pb_source/source.rb +1 -1
  60. data/app/pb_kits/playbook/pb_time_range_inline/_time_range_inline.tsx +3 -1
  61. data/app/pb_kits/playbook/pb_time_range_inline/kit.schema.json +1 -0
  62. data/app/pb_kits/playbook/pb_time_stacked/_time_stacked.tsx +3 -1
  63. data/app/pb_kits/playbook/pb_time_stacked/kit.schema.json +1 -0
  64. data/app/pb_kits/playbook/pb_timestamp/_timestamp.tsx +3 -1
  65. data/app/pb_kits/playbook/pb_timestamp/kit.schema.json +1 -0
  66. data/app/pb_kits/playbook/pb_typeahead/_typeahead.test.jsx +127 -0
  67. data/app/pb_kits/playbook/pb_typeahead/_typeahead.tsx +15 -10
  68. data/app/pb_kits/playbook/pb_user/_user.tsx +3 -1
  69. data/app/pb_kits/playbook/pb_user/kit.schema.json +1 -0
  70. data/app/pb_kits/playbook/pb_user_badge/_user_badge.tsx +3 -1
  71. data/app/pb_kits/playbook/pb_user_badge/kit.schema.json +1 -0
  72. data/app/pb_kits/playbook/pb_weekday_stacked/_weekday_stacked.tsx +3 -1
  73. data/app/pb_kits/playbook/pb_weekday_stacked/kit.schema.json +1 -0
  74. data/app/pb_kits/playbook/utilities/test/globalProps/onClick.test.js +186 -0
  75. data/dist/ai/all-schemas.json +56 -2
  76. data/dist/ai/external-dependencies.json +1 -1
  77. data/dist/ai/forms.json +2 -2
  78. data/dist/ai/index.json +3 -3
  79. data/dist/ai/kits/avatar.schema.json +1 -0
  80. data/dist/ai/kits/contact.schema.json +1 -0
  81. data/dist/ai/kits/date.schema.json +1 -0
  82. data/dist/ai/kits/date_range_inline.schema.json +1 -0
  83. data/dist/ai/kits/date_range_stacked.schema.json +1 -0
  84. data/dist/ai/kits/date_stacked.schema.json +1 -0
  85. data/dist/ai/kits/date_time.schema.json +1 -0
  86. data/dist/ai/kits/date_time_stacked.schema.json +1 -0
  87. data/dist/ai/kits/date_year_stacked.schema.json +1 -0
  88. data/dist/ai/kits/dropdown.schema.json +38 -1
  89. data/dist/ai/kits/image.schema.json +1 -0
  90. data/dist/ai/kits/person.schema.json +1 -0
  91. data/dist/ai/kits/rich_text_editor.schema.json +1 -1
  92. data/dist/ai/kits/time_range_inline.schema.json +1 -0
  93. data/dist/ai/kits/time_stacked.schema.json +1 -0
  94. data/dist/ai/kits/timestamp.schema.json +1 -0
  95. data/dist/ai/kits/user.schema.json +1 -0
  96. data/dist/ai/kits/user_badge.schema.json +1 -0
  97. data/dist/ai/kits/weekday_stacked.schema.json +1 -0
  98. data/dist/ai/playgrounds/dropdown.json +1 -1
  99. data/dist/ai/playgrounds/rich_text_editor.json +1 -1
  100. data/dist/chunks/{_pagination-D0hcdUl3.js → _pagination-CARbC_IN.js} +1 -1
  101. data/dist/chunks/{_tooltip-DfZEKsnv.js → _tooltip-UkcgcThO.js} +1 -1
  102. data/dist/chunks/{_typeahead-CmJ8Ggzz.js → _typeahead-NYVJDWmJ.js} +1 -1
  103. data/dist/chunks/index-4jrZjexD.js +1 -0
  104. data/dist/chunks/index-BAy61y8S.js +1 -0
  105. data/dist/chunks/index-Cb_SDipk.js +1 -0
  106. data/dist/chunks/index-D3RdsDp7.js +1 -0
  107. data/dist/chunks/index-D8PZIesy.js +1 -0
  108. data/dist/chunks/index-DIoc-aua.js +1 -0
  109. data/dist/chunks/index-qex65UMn.js +1 -0
  110. data/dist/chunks/vendor.js +2 -2
  111. data/dist/menu.yml +1 -1
  112. data/dist/playbook-rails-react-bindings.js +1 -1
  113. data/dist/playbook-rails.js +1 -1
  114. data/dist/playbook.css +1 -1
  115. data/lib/playbook/version.rb +1 -1
  116. metadata +37 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dce454b27ec0be36f4812b6955579e934aa2d63d856a62d796e7ef64b05b0a94
4
- data.tar.gz: 56f6845557ded84094f8757e2a29f3151a03407430f478ad6570aaf8dca25e93
3
+ metadata.gz: 8582fa63726a34ad01ae22c73948ace36979ee0b5d3a2f6a362309826689f963
4
+ data.tar.gz: 657c7f4fcc9819b0dec67daaab5cca1c11bc3cd8948374bc462ea287d72fe57e
5
5
  SHA512:
6
- metadata.gz: 259f6127136c2e6f3d26b5eb90e32c641c357792c0ff0dfefe5ba8e98dc808f41a55451456c39c6fa228dae125d8aa3d17296090b65d5d1be1065cd0ef7fd55c
7
- data.tar.gz: 6476556760b7bf8c5f11852974131592ffe329f86beb23fcdbb81103699f94af9d982ad47daa8537a3334d46601ca522ff34c25403406061cebd82f565e4a4bf
6
+ metadata.gz: 2598b3eea96f74b461e103e443895c80e9372ebf6dde222dca8efd6d1d9b7900f7ad3b69a48e4c80e98fb8036e1105cd344e619f2131e877477b52b929a1f4ed
7
+ data.tar.gz: 1cdd22957b2083b97d80ab7591d5441e18d43eb42a734ea33b06edd4365117d42d1b9fc1a112d33aea8cca06de775d95eaa9fa59dd5518b66f2c392c66ff99b4
@@ -157,7 +157,7 @@ module Playbook
157
157
 
158
158
  # Determines if the toggle-all button should be shown in the header based on inline row loading and persist toggle expansion button props
159
159
  def show_toggle_all_button?
160
- return false unless enable_toggle_expansion == "header" || enable_toggle_expansion == "all"
160
+ return false unless %w[header all].include?(enable_toggle_expansion)
161
161
 
162
162
  has_any_sub_rows? || (inline_row_loading && persist_toggle_expansion_button)
163
163
  end
@@ -3,6 +3,7 @@ import classnames from 'classnames'
3
3
 
4
4
  import { buildAriaProps, buildCss, buildDataProps, buildHtmlProps } from '../utilities/props'
5
5
  import { globalProps, GlobalProps } from '../utilities/globalProps'
6
+ import { GlobalEventProps, globalEventProps } from '../utilities/globalEventProps'
6
7
  import { getPlacementProps } from './Utilities/GetPlacementPropsHelper'
7
8
 
8
9
  import Image from "../pb_image/_image";
@@ -33,7 +34,7 @@ export type AvatarProps = {
33
34
  name?: string,
34
35
  size?: "md" | "lg" | "sm" | "xl" | "xs" | "xxs",
35
36
  status?: "away" | "offline" | "online",
36
- } & GlobalProps
37
+ } & GlobalProps & GlobalEventProps
37
38
 
38
39
  const firstTwoInitials = (name: string) =>
39
40
  name.split(/\s/).map((name) => name[0])
@@ -94,6 +95,7 @@ const Avatar = (props: AvatarProps): React.ReactElement => {
94
95
  {...ariaProps}
95
96
  {...dataProps}
96
97
  {...htmlProps}
98
+ {...globalEventProps(props)}
97
99
  className={classes}
98
100
  id={id}
99
101
  >
@@ -83,6 +83,7 @@
83
83
  }
84
84
  },
85
85
  "globalProps": true,
86
+ "globalEventProps": true,
86
87
  "usage": {
87
88
  "react": {
88
89
  "import": "import { Avatar } from 'playbook-ui'",
@@ -3,6 +3,7 @@ import classnames from 'classnames'
3
3
 
4
4
  import { buildAriaProps, buildCss, buildDataProps, buildHtmlProps } from '../utilities/props'
5
5
  import { globalProps } from '../utilities/globalProps'
6
+ import { GlobalEventProps, globalEventProps } from '../utilities/globalEventProps'
6
7
 
7
8
  import Body from '../pb_body/_body'
8
9
  import Caption from '../pb_caption/_caption'
@@ -64,7 +65,7 @@ type ContactProps = {
64
65
  iconEnabled?: boolean
65
66
  id?: string
66
67
  unstyled?: boolean
67
- }
68
+ } & GlobalEventProps
68
69
 
69
70
  const Contact = (props: ContactProps): React.ReactElement => {
70
71
  const {
@@ -125,6 +126,7 @@ const Contact = (props: ContactProps): React.ReactElement => {
125
126
  {...ariaProps}
126
127
  {...dataProps}
127
128
  {...htmlProps}
129
+ {...globalEventProps(props)}
128
130
  className={classes}
129
131
  id={id}
130
132
  >
@@ -139,6 +141,7 @@ const Contact = (props: ContactProps): React.ReactElement => {
139
141
  {...ariaProps}
140
142
  {...dataProps}
141
143
  {...htmlProps}
144
+ {...globalEventProps(props)}
142
145
  className={classes}
143
146
  id={id}
144
147
  >
@@ -52,6 +52,7 @@
52
52
  }
53
53
  },
54
54
  "globalProps": true,
55
+ "globalEventProps": true,
55
56
  "usage": {
56
57
  "react": {
57
58
  "import": "import { Contact } from 'playbook-ui'",
@@ -3,6 +3,7 @@ import classnames from "classnames";
3
3
 
4
4
  import { buildAriaProps, buildCss, buildDataProps, buildHtmlProps } from "../utilities/props";
5
5
  import { globalProps } from "../utilities/globalProps";
6
+ import { GlobalEventProps, globalEventProps } from "../utilities/globalEventProps";
6
7
  import DateTime from '../pb_kit/dateTime';
7
8
 
8
9
  import Body from "../pb_body/_body";
@@ -24,7 +25,7 @@ type PbDateProps = {
24
25
  size?: "sm" | "md" | "lg";
25
26
  unstyled?: boolean;
26
27
  value: Date;
27
- };
28
+ } & GlobalEventProps;
28
29
 
29
30
  const PbDate = (props: PbDateProps): React.ReactElement => {
30
31
  const {
@@ -64,6 +65,7 @@ const PbDate = (props: PbDateProps): React.ReactElement => {
64
65
  {...ariaProps}
65
66
  {...dataProps}
66
67
  {...htmlProps}
68
+ {...globalEventProps(props)}
67
69
  className={classes}
68
70
  id={id}
69
71
  >
@@ -90,6 +90,7 @@
90
90
  }
91
91
  },
92
92
  "globalProps": true,
93
+ "globalEventProps": true,
93
94
  "usage": {
94
95
  "react": {
95
96
  "import": "import { Date } from 'playbook-ui'",
@@ -2,6 +2,7 @@ import React from "react";
2
2
  import classnames from "classnames";
3
3
 
4
4
  import { globalProps } from "../utilities/globalProps";
5
+ import { GlobalEventProps, globalEventProps } from "../utilities/globalEventProps";
5
6
  import { buildCss, buildDataProps, buildHtmlProps } from "../utilities/props";
6
7
  import DateTime from '../pb_kit/dateTime';
7
8
 
@@ -21,7 +22,7 @@ type DateRangeInlineProps = {
21
22
  size?: "sm" | "xs";
22
23
  showCurrentYear?: boolean;
23
24
  startDate?: Date;
24
- };
25
+ } & GlobalEventProps;
25
26
 
26
27
  const dateTimestamp = (dateValue: Date, includeYear: boolean) => {
27
28
  if (includeYear) {
@@ -74,6 +75,7 @@ const DateRangeInline = (props: DateRangeInlineProps): React.ReactElement => {
74
75
  <div
75
76
  {...dataProps}
76
77
  {...htmlProps}
78
+ {...globalEventProps(props)}
77
79
  className={classnames(dateRangeClasses, globalProps(props), className)}
78
80
  >
79
81
  <div className="pb_date_range_inline_wrapper">
@@ -71,6 +71,7 @@
71
71
  }
72
72
  },
73
73
  "globalProps": true,
74
+ "globalEventProps": true,
74
75
  "usage": {
75
76
  "react": {
76
77
  "import": "import { DateRangeInline } from 'playbook-ui'",
@@ -3,6 +3,7 @@ import classnames from 'classnames'
3
3
 
4
4
  import { buildCss, buildDataProps, buildHtmlProps } from '../utilities/props'
5
5
  import { globalProps } from '../utilities/globalProps'
6
+ import { GlobalEventProps, globalEventProps } from '../utilities/globalEventProps'
6
7
 
7
8
  import Body from '../pb_body/_body'
8
9
  import Flex from '../pb_flex/_flex'
@@ -18,7 +19,7 @@ type DateRangeStackedProps = {
18
19
  htmlOptions?: {[key: string]: string | number | boolean | (() => void)},
19
20
  id?: string,
20
21
  startDate: Date,
21
- }
22
+ } & GlobalEventProps
22
23
 
23
24
  const DateRangeStacked = (props: DateRangeStackedProps): React.ReactElement => {
24
25
  const {
@@ -41,6 +42,7 @@ const DateRangeStacked = (props: DateRangeStackedProps): React.ReactElement => {
41
42
  <div
42
43
  {...dataProps}
43
44
  {...htmlProps}
45
+ {...globalEventProps(props)}
44
46
  className={css}
45
47
  >
46
48
  <Flex vertical="center">
@@ -31,6 +31,7 @@
31
31
  }
32
32
  },
33
33
  "globalProps": true,
34
+ "globalEventProps": true,
34
35
  "usage": {
35
36
  "react": {
36
37
  "import": "import { DateRangeStacked } from 'playbook-ui'",
@@ -3,6 +3,7 @@ import React from "react";
3
3
  import classnames from "classnames";
4
4
  import { buildCss, buildDataProps, buildHtmlProps } from "../utilities/props";
5
5
  import { globalProps } from "../utilities/globalProps";
6
+ import { GlobalEventProps, globalEventProps } from "../utilities/globalEventProps";
6
7
  import DateTime from '../pb_kit/dateTime';
7
8
 
8
9
  import Caption from "../pb_caption/_caption";
@@ -20,7 +21,7 @@ type DateStackedProps = {
20
21
  id?: string;
21
22
  reverse?: boolean;
22
23
  showCurrentYear?: boolean;
23
- };
24
+ } & GlobalEventProps;
24
25
 
25
26
  const sizes: {sm: 4, md: 3} = {
26
27
  sm: 4,
@@ -60,6 +61,7 @@ const DateStacked = (props: DateStackedProps): React.ReactElement => {
60
61
  <div
61
62
  {...dataProps}
62
63
  {...htmlProps}
64
+ {...globalEventProps(props)}
63
65
  className={classes}
64
66
  >
65
67
  <div className="pb_date_stacked_day_month">
@@ -76,6 +78,7 @@ const DateStacked = (props: DateStackedProps): React.ReactElement => {
76
78
  <div
77
79
  {...dataProps}
78
80
  {...htmlProps}
81
+ {...globalEventProps(props)}
79
82
  className={classes}
80
83
  >
81
84
  <div className="pb_date_stacked_day_month">
@@ -73,6 +73,7 @@
73
73
  }
74
74
  },
75
75
  "globalProps": true,
76
+ "globalEventProps": true,
76
77
  "usage": {
77
78
  "react": {
78
79
  "import": "import { DateStacked } from 'playbook-ui'",
@@ -3,6 +3,7 @@ import classnames from 'classnames'
3
3
 
4
4
  import { buildAriaProps, buildCss, buildDataProps, buildHtmlProps } from '../utilities/props'
5
5
  import { globalProps } from '../utilities/globalProps'
6
+ import { GlobalEventProps, globalEventProps } from '../utilities/globalEventProps'
6
7
 
7
8
  import Flex from '../pb_flex/_flex'
8
9
  import Time from '../pb_time/_time'
@@ -21,7 +22,7 @@ type DateTimeProps = {
21
22
  showDayOfWeek: boolean,
22
23
  showIcon?: boolean,
23
24
  timeZone?: string
24
- }
25
+ } & GlobalEventProps
25
26
 
26
27
  const DateTime = (props: DateTimeProps): React.ReactElement => {
27
28
  const {
@@ -53,6 +54,7 @@ const DateTime = (props: DateTimeProps): React.ReactElement => {
53
54
  {...ariaProps}
54
55
  {...dataProps}
55
56
  {...htmlProps}
57
+ {...globalEventProps(props)}
56
58
  className={classes}
57
59
  id={id}
58
60
  >
@@ -90,6 +90,7 @@
90
90
  }
91
91
  },
92
92
  "globalProps": true,
93
+ "globalEventProps": true,
93
94
  "usage": {
94
95
  "react": {
95
96
  "import": "import { DateTime } from 'playbook-ui'",
@@ -4,6 +4,7 @@ import classnames from 'classnames'
4
4
 
5
5
  import { buildCss, buildHtmlProps } from '../utilities/props'
6
6
  import { deprecatedProps, globalProps } from '../utilities/globalProps'
7
+ import { GlobalEventProps } from '../utilities/globalEventProps'
7
8
 
8
9
  import Flex from '../pb_flex/_flex'
9
10
  import FlexItem from '../pb_flex/_flex_item'
@@ -20,7 +21,7 @@ type DateTimeStackedProps = {
20
21
  dark: boolean,
21
22
  timeZone?: string,
22
23
  showCurrentYear?: boolean,
23
- }
24
+ } & GlobalEventProps
24
25
 
25
26
  const DateTimeStacked = (props: DateTimeStackedProps): React.ReactElement => {
26
27
  if (props.date) deprecatedProps()
@@ -57,6 +57,7 @@
57
57
  }
58
58
  },
59
59
  "globalProps": true,
60
+ "globalEventProps": true,
60
61
  "usage": {
61
62
  "react": {
62
63
  "import": "import { DateTimeStacked } from 'playbook-ui'",
@@ -3,6 +3,7 @@ import classnames from 'classnames'
3
3
 
4
4
  import { buildCss, buildDataProps, buildHtmlProps } from '../utilities/props'
5
5
  import { globalProps } from '../utilities/globalProps'
6
+ import { GlobalEventProps, globalEventProps } from '../utilities/globalEventProps'
6
7
  import DateTime from '../pb_kit/dateTime';
7
8
 
8
9
  import Body from '../pb_body/_body'
@@ -16,7 +17,7 @@ type DateYearStackedProps = {
16
17
  date: Date,
17
18
  htmlOptions?: {[key: string]: string | number | boolean | (() => void)},
18
19
  id?: string,
19
- }
20
+ } & GlobalEventProps
20
21
 
21
22
  const DateYearStacked = (props: DateYearStackedProps): React.ReactElement => {
22
23
  const {
@@ -39,6 +40,7 @@ const DateYearStacked = (props: DateYearStackedProps): React.ReactElement => {
39
40
  <div
40
41
  {...dataProps}
41
42
  {...htmlProps}
43
+ {...globalEventProps(props)}
42
44
  className={css}
43
45
  >
44
46
  <Title
@@ -37,6 +37,7 @@
37
37
  }
38
38
  },
39
39
  "globalProps": true,
40
+ "globalEventProps": true,
40
41
  "usage": {
41
42
  "react": {
42
43
  "import": "import { DateYearStacked } from 'playbook-ui'",
@@ -370,6 +370,16 @@ export const bindMousePointerDrag = ({
370
370
  event.preventDefault();
371
371
  event.stopPropagation();
372
372
 
373
+ // Dropdown: restore pill focus after preventDefault so ArrowLeft/Right work.
374
+ // Typeahead: leave focus on the search input — focusing the pill blurs it and
375
+ // react-select closes the menu / clears the query.
376
+ const pill = itemElement.querySelector<HTMLElement>(
377
+ '.pb_form_pill_kit, .pb_form_pill_kit_icon',
378
+ );
379
+ if (pill && !itemElement.closest('.pb_typeahead_kit')) {
380
+ pill.focus({ preventScroll: true });
381
+ }
382
+
373
383
  state.active = true;
374
384
  state.startX = event.clientX;
375
385
  state.startY = event.clientY;
@@ -4,6 +4,7 @@
4
4
  @import "../tokens/border_radius";
5
5
  @import "../tokens/shadows";
6
6
  @import "../tokens/positioning";
7
+ @import "../tokens/opacity";
7
8
  @import "../pb_body/body_mixins";
8
9
  @import "../pb_textarea/textarea_mixin";
9
10
 
@@ -536,3 +537,114 @@
536
537
  padding: 0;
537
538
  pointer-events: auto;
538
539
  }
540
+
541
+ .pb_dropdown_draggable_pills {
542
+ display: inline-flex;
543
+ flex-wrap: wrap;
544
+ align-items: center;
545
+ gap: 0;
546
+
547
+ .pb_draggable_item {
548
+ position: relative;
549
+ display: inline-flex;
550
+ align-items: center;
551
+ user-select: none;
552
+ -webkit-user-select: none;
553
+
554
+ &.pb_dropdown_drop_before::before,
555
+ &.pb_dropdown_drop_after::after {
556
+ content: "";
557
+ position: absolute;
558
+ inset-block: 2px;
559
+ width: 2px;
560
+ background-color: $primary;
561
+ border-radius: $border_radius_rounded;
562
+ pointer-events: none;
563
+ }
564
+ &.pb_dropdown_drop_before::before {
565
+ inset-inline-start: -5px;
566
+ }
567
+ &.pb_dropdown_drop_after::after {
568
+ inset-inline-end: 3px;
569
+ }
570
+
571
+ &:hover {
572
+ cursor: grab;
573
+ }
574
+
575
+ &.is_dragging {
576
+ cursor: grabbing;
577
+ }
578
+
579
+ .pb_form_pill_kit_icon,
580
+ .pb_form_pill_kit_icon * {
581
+ cursor: grab;
582
+ }
583
+ .pb_form_pill_close,
584
+ .pb_form_pill_close * {
585
+ cursor: pointer;
586
+ }
587
+ }
588
+
589
+ &.active .pb_draggable_item > * {
590
+ pointer-events: none;
591
+ }
592
+ }
593
+
594
+ .pb_dropdown_pill_with_handle {
595
+ display: inline-flex;
596
+ align-items: center;
597
+ gap: $space_xxs;
598
+ }
599
+
600
+ .pb_dropdown_external_drag_handle {
601
+ display: inline-flex;
602
+ align-items: center;
603
+ flex-shrink: 0;
604
+ cursor: grab;
605
+ user-select: none;
606
+ color: $text_lighter;
607
+
608
+ &:active {
609
+ cursor: grabbing;
610
+ }
611
+
612
+ .pb_dropdown_pill_grip_icon {
613
+ color: $text_lighter !important;
614
+ }
615
+ }
616
+
617
+ .pb_dropdown_draggable_pills,
618
+ .pb_dropdown_pill_drag_preview {
619
+ .pb_form_pill_kit_icon .pb_form_pill_icon,
620
+ .pb_form_pill_kit_icon .pb_dropdown_pill_grip_icon {
621
+ order: -1;
622
+ color: $text_lighter !important;
623
+ margin-left: -$space_xs;
624
+ padding-right: $space_xxs;
625
+ scale: 0.9;
626
+ }
627
+ .pb_form_pill_kit_icon.dark .pb_form_pill_icon,
628
+ .pb_form_pill_kit_icon.dark .pb_dropdown_pill_grip_icon {
629
+ color: $text_lighter_dark !important;
630
+ }
631
+ }
632
+
633
+ .pb_dropdown_pill_drag_preview {
634
+ position: fixed;
635
+ z-index: $z_max;
636
+ display: inline-flex;
637
+ align-items: center;
638
+ opacity: $opacity_5;
639
+ pointer-events: none;
640
+
641
+ .pb_form_pill_kit,
642
+ .pb_form_pill_kit_icon {
643
+ box-shadow: $shadow_deep;
644
+ }
645
+ }
646
+
647
+ body:has(.pb_dropdown_pill_drag_preview),
648
+ body:has(.pb_dropdown_pill_drag_preview) * {
649
+ cursor: grabbing !important;
650
+ }
@@ -126,6 +126,8 @@ type DropdownProps = {
126
126
  defaultValue?: GenericObject;
127
127
  error?: string;
128
128
  enableFormSupport?: boolean;
129
+ enablePillReorder?: boolean;
130
+ externalDragHandle?: boolean;
129
131
  htmlOptions?: { [key: string]: string | number | boolean | (() => void) },
130
132
  id?: string;
131
133
  isClosed?: boolean;
@@ -138,6 +140,7 @@ type DropdownProps = {
138
140
  options?: GenericObject;
139
141
  placeholder?: string;
140
142
  separators?: boolean;
143
+ showPillIndex?: boolean;
141
144
  variant?: "default" | "subtle" | "quickpick";
142
145
  rangeEndsToday?: boolean;
143
146
  controlsStartId?: string;
@@ -184,6 +187,8 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
184
187
  disabled = false,
185
188
  error: errorProp,
186
189
  enableFormSupport = false,
190
+ enablePillReorder = false,
191
+ externalDragHandle = false,
187
192
  htmlOptions = {},
188
193
  id,
189
194
  isClosed = true,
@@ -196,6 +201,7 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
196
201
  onSelect,
197
202
  options,
198
203
  placeholder,
204
+ showPillIndex = false,
199
205
  rangeEndsToday = false,
200
206
  controlsStartId,
201
207
  controlsEndId,
@@ -207,6 +213,8 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
207
213
  validationMessage = "Please fill out this field."
208
214
  } = props;
209
215
 
216
+ const isPillReorderEnabled = Boolean(enablePillReorder && multiSelect);
217
+
210
218
  const creationEnabled = allowOptionCreation && variant !== "quickpick";
211
219
  const autocomplete = autocompleteProp || creationEnabled;
212
220
 
@@ -837,6 +845,8 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
837
845
  disabled,
838
846
  error,
839
847
  errorId,
848
+ enablePillReorder: isPillReorderEnabled,
849
+ externalDragHandle,
840
850
  filterItem,
841
851
  filteredOptions,
842
852
  focusedOptionIndex,
@@ -865,6 +875,7 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
865
875
  setIsDropDownClosed,
866
876
  setIsInputFocused,
867
877
  setSelected,
878
+ showPillIndex,
868
879
  toggleDropdown
869
880
  }}
870
881
  >
@@ -0,0 +1,51 @@
1
+ <%
2
+ options = [
3
+ { label: 'Year', value: 'year', id: 'year' },
4
+ { label: 'Territory', value: 'territory', id: 'territory' },
5
+ { label: 'Branch', value: 'branch', id: 'branch' },
6
+ { label: 'Product', value: 'product', id: 'product' },
7
+ ]
8
+ %>
9
+
10
+ <%= pb_rails("body", props: { text: "Select services, then drag the pills to reorder them.", margin_bottom: "xs" }) %>
11
+
12
+ <%= pb_rails("dropdown", props: {
13
+ id: "dropdown-draggable-pills-example",
14
+ default_value: [options[0], options[1], options[2]],
15
+ enable_pill_reorder: true,
16
+ show_pill_index: true,
17
+ multi_select: true,
18
+ label: "Services",
19
+ name: :services,
20
+ options: options,
21
+ placeholder: "Add services...",
22
+ }) %>
23
+
24
+ <%= pb_rails("body", props: {
25
+ id: "dropdown-draggable-order",
26
+ color: "lighter",
27
+ margin_top: "xs",
28
+ text: "Current order: Year -> Territory -> Branch",
29
+ }) %>
30
+
31
+ <script>
32
+ (() => {
33
+ const dropdownId = "dropdown-draggable-pills-example";
34
+ const orderElement = document.getElementById("dropdown-draggable-order");
35
+
36
+ const updateOrderText = (detail) => {
37
+ if (!orderElement || !Array.isArray(detail)) return;
38
+ orderElement.textContent = `Current order: ${detail.map((item) => item.label).join(" -> ")}`;
39
+ };
40
+
41
+ document.addEventListener("pb:dropdown:reordered", (event) => {
42
+ if (event.target.id !== dropdownId) return;
43
+ updateOrderText(event.detail);
44
+ });
45
+
46
+ document.addEventListener("pb:dropdown:selected", (event) => {
47
+ if (event.target.id !== dropdownId) return;
48
+ updateOrderText(event.detail);
49
+ });
50
+ })();
51
+ </script>
@@ -0,0 +1,62 @@
1
+ import React, { useState } from 'react'
2
+ import { Body, Button, Dropdown, Flex } from 'playbook-ui'
3
+
4
+ const options = [
5
+ { label: 'Year', value: 'year', id: 'year' },
6
+ { label: 'Territory', value: 'territory', id: 'territory' },
7
+ { label: 'Branch', value: 'branch', id: 'branch' },
8
+ { label: 'Product', value: 'product', id: 'product' },
9
+ ]
10
+
11
+ const DropdownDraggablePills = (props) => {
12
+ const [value, setValue] = useState([
13
+ options[0],
14
+ options[1],
15
+ options[2],
16
+ ])
17
+
18
+ const currentOrder = value.map((item) => item.label).join(' -> ')
19
+
20
+ const handleReset = () => {
21
+ setValue([options[0], options[1], options[2]])
22
+ }
23
+
24
+ return (
25
+ <Flex
26
+ align="stretch"
27
+ gap="sm"
28
+ orientation="column"
29
+ >
30
+ <Flex
31
+ align="center"
32
+ justify="between"
33
+ >
34
+ <Body text="Select services, then drag the pills to reorder them." />
35
+ <Button
36
+ onClick={handleReset}
37
+ text="Reset"
38
+ variant="secondary"
39
+ />
40
+ </Flex>
41
+
42
+ <Dropdown
43
+ enablePillReorder
44
+ label="Services"
45
+ multiSelect
46
+ onChange={({ target }) => setValue(target.value || [])}
47
+ options={options}
48
+ placeholder="Add services..."
49
+ showPillIndex
50
+ value={value}
51
+ {...props}
52
+ />
53
+
54
+ <Body
55
+ color="lighter"
56
+ text={`Current order: ${currentOrder}`}
57
+ />
58
+ </Flex>
59
+ )
60
+ }
61
+
62
+ export default DropdownDraggablePills
@@ -0,0 +1,9 @@
1
+ Use `enable_pill_reorder: true` with `show_pill_index: true` to let users drag selected multi-select pills into a new order. By default, each pill shows a grip icon and can be dragged from anywhere on the pill. Set `external_drag_handle: true` to use an external grip handle instead (drag only from the handle).
2
+
3
+ While dragging, pills stay in place, a ghost follows the pointer, and a blue line marks where the pill will land. Order is committed on drop.
4
+
5
+ The `pb:dropdown:reordered` custom event receives the reordered value array. Submitted form values (hidden inputs) preserve the new order. `pb:dropdown:selected` also fires with the updated order.
6
+
7
+ Keyboard reorder: focus a pill, then press ArrowLeft or ArrowRight to move it one position.
8
+
9
+ Works with Multi-Select and Multi-Select + Autocomplete Dropdown variants only, and is disabled by default.
@@ -0,0 +1,9 @@
1
+ Use `enablePillReorder` to let users drag selected multi-select pills into a new order. Pair with `showPillIndex` to display numbered prefixes that update automatically after reorder or removal.
2
+
3
+ By default, each pill shows a grip icon and can be dragged from anywhere on the pill. Set `externalDragHandle` to `true` to use an external grip handle instead (drag only from the handle).
4
+
5
+ While dragging, pills stay in place, a ghost follows the pointer, and a blue line marks where the pill will land. Order is committed on drop. The `onChange` callback receives the reordered value array.
6
+
7
+ Keyboard reorder: focus a pill, then press ArrowLeft or ArrowRight to move it one position.
8
+
9
+ Works with Multi-Select and Multi-Select + Autocomplete. Dropdown variants only, and is disabled by default.