playbook_ui 18.1.0.pre.rc.1 → 18.1.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 (62) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/pb_background/_background.tsx +4 -1
  3. data/app/pb_kits/playbook/pb_background/background.test.js +23 -1
  4. data/app/pb_kits/playbook/pb_filter/Filter/FilterResponsive.tsx +116 -0
  5. data/app/pb_kits/playbook/pb_filter/Filter/index.tsx +48 -6
  6. data/app/pb_kits/playbook/pb_filter/_filter.scss +127 -0
  7. data/app/pb_kits/playbook/pb_filter/_filter.tsx +1 -0
  8. data/app/pb_kits/playbook/pb_filter/docs/_filter_responsive.html.erb +42 -0
  9. data/app/pb_kits/playbook/pb_filter/docs/_filter_responsive.jsx +76 -0
  10. data/app/pb_kits/playbook/pb_filter/docs/_filter_responsive.md +3 -0
  11. data/app/pb_kits/playbook/pb_filter/docs/_playground.json +2 -0
  12. data/app/pb_kits/playbook/pb_filter/docs/_playground.overrides.json +2 -0
  13. data/app/pb_kits/playbook/pb_filter/docs/example.yml +2 -0
  14. data/app/pb_kits/playbook/pb_filter/docs/index.js +1 -0
  15. data/app/pb_kits/playbook/pb_filter/filter.html.erb +139 -97
  16. data/app/pb_kits/playbook/pb_filter/filter.rb +21 -1
  17. data/app/pb_kits/playbook/pb_filter/filter.test.js +64 -0
  18. data/app/pb_kits/playbook/pb_filter/kit.schema.json +13 -2
  19. data/app/pb_kits/playbook/pb_pill/_pill.test.jsx +43 -0
  20. data/app/pb_kits/playbook/pb_pill/_pill.tsx +12 -6
  21. data/app/pb_kits/playbook/pb_pill/docs/_pill_children.html.erb +9 -0
  22. data/app/pb_kits/playbook/pb_pill/docs/_pill_children.jsx +45 -0
  23. data/app/pb_kits/playbook/pb_pill/docs/_pill_children.md +1 -0
  24. data/app/pb_kits/playbook/pb_pill/docs/_playground.json +14 -1
  25. data/app/pb_kits/playbook/pb_pill/docs/_playground.overrides.json +17 -0
  26. data/app/pb_kits/playbook/pb_pill/docs/example.yml +2 -0
  27. data/app/pb_kits/playbook/pb_pill/docs/index.js +1 -0
  28. data/app/pb_kits/playbook/pb_pill/pill.html.erb +5 -1
  29. data/app/pb_kits/playbook/pb_table/_table.tsx +1 -1
  30. data/app/pb_kits/playbook/pb_table/docs/_table_header.jsx +193 -0
  31. data/app/pb_kits/playbook/pb_table/docs/{_table_header.md → _table_header_rails.md} +5 -3
  32. data/app/pb_kits/playbook/pb_table/docs/_table_header_react.md +15 -0
  33. data/app/pb_kits/playbook/pb_table/docs/_table_responsive_table.html.erb +75 -0
  34. data/app/pb_kits/playbook/pb_table/docs/_table_responsive_table.jsx +80 -0
  35. data/app/pb_kits/playbook/pb_table/docs/_table_responsive_table_rails.md +5 -0
  36. data/app/pb_kits/playbook/pb_table/docs/_table_responsive_table_react.md +5 -0
  37. data/app/pb_kits/playbook/pb_table/docs/example.yml +1 -0
  38. data/app/pb_kits/playbook/pb_table/docs/index.js +1 -0
  39. data/app/pb_kits/playbook/pb_table/subcomponents/_table_header.tsx +143 -12
  40. data/app/pb_kits/playbook/pb_table/table.rb +1 -1
  41. data/app/pb_kits/playbook/pb_table/table.test.js +134 -1
  42. data/app/pb_kits/playbook/pb_table/utilities/sortMenuHelpers.test.ts +76 -0
  43. data/app/pb_kits/playbook/pb_table/utilities/sortMenuHelpers.ts +84 -0
  44. data/dist/ai/all-schemas.json +11 -0
  45. data/dist/ai/forms.json +1 -1
  46. data/dist/ai/index.json +2 -2
  47. data/dist/ai/kits/filter.schema.json +11 -0
  48. data/dist/ai/playgrounds/index.json +1 -1
  49. data/dist/ai/playgrounds/pill.json +1 -1
  50. data/dist/ai/visual-index.json +1 -1
  51. data/dist/chunks/{_detail-Cy2bFz4f.js → _detail-BqqzPTNr.js} +2 -2
  52. data/dist/chunks/_table-BGTSSDK1.js +1 -0
  53. data/dist/chunks/_typeahead-KNcX62pc.js +1 -0
  54. data/dist/chunks/vendor.js +3 -3
  55. data/dist/playbook-rails-react-bindings.js +1 -1
  56. data/dist/playbook-rails.js +1 -1
  57. data/dist/playbook.css +1 -1
  58. data/lib/playbook/changelog_generator.rb +12 -3
  59. data/lib/playbook/version.rb +1 -1
  60. metadata +19 -6
  61. data/dist/chunks/_table-CZFM253V.js +0 -1
  62. data/dist/chunks/_typeahead-BiNcC1AJ.js +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8885b14507b1ffa09091188f028bc63097b1d187eae55a40673ac13a0a8d67c1
4
- data.tar.gz: b5266d626ee2c9c069c5e18f7bf9b55c7e62d04f394645c1babca4bf7f1f0bf0
3
+ metadata.gz: 69806745bf9d406cc340a98ebaa54bbab8fd00312d756cd0bf60e3077db5794e
4
+ data.tar.gz: 0aef11e0e9dc51c336af96739287476e8b01e8397c2580cfff87d8ef0a17a7eb
5
5
  SHA512:
6
- metadata.gz: 641e3a2789ab3416e5f5f594c0c33fe31510e55750c4d1432b9acfa35a9f5f50529e1eb1663244c4faefbd353ebf15731f470c457fe365954125bd18c7e55183
7
- data.tar.gz: 90781fad9169b4c1a23c078ec59a38448562d6cee63811282cbddb011a9269ac177bf5435472d2164aeebe2c36139e0d3763cf52539a03aee3865c54c409fa46
6
+ metadata.gz: 590f41d6ac3e5304ad388114c1a0a0264df448ef4e4df753a4e06058c4a80bae552f5aefb78f768ff257073694dcc9433fd697520a7603d7d2ce5b4b314fd5c5
7
+ data.tar.gz: 4dd0fe2434dc65fd2a2eab892ffd571d6c6f2fcf9d7ea72e5fb83da7d5f5cf44ccaf5c2e579765c2886092779b4b5c7de0007da7a12cc49998c23ca253815208
@@ -98,7 +98,7 @@ const Background = (props: BackgroundProps): React.ReactElement => {
98
98
  imageUrl: getResponsiveValue(imageUrl),
99
99
  });
100
100
 
101
- // Update responsive values on window resize.
101
+ // Keep responsive values in sync when props change, and on window resize.
102
102
  useEffect(() => {
103
103
  const updateResponsiveProps = () => {
104
104
  setResponsiveProps({
@@ -109,6 +109,7 @@ const Background = (props: BackgroundProps): React.ReactElement => {
109
109
  imageUrl: getResponsiveValue(imageUrl),
110
110
  });
111
111
  };
112
+ updateResponsiveProps();
112
113
  window.addEventListener('resize', updateResponsiveProps);
113
114
  return () => window.removeEventListener('resize', updateResponsiveProps);
114
115
  }, [backgroundSize, backgroundPosition, backgroundRepeat, backgroundColor, imageUrl]);
@@ -153,6 +154,8 @@ const Background = (props: BackgroundProps): React.ReactElement => {
153
154
  ...dynamicInlineProps
154
155
  };
155
156
 
157
+ // Dynamic HTML tag from props; matches other kits (Title, Collapsible, etc.).
158
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
156
159
  const Tag: React.ReactElement | any = `${tag}`;
157
160
  const ariaProps = buildAriaProps(aria);
158
161
  const dataProps = buildDataProps(data);
@@ -1,4 +1,5 @@
1
- import { ensureAccessible, renderKit } from '../utilities/test-utils'
1
+ import React from 'react'
2
+ import { ensureAccessible, render, renderKit } from '../utilities/test-utils'
2
3
 
3
4
  import Background from './_background'
4
5
 
@@ -20,6 +21,27 @@ test('backgroundColor = category_1', () => {
20
21
  expect(kit).toHaveClass('pb_background_kit pb_background_color_category_1')
21
22
  })
22
23
 
24
+ test('updates backgroundColor class when the prop changes', () => {
25
+ const { getByTestId, rerender } = render(
26
+ <Background
27
+ backgroundColor="info_subtle"
28
+ data={{ testid: 'background' }}
29
+ />
30
+ )
31
+
32
+ expect(getByTestId('background')).toHaveClass('pb_background_color_info_subtle')
33
+
34
+ rerender(
35
+ <Background
36
+ backgroundColor="card_light"
37
+ data={{ testid: 'background' }}
38
+ />
39
+ )
40
+
41
+ expect(getByTestId('background')).toHaveClass('pb_background_color_card_light')
42
+ expect(getByTestId('background')).not.toHaveClass('pb_background_color_info_subtle')
43
+ })
44
+
23
45
  test('customColor prop styles background color with a hex value', () => {
24
46
  const kit = renderKit(Background, props, { customColor: '#1d99a8' })
25
47
 
@@ -0,0 +1,116 @@
1
+ import React from 'react'
2
+ import { isEmpty } from '../../utilities/object'
3
+
4
+ import CurrentFilters, { FilterDescription, InteractiveFilters } from './CurrentFilters'
5
+ import FilterBackground, { FilterBackgroundProps } from './FilterBackground'
6
+ import FiltersPopover from './FiltersPopover'
7
+ import ResultsCount from './ResultsCount'
8
+ import SortMenu, {
9
+ SortingChangeCallback,
10
+ SortOptions,
11
+ SortValue,
12
+ } from './SortMenu'
13
+
14
+ import Caption from '../../pb_caption/_caption'
15
+ import SectionSeparator from '../../pb_section_separator/_section_separator'
16
+
17
+ export type FilterResponsiveProps = {
18
+ children?: React.ReactChild[] | React.ReactChild,
19
+ filters?: FilterDescription,
20
+ interactiveFilters?: InteractiveFilters,
21
+ onSortChange?: SortingChangeCallback,
22
+ results?: number,
23
+ sortOptions?: SortOptions,
24
+ sortValue?: SortValue[],
25
+ } & FilterBackgroundProps
26
+
27
+ // One tree for responsive="stacked": CSS grid (shared with Rails) toggles
28
+ // one-row vs two-row chrome without remounting across the breakpoint.
29
+ // Stacked bottom reuses `.filter-bottom` (via `.pb_filter_responsive_bottom`)
30
+ // so Results/Sort match FilterDouble sizing.
31
+ const FilterResponsive = ({
32
+ children,
33
+ dark,
34
+ filters,
35
+ interactiveFilters,
36
+ maxHeight,
37
+ minWidth,
38
+ onSortChange,
39
+ placement,
40
+ popoverProps,
41
+ results,
42
+ sortOptions,
43
+ sortValue,
44
+ ...bgProps
45
+ }: FilterResponsiveProps): React.ReactElement => {
46
+ const showSort = !isEmpty(sortOptions)
47
+
48
+ return (
49
+ <FilterBackground
50
+ dark={dark}
51
+ {...bgProps}
52
+ >
53
+ <div className="pb_filter_responsive_layout">
54
+ <div className="pb_filter_responsive_filters">
55
+ {children &&
56
+ <FiltersPopover
57
+ dark={dark}
58
+ maxHeight={maxHeight}
59
+ minWidth={minWidth}
60
+ placement={placement}
61
+ popoverProps={popoverProps}
62
+ >
63
+ {children}
64
+ </FiltersPopover>
65
+ }
66
+ <CurrentFilters
67
+ dark={dark}
68
+ filters={filters}
69
+ interactiveFilters={interactiveFilters}
70
+ />
71
+ </div>
72
+
73
+ <div className="pb_filter_responsive_results_inline">
74
+ <ResultsCount
75
+ dark={dark}
76
+ results={results}
77
+ />
78
+ </div>
79
+
80
+ <div className="pb_filter_responsive_sep">
81
+ <SectionSeparator dark={dark} />
82
+ </div>
83
+
84
+ <div className="pb_filter_responsive_bottom filter-bottom">
85
+ <div className="pb_filter_responsive_results_bar">
86
+ <ResultsCount
87
+ dark={dark}
88
+ results={results}
89
+ title
90
+ />
91
+ </div>
92
+
93
+ <div className="pb_filter_responsive_sort">
94
+ {showSort &&
95
+ <>
96
+ <Caption
97
+ className="pb_filter_responsive_sort_label"
98
+ dark={dark}
99
+ text="sort by:"
100
+ />
101
+ <SortMenu
102
+ dark={dark}
103
+ onChange={onSortChange}
104
+ options={sortOptions}
105
+ value={sortValue}
106
+ />
107
+ </>
108
+ }
109
+ </div>
110
+ </div>
111
+ </div>
112
+ </FilterBackground>
113
+ )
114
+ }
115
+
116
+ export default FilterResponsive
@@ -1,13 +1,20 @@
1
1
  import React from 'react'
2
+ import classnames from 'classnames'
3
+
2
4
  import FilterSingle, { FilterSingleProps } from './FilterSingle'
3
5
  import FilterDouble, { FilterDoubleProps } from './FilterDouble'
6
+ import FilterResponsive from './FilterResponsive'
4
7
  import FilterSidebar, { FilterSidebarProps } from './FilterSidebar'
5
8
  import FilterSection from './FilterSection'
6
9
 
7
10
  type FilterProps =
8
- | FilterSingleProps
11
+ | (FilterSingleProps & {
12
+ double?: boolean,
13
+ responsive?: 'stacked',
14
+ })
9
15
  | (FilterDoubleProps & {
10
16
  double?: boolean,
17
+ responsive?: 'stacked',
11
18
  })
12
19
  | (FilterSidebarProps & {
13
20
  variant?: null | 'sidebar',
@@ -15,25 +22,60 @@ type FilterProps =
15
22
 
16
23
  const Filter = ({
17
24
  double = false,
25
+ responsive,
18
26
  variant,
19
27
  ...templateProps
20
28
  }: FilterProps): React.ReactElement => {
29
+ const { children, className, ...layoutProps } = templateProps
30
+ // Match Rails: stacked only for default/single (has filter children).
31
+ // Sort-only (no children) stays on FilterSingle.
32
+ const useResponsiveStacked = responsive === 'stacked' && Boolean(children)
33
+ const mergedClassName = classnames(
34
+ useResponsiveStacked && 'pb_filter_responsive',
35
+ className,
36
+ )
37
+
21
38
  const displayFilter = () => {
22
39
  if (variant === 'sidebar') {
23
40
  return (
24
- <FilterSidebar {...templateProps} />
41
+ <FilterSidebar
42
+ className={className}
43
+ {...layoutProps}
44
+ >
45
+ {children}
46
+ </FilterSidebar>
25
47
  )
26
48
  }
27
- if (double === true) {
49
+ if (useResponsiveStacked) {
28
50
  return (
29
- <FilterDouble {...templateProps} />
51
+ <FilterResponsive
52
+ {...layoutProps}
53
+ className={mergedClassName}
54
+ >
55
+ {children}
56
+ </FilterResponsive>
30
57
  )
31
- } else {
58
+ }
59
+ if (double === true) {
32
60
  return (
33
- <FilterSingle {...templateProps} />
61
+ <FilterDouble
62
+ {...layoutProps}
63
+ className={className}
64
+ >
65
+ {children}
66
+ </FilterDouble>
34
67
  )
35
68
  }
69
+ return (
70
+ <FilterSingle
71
+ {...layoutProps}
72
+ className={className}
73
+ >
74
+ {children}
75
+ </FilterSingle>
76
+ )
36
77
  }
78
+
37
79
  return (
38
80
  <>
39
81
  {displayFilter()}
@@ -1,6 +1,7 @@
1
1
  @import "../tokens/spacing";
2
2
  @import "../tokens/colors";
3
3
  @import "../tokens/border_radius";
4
+ @import "../tokens/screen_sizes";
4
5
 
5
6
  .pb_filter_sort_menu {
6
7
  li {
@@ -124,6 +125,132 @@
124
125
  opacity:0;
125
126
  }
126
127
  }
128
+
129
+ &.pb_filter_responsive {
130
+ overflow: hidden;
131
+
132
+ .maskContainer {
133
+ flex: 1 1 auto;
134
+ min-width: 0;
135
+ position: relative;
136
+ }
137
+
138
+ .filters {
139
+ -webkit-overflow-scrolling: touch;
140
+ scrollbar-width: none;
141
+ }
142
+
143
+ .maskContainer::after {
144
+ background: linear-gradient(to right, rgba($white, 0), $white 65%);
145
+ content: "";
146
+ height: 100%;
147
+ margin: 0;
148
+ padding: 0;
149
+ pointer-events: none;
150
+ position: absolute;
151
+ right: 0;
152
+ top: 0;
153
+ width: $space_xl + $space_sm;
154
+ z-index: 1;
155
+ }
156
+
157
+ .maskContainer::before {
158
+ display: none;
159
+ }
160
+
161
+ .pb_filter_responsive_layout {
162
+ align-items: center;
163
+ column-gap: $space_xs;
164
+ display: grid;
165
+ grid-template-areas: "filters results-inline sort";
166
+ grid-template-columns: minmax(0, 1fr) auto auto;
167
+ padding-right: $space_lg;
168
+ width: 100%;
169
+ }
170
+
171
+ .pb_filter_responsive_filters {
172
+ align-items: center;
173
+ display: flex;
174
+ grid-area: filters;
175
+ min-width: 0;
176
+ }
177
+
178
+ .pb_filter_responsive_results_inline {
179
+ grid-area: results-inline;
180
+ flex-shrink: 0;
181
+ }
182
+
183
+ .pb_filter_responsive_sep {
184
+ display: none;
185
+ grid-area: sep;
186
+ }
187
+
188
+ // Wide: contents so `sort` still occupies the one-row grid area.
189
+ // Stacked: becomes the FilterDouble bottom bar (see break_at below).
190
+ .pb_filter_responsive_bottom {
191
+ display: contents;
192
+ }
193
+
194
+ .pb_filter_responsive_results_bar {
195
+ display: none;
196
+ }
197
+
198
+ .pb_filter_responsive_sort {
199
+ align-items: center;
200
+ display: flex;
201
+ flex-shrink: 0;
202
+ grid-area: sort;
203
+ gap: $space_xs;
204
+ }
205
+
206
+ .pb_filter_responsive_sort_label {
207
+ display: none;
208
+ }
209
+
210
+ @include break_at($screen-md-max) {
211
+ .pb_filter_responsive_layout {
212
+ align-items: center;
213
+ grid-template-areas:
214
+ "filters"
215
+ "sep"
216
+ "bottom";
217
+ grid-template-columns: minmax(0, 1fr);
218
+ padding-right: 0;
219
+ row-gap: 0;
220
+ }
221
+
222
+ .pb_filter_responsive_results_inline {
223
+ display: none;
224
+ }
225
+
226
+ .pb_filter_responsive_sep {
227
+ display: block;
228
+ }
229
+
230
+ .pb_filter_responsive_bottom {
231
+ align-items: center;
232
+ display: flex;
233
+ grid-area: bottom;
234
+ justify-content: space-between;
235
+ }
236
+
237
+ .pb_filter_responsive_results_bar {
238
+ align-items: center;
239
+ display: flex;
240
+ }
241
+
242
+ .pb_filter_responsive_sort_label {
243
+ display: revert;
244
+ }
245
+ }
246
+ }
247
+
248
+ &.pb_filter_responsive.dark {
249
+ .maskContainer::after {
250
+ background: linear-gradient(to right, rgba($card_dark, 0), $card_dark 65%);
251
+ opacity: 1;
252
+ }
253
+ }
127
254
  }
128
255
 
129
256
  .pb_popover_tooltip.pb_interactive_filter_editor {
@@ -19,6 +19,7 @@ export type FilterProps = {
19
19
  onSortChange?: (value: SortValue[]) => void,
20
20
  placement?: "top" | "bottom" | "left" | "right" | "top-start" | "top-end" | "bottom-start" | "bottom-end" | "right-start" | "right-end" | "left-start" | "left-end",
21
21
  popoverProps?: Record<string, unknown>,
22
+ responsive?: "stacked",
22
23
  results?: number,
23
24
  sortOptions?: Record<string, unknown>,
24
25
  sortValue?: SortValue[],
@@ -0,0 +1,42 @@
1
+ <%=
2
+ pb_rails("filter", props: {
3
+ id: "filter-responsive",
4
+ min_width: "360px",
5
+ responsive: "stacked",
6
+ filters: [
7
+ { name: "Full Name", value: "John Wick" },
8
+ { name: "City", value: "San Francisco" },
9
+ { name: "Territory", value: "Pacific Northwest" },
10
+ { name: "Status", value: "Active" },
11
+ { name: "Role", value: "Manager" },
12
+ ],
13
+ sort_menu: [
14
+ { item: "Popularity", link: "?q[sorts]=managers_popularity+asc", active: true, direction: "desc" },
15
+ { item: "Manager's Title", link: "?q[sorts]=managers_title+asc", active: false },
16
+ { item: "Manager's Name", link: "?q[sorts]=managers_name+asc", active: false },
17
+ ],
18
+ template: "single",
19
+ results: 546,
20
+ }) do
21
+ %>
22
+ <%
23
+ example_collection = [
24
+ OpenStruct.new(name: "USA", value: 1),
25
+ OpenStruct.new(name: "Canada", value: 2),
26
+ OpenStruct.new(name: "Brazil", value: 3),
27
+ OpenStruct.new(name: "Philippines", value: 4),
28
+ ]
29
+ %>
30
+ <%= pb_rails("form", props: { form_system_options: { scope: :example, method: :get } }) do |form| %>
31
+ <%= form.text_field :example_text_field, props: { label: true } %>
32
+ <%= form.collection_select :example_collection_select, example_collection, :value, :name, props: { label: true } %>
33
+ <%= form.actions do |action| %>
34
+ <%= action.submit props: {
35
+ text: "Apply",
36
+ data: {
37
+ disable_with: "pb_rails('icon', props: { icon: 'spinner', spin: true, fixed_width: true })Searching...".html_safe
38
+ },}%>
39
+ <%= action.button props: { type: "reset", text: "Clear", variant: "secondary" } %>
40
+ <% end %>
41
+ <% end %>
42
+ <% end %>
@@ -0,0 +1,76 @@
1
+ import React from 'react'
2
+
3
+ import Filter from '../_filter'
4
+
5
+ import Button from '../../pb_button/_button'
6
+ import Flex from '../../pb_flex/_flex'
7
+ import Select from '../../pb_select/_select'
8
+ import TextInput from '../../pb_text_input/_text_input'
9
+
10
+ const FilterResponsive = (props) => {
11
+ const options = [
12
+ { value: 'USA' },
13
+ { value: 'Canada' },
14
+ { value: 'Brazil' },
15
+ { value: 'Philippines' },
16
+ { value: 'A galaxy far far away...' },
17
+ ]
18
+
19
+ return (
20
+ <Filter
21
+ filters={{
22
+ 'Full Name': 'John Wick',
23
+ 'City': 'San Francisco',
24
+ 'Territory': 'Pacific Northwest',
25
+ 'Status': 'Active',
26
+ 'Role': 'Manager',
27
+ }}
28
+ minWidth="360px"
29
+ responsive="stacked"
30
+ results={546}
31
+ sortOptions={{
32
+ popularity: 'Popularity',
33
+ // eslint-disable-next-line
34
+ manager_title: 'Manager\'s Title',
35
+ // eslint-disable-next-line
36
+ manager_name: 'Manager\'s Name',
37
+ }}
38
+ sortValue={[{ name: 'popularity', dir: 'desc' }]}
39
+ {...props}
40
+ >
41
+ {({ closePopover }) => (
42
+ <form>
43
+ <TextInput
44
+ label="Full Name"
45
+ placeholder="Enter name"
46
+ {...props}
47
+ />
48
+ <Select
49
+ blankSelection="Select One..."
50
+ label="Territory"
51
+ name="location"
52
+ options={options}
53
+ {...props}
54
+ />
55
+ <Flex
56
+ spacing="between"
57
+ {...props}
58
+ >
59
+ <Button
60
+ onClick={closePopover}
61
+ text="Apply"
62
+ {...props}
63
+ />
64
+ <Button
65
+ text="Clear"
66
+ variant="secondary"
67
+ {...props}
68
+ />
69
+ </Flex>
70
+ </form>
71
+ )}
72
+ </Filter>
73
+ )
74
+ }
75
+
76
+ export default FilterResponsive
@@ -0,0 +1,3 @@
1
+ Use `responsive="stacked"` (React) or `responsive: "stacked"` (Rails) to use the two-row layout below `767px` and the one-row layout above.
2
+
3
+ When set, `responsive` controls the layout (`double` / `template` are ignored for the default and single layouts). `filter_only` and `sort_only` are unchanged. Both platforms keep one DOM tree and switch chrome with CSS, so resizing does not remount the filter UI.
@@ -14,6 +14,7 @@
14
14
  "onCollapse": "() => {}",
15
15
  "onSortChange": "() => {}",
16
16
  "popoverProps": {},
17
+ "responsive": "",
17
18
  "results": 546,
18
19
  "sortOptions": {
19
20
  "popularity": "Popularity",
@@ -32,6 +33,7 @@
32
33
  "name": "Layout",
33
34
  "props": [
34
35
  "double",
36
+ "responsive",
35
37
  "variant",
36
38
  "background",
37
39
  "results"
@@ -62,6 +62,7 @@
62
62
  "onSortChange": "() => {}",
63
63
  "placement": "bottom-start",
64
64
  "popoverProps": {},
65
+ "responsive": "",
65
66
  "results": 546,
66
67
  "sortOptions": {
67
68
  "popularity": "Popularity",
@@ -80,6 +81,7 @@
80
81
  "name": "Layout",
81
82
  "props": [
82
83
  "double",
84
+ "responsive",
83
85
  "variant",
84
86
  "background",
85
87
  "results"
@@ -11,6 +11,7 @@ examples:
11
11
  - filter_max_height: Max Height for Popover Inside of Filter
12
12
  - filter_placement: Filter Placement
13
13
  - filter_popover_props: Popover Props
14
+ - filter_responsive: Responsive
14
15
  - filter_within_turbo_frames: Within Turbo Frames
15
16
  - filter_interactive: Interactive Applied Filters
16
17
 
@@ -25,6 +26,7 @@ examples:
25
26
  - filter_max_height: Max Height for Popover Inside of Filter
26
27
  - filter_placement: Filter Placement
27
28
  - filter_popover_props: Popover Props
29
+ - filter_responsive: Responsive
28
30
  - filter_sidebar: Sidebar
29
31
  - filter_interactive_react: Interactive Applied Filters
30
32
 
@@ -8,5 +8,6 @@ export { default as FilterMaxWidth } from './_filter_max_width.jsx'
8
8
  export { default as FilterMaxHeight } from './_filter_max_height.jsx'
9
9
  export { default as FilterPlacement } from './_filter_placement.jsx'
10
10
  export { default as FilterPopoverProps } from './_filter_popover_props.jsx'
11
+ export { default as FilterResponsive } from './_filter_responsive.jsx'
11
12
  export { default as FilterSidebar } from './_filter_sidebar.jsx'
12
13
  export { default as FilterInteractiveReact } from './_filter_interactive_react.jsx'