playbook_ui 18.1.0.pre.rc.2 → 18.1.0.pre.rc.4

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 (35) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/pb_copy_button/_copy_button.tsx +5 -1
  3. data/app/pb_kits/playbook/pb_copy_button/copy_button.test.jsx +12 -0
  4. data/app/pb_kits/playbook/pb_date_picker/_date_picker.tsx +3 -0
  5. data/app/pb_kits/playbook/pb_date_picker/date_picker.rb +3 -0
  6. data/app/pb_kits/playbook/pb_date_picker/date_picker.test.js +14 -0
  7. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_close_on_select.html.erb +5 -0
  8. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_close_on_select.jsx +21 -0
  9. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_close_on_select.md +3 -0
  10. data/app/pb_kits/playbook/pb_date_picker/docs/_playground.json +1 -0
  11. data/app/pb_kits/playbook/pb_date_picker/docs/example.yml +2 -0
  12. data/app/pb_kits/playbook/pb_date_picker/docs/index.js +1 -0
  13. data/app/pb_kits/playbook/pb_date_picker/kit.schema.json +8 -0
  14. data/app/pb_kits/playbook/pb_date_time_stacked/_date_time_stacked.tsx +10 -4
  15. data/app/pb_kits/playbook/pb_date_time_stacked/date_time_stacked.test.js +12 -0
  16. data/app/pb_kits/playbook/pb_dialog/child_kits/_dialog_body.tsx +9 -4
  17. data/app/pb_kits/playbook/pb_dialog/dialog.test.jsx +10 -0
  18. data/app/pb_kits/playbook/pb_empty_state/_empty_state.tsx +5 -1
  19. data/app/pb_kits/playbook/pb_empty_state/empty_state.test.jsx +11 -0
  20. data/app/pb_kits/playbook/pb_filter/Filter/FilterBackground.tsx +8 -2
  21. data/app/pb_kits/playbook/pb_filter/Filter/SortMenu.tsx +1 -1
  22. data/app/pb_kits/playbook/pb_filter/filter.rb +2 -2
  23. data/app/pb_kits/playbook/pb_filter/filter.test.js +14 -0
  24. data/app/pb_kits/playbook/pb_progress_step/_progress_step_item.tsx +2 -1
  25. data/app/pb_kits/playbook/pb_progress_step/progress_step.test.js +16 -0
  26. data/app/pb_kits/playbook/pb_source/_source.tsx +14 -11
  27. data/app/pb_kits/playbook/pb_source/source.test.js +6 -0
  28. data/dist/ai/all-schemas.json +8 -0
  29. data/dist/ai/forms.json +1 -1
  30. data/dist/ai/index.json +2 -2
  31. data/dist/ai/kits/date_picker.schema.json +8 -0
  32. data/dist/chunks/{_table-BGTSSDK1.js → _table-BrYlBrTH.js} +1 -1
  33. data/dist/chunks/vendor.js +2 -2
  34. data/lib/playbook/version.rb +1 -1
  35. metadata +6 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 69806745bf9d406cc340a98ebaa54bbab8fd00312d756cd0bf60e3077db5794e
4
- data.tar.gz: 0aef11e0e9dc51c336af96739287476e8b01e8397c2580cfff87d8ef0a17a7eb
3
+ metadata.gz: 81d76f51de9e88ac32f50756b803e8a063264b582bc8e9797ef49e2dfba04867
4
+ data.tar.gz: 5a214970102ba6d3a2abe9a4e2342aaf4e79b2e1e55b8ad6acdd597580e678ce
5
5
  SHA512:
6
- metadata.gz: 590f41d6ac3e5304ad388114c1a0a0264df448ef4e4df753a4e06058c4a80bae552f5aefb78f768ff257073694dcc9433fd697520a7603d7d2ce5b4b314fd5c5
7
- data.tar.gz: 4dd0fe2434dc65fd2a2eab892ffd571d6c6f2fcf9d7ea72e5fb83da7d5f5cf44ccaf5c2e579765c2886092779b4b5c7de0007da7a12cc49998c23ca253815208
6
+ metadata.gz: 7ca0873a34437139622dca8b4848cde6f266bfb059caa97af140a2226e327772bea439c0b90140e9dba01f32082ee6cf8ea066ad1c626a77ea5de7e9efcf88a5
7
+ data.tar.gz: af0f9628b3defe688b29dacf8beffb13e37235c30e92e1eb6b6cf4af96708ed1c4d0a072704ecb990ae74bd8759b0cbb1dae5a81d2ddea2322cad39a90ebfca3
@@ -1,6 +1,6 @@
1
1
  import React from 'react'
2
2
  import classnames from 'classnames'
3
- import { buildAriaProps, buildCss, buildDataProps } from '../utilities/props'
3
+ import { buildAriaProps, buildCss, buildDataProps, buildHtmlProps } from '../utilities/props'
4
4
  import { globalProps } from '../utilities/globalProps'
5
5
 
6
6
  import Button from '../pb_button/_button'
@@ -13,6 +13,7 @@ type CopyButtonProps = {
13
13
  aria?: { [key: string]: string }
14
14
  className?: string
15
15
  data?: { [key: string]: string }
16
+ htmlOptions?: {[key: string]: string | number | boolean | (() => void)}
16
17
  id?: string
17
18
  from?: string
18
19
  text?: string
@@ -29,6 +30,7 @@ const CopyButton = (props: CopyButtonProps) => {
29
30
  className,
30
31
  data = {},
31
32
  from = '',
33
+ htmlOptions = {},
32
34
  id,
33
35
  text = 'Copy',
34
36
  timeout = 1000,
@@ -42,12 +44,14 @@ const CopyButton = (props: CopyButtonProps) => {
42
44
 
43
45
  const ariaProps = buildAriaProps(aria)
44
46
  const dataProps = buildDataProps(data)
47
+ const htmlProps = buildHtmlProps(htmlOptions)
45
48
  const classes = classnames(buildCss('pb_copy_button_kit'), globalProps(props), className)
46
49
 
47
50
  return (
48
51
  <div
49
52
  {...ariaProps}
50
53
  {...dataProps}
54
+ {...htmlProps}
51
55
  className={classes}
52
56
  id={id}
53
57
  >
@@ -86,3 +86,15 @@ test('passes text and tooltip props to button', () => {
86
86
  const tooltip = kit.querySelector('.pb_tooltip_kit')
87
87
  expect(tooltip).toBeInTheDocument()
88
88
  })
89
+
90
+ test('applies htmlOptions to the root element', () => {
91
+ render(
92
+ <CopyButton
93
+ data={{ testid: 'html-options-test' }}
94
+ htmlOptions={{ title: 'copy title' }}
95
+ value="copy"
96
+ />
97
+ )
98
+
99
+ expect(screen.getByTestId('html-options-test')).toHaveAttribute('title', 'copy title')
100
+ })
@@ -52,6 +52,7 @@ type DatePickerProps = {
52
52
  allowInput?: boolean,
53
53
  aria?: { [key: string]: string },
54
54
  className?: string,
55
+ closeOnSelect?: boolean,
55
56
  customQuickPickDates: { override: boolean, dates: any[] },
56
57
  dark?: boolean,
57
58
  data?: { [key: string]: string },
@@ -103,6 +104,7 @@ const DatePicker = (props: DatePickerProps): React.ReactElement => {
103
104
  allowInput = false,
104
105
  aria = {},
105
106
  className,
107
+ closeOnSelect = true,
106
108
  customQuickPickDates,
107
109
  dark = false,
108
110
  data = {},
@@ -180,6 +182,7 @@ const DatePicker = (props: DatePickerProps): React.ReactElement => {
180
182
  useEffect(() => {
181
183
  datePickerHelper({
182
184
  allowInput,
185
+ closeOnSelect,
183
186
  customQuickPickDates,
184
187
  defaultDate: normalizedDefaultDate,
185
188
  disableDate,
@@ -91,6 +91,8 @@ module Playbook
91
91
  default: "pointer"
92
92
  prop :year_ascending, type: Playbook::Props::Boolean,
93
93
  default: false
94
+ prop :close_on_select, type: Playbook::Props::Boolean,
95
+ default: true
94
96
 
95
97
  def classname
96
98
  default_margin_bottom = margin_bottom.present? ? "" : " mb_sm"
@@ -101,6 +103,7 @@ module Playbook
101
103
  def date_picker_config
102
104
  {
103
105
  allowInput: allow_input,
106
+ closeOnSelect: close_on_select,
104
107
  customQuickPickDates: custom_quick_pick_dates,
105
108
  defaultDate: default_date,
106
109
  disableDate: disable_date,
@@ -510,4 +510,18 @@ describe('DatePicker Kit', () => {
510
510
  )
511
511
  })
512
512
  })
513
+
514
+ test('passes closeOnSelect to flatpickr', async () => {
515
+ render(
516
+ <DatePicker
517
+ closeOnSelect={false}
518
+ pickerId="date-picker-close-on-select"
519
+ />
520
+ )
521
+
522
+ await waitFor(() => {
523
+ const input = document.getElementById('date-picker-close-on-select')
524
+ expect(input._flatpickr.config.closeOnSelect).toBe(false)
525
+ })
526
+ })
513
527
  })
@@ -0,0 +1,5 @@
1
+ <%= pb_rails("date_picker", props: {
2
+ close_on_select: false,
3
+ default_date: DateTime.now.utc.iso8601,
4
+ picker_id: "date-picker-close-on-select"
5
+ }) %>
@@ -0,0 +1,21 @@
1
+ import React from 'react'
2
+
3
+ import DatePicker from '../_date_picker'
4
+
5
+ const DEFAULT_DATE = new Date()
6
+
7
+ const DatePickerCloseOnSelect = (props) => {
8
+ return (
9
+ <>
10
+ <DatePicker
11
+ closeOnSelect={false}
12
+ defaultDate={DEFAULT_DATE}
13
+ initializeOnce
14
+ pickerId="date-picker-close-on-select"
15
+ {...props}
16
+ />
17
+ </>
18
+ )
19
+ }
20
+
21
+ export default DatePickerCloseOnSelect
@@ -0,0 +1,3 @@
1
+ When `closeOnSelect` / `close_on_select` is set to `false`, the DatePicker remains open after a date is selected and closes when the user clicks outside it. The prop defaults to `true`.
2
+
3
+ In React, use `initializeOnce` when the change handler updates state so that rerendering does not reinitialize and close the DatePicker.
@@ -3,6 +3,7 @@
3
3
  "propTargets": {},
4
4
  "defaults": {
5
5
  "allowInput": false,
6
+ "closeOnSelect": true,
6
7
  "dark": false,
7
8
  "defaultDate": "",
8
9
  "disableInput": false,
@@ -33,6 +33,7 @@ examples:
33
33
  - date_picker_positions: Custom Positions
34
34
  - date_picker_positions_element: Custom Position (based on element)
35
35
  - date_picker_required_indicator: Required Indicator
36
+ - date_picker_close_on_select: Close on Select
36
37
  - date_picker_turbo_frames: Within Turbo Frames
37
38
 
38
39
  react:
@@ -68,4 +69,5 @@ examples:
68
69
  - date_picker_positions: Custom Positions
69
70
  - date_picker_positions_element: Custom Position (based on element)
70
71
  - date_picker_required_indicator: Required Indicator
72
+ - date_picker_close_on_select: Close on Select
71
73
  - date_picker_dialog_submission: Dialog Form Submission
@@ -31,3 +31,4 @@ export { default as DatePickerAndDropdownRange } from './_date_picker_and_dropdo
31
31
  export { default as DatePickerRequiredIndicator } from "./_date_picker_required_indicator.jsx";
32
32
  export { default as DatePickerDialogSubmission } from "./_date_picker_dialog_submission.jsx";
33
33
  export { default as DatePickerYearAsc } from './_date_picker_year_asc.jsx'
34
+ export { default as DatePickerCloseOnSelect } from './_date_picker_close_on_select.jsx'
@@ -15,6 +15,14 @@
15
15
  ],
16
16
  "default": false
17
17
  },
18
+ "closeOnSelect": {
19
+ "type": "boolean",
20
+ "platforms": [
21
+ "react",
22
+ "rails"
23
+ ],
24
+ "default": true
25
+ },
18
26
  "customQuickPickDates": {
19
27
  "type": "GenericObject",
20
28
  "platforms": [
@@ -1,5 +1,6 @@
1
1
 
2
2
  import React from 'react'
3
+ import classnames from 'classnames'
3
4
 
4
5
  import { buildCss, buildHtmlProps } from '../utilities/props'
5
6
  import { deprecatedProps, globalProps } from '../utilities/globalProps'
@@ -11,6 +12,7 @@ import TimeStacked from '../pb_time_stacked/_time_stacked'
11
12
  import DateStacked from '../pb_date_stacked/_date_stacked'
12
13
 
13
14
  type DateTimeStackedProps = {
15
+ className?: string,
14
16
  htmlOptions?: {[key: string]: string | number | boolean | (() => void)},
15
17
  id?: string,
16
18
  date: Date,
@@ -27,20 +29,25 @@ const DateTimeStacked = (props: DateTimeStackedProps): React.ReactElement => {
27
29
  date,
28
30
  datetime,
29
31
  dark,
32
+ className,
30
33
  htmlOptions = {},
31
34
  timeZone = 'America/New_York',
32
35
  showCurrentYear = false,
33
36
  } = props
34
37
 
35
- const classes = buildCss('pb_date_time_stacked_kit', globalProps(props))
36
- const htmlProps = buildHtmlProps(htmlOptions)
38
+ const classes = classnames(
39
+ buildCss('pb_date_time_stacked_kit'),
40
+ globalProps(props),
41
+ className
42
+ )
37
43
 
38
44
  return (
39
45
  <Flex
46
+ htmlOptions={htmlOptions}
40
47
  inline={false}
41
48
  vertical="stretch"
42
- {...htmlProps}
43
49
  {...props}
50
+ className={classes}
44
51
  >
45
52
  <FlexItem>
46
53
  <DateStacked
@@ -58,7 +65,6 @@ const DateTimeStacked = (props: DateTimeStackedProps): React.ReactElement => {
58
65
  />
59
66
  <FlexItem>
60
67
  <TimeStacked
61
- className={classes}
62
68
  dark={dark}
63
69
  date={date || datetime}
64
70
  timeZone={timeZone}
@@ -74,3 +74,15 @@ test('hides current year by default', () => {
74
74
  expect(yearElement).toBeNull()
75
75
  }
76
76
  })
77
+
78
+ test('applies kit class and global props to the root', () => {
79
+ const kit = renderKit(DateTimeStacked, {
80
+ data: { testid: 'datetimestacked-root' },
81
+ datetime,
82
+ dark: false,
83
+ margin: 'md',
84
+ })
85
+
86
+ expect(kit).toHaveClass('pb_date_time_stacked_kit')
87
+ expect(kit).toHaveClass('m_md')
88
+ })
@@ -1,22 +1,27 @@
1
1
  import React from 'react'
2
2
  import classnames from 'classnames'
3
- import { buildCss } from '../../utilities/props'
3
+ import { buildCss, buildHtmlProps } from '../../utilities/props'
4
4
  import { globalProps } from '../../utilities/globalProps'
5
5
 
6
6
  type DialogBodyProps = {
7
7
  children: React.ReactNode | React.ReactNode[] | string,
8
8
  padding?: "xxs" | "xs" | "sm" | "md" | "lg" | "xl",
9
- className?: string
9
+ className?: string,
10
+ htmlOptions?: {[key: string]: string | number | boolean | (() => void)},
10
11
  }
11
12
 
12
13
  // Body component
13
14
  const DialogBody = (props: DialogBodyProps): React.ReactElement => {
14
- const { children, className } = props
15
+ const { children, className, htmlOptions = {} } = props
15
16
  const bodyCSS = buildCss("dialog_body")
16
17
  const bodySpacing = globalProps(props)
18
+ const htmlProps = buildHtmlProps(htmlOptions)
17
19
 
18
20
  return (
19
- <div className={classnames(bodyCSS, bodySpacing, className)}>
21
+ <div
22
+ {...htmlProps}
23
+ className={classnames(bodyCSS, bodySpacing, className)}
24
+ >
20
25
  {children}
21
26
  </div>
22
27
  )
@@ -268,3 +268,13 @@ describe('isNativeSelectMenuInteraction', () => {
268
268
  expect(isNativeSelectMenuInteraction(dialog, select)).toBe(false)
269
269
  })
270
270
  })
271
+
272
+ test("applies htmlOptions to Dialog.Body", () => {
273
+ render(
274
+ <Dialog.Body htmlOptions={{ title: "body title" }}>
275
+ {"Body content"}
276
+ </Dialog.Body>
277
+ )
278
+
279
+ expect(document.querySelector(".dialog_body")).toHaveAttribute("title", "body title")
280
+ })
@@ -2,7 +2,7 @@
2
2
  import React from "react"
3
3
  import ReactDOMServer from "react-dom/server"
4
4
  import classnames from "classnames"
5
- import { buildAriaProps, buildCss, buildDataProps } from "../utilities/props"
5
+ import { buildAriaProps, buildCss, buildDataProps, buildHtmlProps } from "../utilities/props"
6
6
  import { globalProps } from "../utilities/globalProps"
7
7
  import Title from "../pb_title/_title"
8
8
  import Body from "../pb_body/_body"
@@ -22,6 +22,7 @@ type EmptyStateProps = {
22
22
  data?: { [key: string]: string },
23
23
  description?: string,
24
24
  header?: string,
25
+ htmlOptions?: {[key: string]: string | number | boolean | (() => void)},
25
26
  id?: string,
26
27
  image?: string,
27
28
  linkButton?: string,
@@ -40,6 +41,7 @@ const EmptyState = (props: EmptyStateProps) => {
40
41
  data = {},
41
42
  description,
42
43
  header = "",
44
+ htmlOptions = {},
43
45
  id,
44
46
  image,
45
47
  linkButton,
@@ -52,6 +54,7 @@ const EmptyState = (props: EmptyStateProps) => {
52
54
 
53
55
  const ariaProps = buildAriaProps(aria)
54
56
  const dataProps = buildDataProps(data)
57
+ const htmlProps = buildHtmlProps(htmlOptions)
55
58
  const classes = classnames(buildCss("pb_empty_state_kit"), globalProps(props), className)
56
59
 
57
60
  const renderContent = () => {
@@ -137,6 +140,7 @@ const EmptyState = (props: EmptyStateProps) => {
137
140
  const layout = (
138
141
  <div {...ariaProps}
139
142
  {...dataProps}
143
+ {...htmlProps}
140
144
  className={classes}
141
145
  id={id}
142
146
  >
@@ -14,4 +14,15 @@ test('returns namespaced class name', () => {
14
14
 
15
15
  const kit = screen.getByTestId('primary-test')
16
16
  expect(kit).toHaveClass('pb_empty_state_kit')
17
+ })
18
+
19
+ test('applies htmlOptions to the root element', () => {
20
+ render(
21
+ <EmptyState
22
+ data={{ testid: 'html-options-test' }}
23
+ htmlOptions={{ title: 'empty state title' }}
24
+ />
25
+ )
26
+
27
+ expect(screen.getByTestId('html-options-test')).toHaveAttribute('title', 'empty state title')
17
28
  })
@@ -1,6 +1,7 @@
1
1
  import React from 'react'
2
2
  import classnames from 'classnames'
3
3
 
4
+ import { buildHtmlProps } from '../../utilities/props'
4
5
  import { GlobalProps, globalProps } from '../../utilities/globalProps'
5
6
 
6
7
  import Card from '../../pb_card/_card'
@@ -10,13 +11,18 @@ export type FilterBackgroundProps = {
10
11
  className?: string,
11
12
  children?: React.ReactChild[] | React.ReactChild,
12
13
  dark?: boolean,
14
+ htmlOptions?: {[key: string]: string | number | boolean | (() => void)},
13
15
  } & GlobalProps
14
16
 
15
17
  const FilterBackground = (props: FilterBackgroundProps): React.ReactElement => {
16
- const { background = true, className, children, dark } = props
18
+ const { background = true, className, children, dark, htmlOptions = {} } = props
19
+ const htmlProps = buildHtmlProps(htmlOptions)
17
20
 
18
21
  return (
19
- <div className={classnames(`pb_filter_kit ${className}`, globalProps(props))}>
22
+ <div
23
+ {...htmlProps}
24
+ className={classnames(`pb_filter_kit ${className}`, globalProps(props))}
25
+ >
20
26
  { background ?
21
27
  <Card
22
28
  dark={dark}
@@ -21,7 +21,7 @@ const nextValue = (value: SortValue[], name: string): SortValue => {
21
21
  }
22
22
 
23
23
  const directionIcon = (dir: Direction) => (
24
- dir == 'asc' ? 'arrow-up-short-wide' : 'arrow-down-wide-short'
24
+ dir == 'asc' ? 'arrow-up-wide-short' : 'arrow-down-short-wide'
25
25
  )
26
26
 
27
27
  const renderOptions = (options: SortOptions, value: SortValue[], handleChange: (arg0: SortValue) => void) => (
@@ -115,9 +115,9 @@ module Playbook
115
115
  def sort_icon(direction)
116
116
  case direction
117
117
  when "asc"
118
- "arrow-up-short-wide"
118
+ "arrow-up-wide-short"
119
119
  when "desc"
120
- "arrow-down-wide-short"
120
+ "arrow-down-short-wide"
121
121
  else
122
122
  ""
123
123
  end
@@ -153,6 +153,20 @@ test("generates quickpick options for interactive dropdown filters", () => {
153
153
  expect(handleChange).toHaveBeenCalledWith("quickpick-last-month");
154
154
  });
155
155
 
156
+ test("applies htmlOptions to the root element", () => {
157
+ render(
158
+ <Filter
159
+ htmlOptions={{ title: "filter title" }}
160
+ results={1}
161
+ />
162
+ );
163
+
164
+ expect(document.querySelector(".pb_filter_kit")).toHaveAttribute(
165
+ "title",
166
+ "filter title"
167
+ );
168
+ });
169
+
156
170
  test("renders double layout when double is true", () => {
157
171
  render(<FilterTest double />);
158
172
 
@@ -2,6 +2,7 @@ import React from 'react'
2
2
  import classnames from 'classnames'
3
3
 
4
4
  import { buildCss, buildDataProps, buildHtmlProps } from '../utilities/props'
5
+ import { globalProps } from '../utilities/globalProps'
5
6
 
6
7
  import Icon from '../pb_icon/_icon'
7
8
 
@@ -32,7 +33,7 @@ const ProgressStepItem = (props: ProgressStepItemProps): React.ReactElement => {
32
33
  <li
33
34
  {...dataProps}
34
35
  {...htmlProps}
35
- className={classnames(progressStepItem, className)}
36
+ className={classnames(progressStepItem, globalProps(props), className)}
36
37
  >
37
38
  <div className="box">
38
39
  <div className="circle">
@@ -108,6 +108,22 @@ test('should render the children elements', () => {
108
108
  expect(step3Kit).toHaveClass('pb_progress_step_item_inactive')
109
109
  })
110
110
 
111
+ test('should apply global props to ProgressStepItem', () => {
112
+ render(
113
+ <ProgressStep>
114
+ <ProgressStepItem
115
+ data={{ testid: step1Id }}
116
+ margin="md"
117
+ status="complete"
118
+ >
119
+ {'Step 1'}
120
+ </ProgressStepItem>
121
+ </ProgressStep>
122
+ )
123
+
124
+ expect(screen.getByTestId(step1Id)).toHaveClass('m_md')
125
+ })
126
+
111
127
  test('should render info color', () => {
112
128
  render(
113
129
  <ProgressStep
@@ -2,6 +2,7 @@ import React from 'react'
2
2
  import classnames from 'classnames'
3
3
 
4
4
  import { buildDataProps, buildAriaProps, buildHtmlProps } from '../utilities/props'
5
+ import { globalProps } from '../utilities/globalProps'
5
6
  import { titleize } from '../utilities/text'
6
7
 
7
8
  import Avatar, { AvatarProps } from '../pb_avatar/_avatar'
@@ -22,23 +23,25 @@ type SourceProps = {
22
23
  user: AvatarProps,
23
24
  }
24
25
 
25
- const Source = ({
26
- aria = {},
27
- className,
28
- data = {},
29
- hideIcon = false,
30
- htmlOptions = {},
31
- id,
32
- source,
33
- type = 'inbound',
34
- user = {},
35
- }: SourceProps): React.ReactElement => {
26
+ const Source = (props: SourceProps): React.ReactElement => {
27
+ const {
28
+ aria = {},
29
+ className,
30
+ data = {},
31
+ hideIcon = false,
32
+ htmlOptions = {},
33
+ id,
34
+ source,
35
+ type = 'inbound',
36
+ user = {},
37
+ } = props
36
38
  const dataProps = buildDataProps(data)
37
39
  const htmlProps = buildHtmlProps(htmlOptions)
38
40
  const ariaProps = buildAriaProps(aria)
39
41
 
40
42
  const css = classnames([
41
43
  'pb_source_kit',
44
+ globalProps(props),
42
45
  className,
43
46
  ])
44
47
 
@@ -80,3 +80,9 @@ test('should pass user prop', () => {
80
80
  kit = screen.getByText(user.userId)
81
81
  expect(kit).toBeInTheDocument()
82
82
  })
83
+
84
+ test('should apply global props to the root element', () => {
85
+ render(<SourceDefault margin="md" />)
86
+ const kit = screen.getByTestId(testId)
87
+ expect(kit).toHaveClass('m_md')
88
+ })
@@ -3972,6 +3972,14 @@
3972
3972
  ],
3973
3973
  "default": false
3974
3974
  },
3975
+ "closeOnSelect": {
3976
+ "type": "boolean",
3977
+ "platforms": [
3978
+ "react",
3979
+ "rails"
3980
+ ],
3981
+ "default": true
3982
+ },
3975
3983
  "customQuickPickDates": {
3976
3984
  "type": "GenericObject",
3977
3985
  "platforms": [
data/dist/ai/forms.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "metadataVersion": 1,
3
- "version": "18.1.0-rc.2",
3
+ "version": "18.1.0-rc.4",
4
4
  "builder": {
5
5
  "class": "Playbook::Forms::Builder",
6
6
  "helper": "pb_form_with",
data/dist/ai/index.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
- "version": "18.1.0-rc.2",
2
+ "version": "18.1.0-rc.4",
3
3
  "metadataVersion": 1,
4
4
  "forms": "forms.json",
5
- "generated": "2026-09-29T19:21:09.246Z",
5
+ "generated": "2026-10-02T20:48:38.790Z",
6
6
  "schemas": {
7
7
  "globalProps": "global-props.schema.json",
8
8
  "globalEventProps": "global-event-props.schema.json",
@@ -15,6 +15,14 @@
15
15
  ],
16
16
  "default": false
17
17
  },
18
+ "closeOnSelect": {
19
+ "type": "boolean",
20
+ "platforms": [
21
+ "react",
22
+ "rails"
23
+ ],
24
+ "default": true
25
+ },
18
26
  "customQuickPickDates": {
19
27
  "type": "GenericObject",
20
28
  "platforms": [