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.
- checksums.yaml +4 -4
- data/app/pb_kits/playbook/pb_background/_background.tsx +4 -1
- data/app/pb_kits/playbook/pb_background/background.test.js +23 -1
- data/app/pb_kits/playbook/pb_filter/Filter/FilterResponsive.tsx +116 -0
- data/app/pb_kits/playbook/pb_filter/Filter/index.tsx +48 -6
- data/app/pb_kits/playbook/pb_filter/_filter.scss +127 -0
- data/app/pb_kits/playbook/pb_filter/_filter.tsx +1 -0
- data/app/pb_kits/playbook/pb_filter/docs/_filter_responsive.html.erb +42 -0
- data/app/pb_kits/playbook/pb_filter/docs/_filter_responsive.jsx +76 -0
- data/app/pb_kits/playbook/pb_filter/docs/_filter_responsive.md +3 -0
- data/app/pb_kits/playbook/pb_filter/docs/_playground.json +2 -0
- data/app/pb_kits/playbook/pb_filter/docs/_playground.overrides.json +2 -0
- data/app/pb_kits/playbook/pb_filter/docs/example.yml +2 -0
- data/app/pb_kits/playbook/pb_filter/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_filter/filter.html.erb +139 -97
- data/app/pb_kits/playbook/pb_filter/filter.rb +21 -1
- data/app/pb_kits/playbook/pb_filter/filter.test.js +64 -0
- data/app/pb_kits/playbook/pb_filter/kit.schema.json +13 -2
- data/app/pb_kits/playbook/pb_pill/_pill.test.jsx +43 -0
- data/app/pb_kits/playbook/pb_pill/_pill.tsx +12 -6
- data/app/pb_kits/playbook/pb_pill/docs/_pill_children.html.erb +9 -0
- data/app/pb_kits/playbook/pb_pill/docs/_pill_children.jsx +45 -0
- data/app/pb_kits/playbook/pb_pill/docs/_pill_children.md +1 -0
- data/app/pb_kits/playbook/pb_pill/docs/_playground.json +14 -1
- data/app/pb_kits/playbook/pb_pill/docs/_playground.overrides.json +17 -0
- data/app/pb_kits/playbook/pb_pill/docs/example.yml +2 -0
- data/app/pb_kits/playbook/pb_pill/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_pill/pill.html.erb +5 -1
- data/app/pb_kits/playbook/pb_table/_table.tsx +1 -1
- data/app/pb_kits/playbook/pb_table/docs/_table_header.jsx +193 -0
- data/app/pb_kits/playbook/pb_table/docs/{_table_header.md → _table_header_rails.md} +5 -3
- data/app/pb_kits/playbook/pb_table/docs/_table_header_react.md +15 -0
- data/app/pb_kits/playbook/pb_table/docs/_table_responsive_table.html.erb +75 -0
- data/app/pb_kits/playbook/pb_table/docs/_table_responsive_table.jsx +80 -0
- data/app/pb_kits/playbook/pb_table/docs/_table_responsive_table_rails.md +5 -0
- data/app/pb_kits/playbook/pb_table/docs/_table_responsive_table_react.md +5 -0
- data/app/pb_kits/playbook/pb_table/docs/example.yml +1 -0
- data/app/pb_kits/playbook/pb_table/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_table/subcomponents/_table_header.tsx +143 -12
- data/app/pb_kits/playbook/pb_table/table.rb +1 -1
- data/app/pb_kits/playbook/pb_table/table.test.js +134 -1
- data/app/pb_kits/playbook/pb_table/utilities/sortMenuHelpers.test.ts +76 -0
- data/app/pb_kits/playbook/pb_table/utilities/sortMenuHelpers.ts +84 -0
- data/dist/ai/all-schemas.json +11 -0
- data/dist/ai/forms.json +1 -1
- data/dist/ai/index.json +2 -2
- data/dist/ai/kits/filter.schema.json +11 -0
- data/dist/ai/playgrounds/index.json +1 -1
- data/dist/ai/playgrounds/pill.json +1 -1
- data/dist/ai/visual-index.json +1 -1
- data/dist/chunks/{_detail-Cy2bFz4f.js → _detail-BqqzPTNr.js} +2 -2
- data/dist/chunks/_table-BGTSSDK1.js +1 -0
- data/dist/chunks/_typeahead-KNcX62pc.js +1 -0
- data/dist/chunks/vendor.js +3 -3
- data/dist/playbook-rails-react-bindings.js +1 -1
- data/dist/playbook-rails.js +1 -1
- data/dist/playbook.css +1 -1
- data/lib/playbook/changelog_generator.rb +12 -3
- data/lib/playbook/version.rb +1 -1
- metadata +19 -6
- data/dist/chunks/_table-CZFM253V.js +0 -1
- data/dist/chunks/_typeahead-BiNcC1AJ.js +0 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 69806745bf9d406cc340a98ebaa54bbab8fd00312d756cd0bf60e3077db5794e
|
|
4
|
+
data.tar.gz: 0aef11e0e9dc51c336af96739287476e8b01e8397c2580cfff87d8ef0a17a7eb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
-
//
|
|
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
|
|
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
|
|
41
|
+
<FilterSidebar
|
|
42
|
+
className={className}
|
|
43
|
+
{...layoutProps}
|
|
44
|
+
>
|
|
45
|
+
{children}
|
|
46
|
+
</FilterSidebar>
|
|
25
47
|
)
|
|
26
48
|
}
|
|
27
|
-
if (
|
|
49
|
+
if (useResponsiveStacked) {
|
|
28
50
|
return (
|
|
29
|
-
<
|
|
51
|
+
<FilterResponsive
|
|
52
|
+
{...layoutProps}
|
|
53
|
+
className={mergedClassName}
|
|
54
|
+
>
|
|
55
|
+
{children}
|
|
56
|
+
</FilterResponsive>
|
|
30
57
|
)
|
|
31
|
-
}
|
|
58
|
+
}
|
|
59
|
+
if (double === true) {
|
|
32
60
|
return (
|
|
33
|
-
<
|
|
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'
|