@scottish-government/designsystem-react 0.10.2 → 0.12.0
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.
- package/@types/components/Accordion.d.ts +3 -2
- package/@types/components/ButtonGroup.d.ts +5 -0
- package/@types/components/PageHeader.d.ts +2 -1
- package/@types/components/RadioButton.d.ts +2 -2
- package/@types/components/SearchFacets.d.ts +18 -0
- package/@types/components/SearchFilters.d.ts +14 -0
- package/@types/components/SearchResult.d.ts +30 -0
- package/@types/components/SearchSort.d.ts +9 -0
- package/@types/components/SideNavigation.d.ts +1 -1
- package/CHANGELOG.md +39 -5
- package/dist/common/AbstractNotificationBanner.d.ts +9 -0
- package/dist/common/ActionLink.d.ts +5 -0
- package/dist/common/ConditionalWrapper.d.ts +8 -0
- package/dist/common/FileIcon.d.ts +6 -0
- package/dist/common/HintText.d.ts +5 -0
- package/dist/common/Icon.d.ts +6 -0
- package/dist/common/ScreenReaderText.d.ts +5 -0
- package/dist/common/WrapperTag.d.ts +8 -0
- package/dist/components/Accordion/Accordion.d.ts +10 -0
- package/dist/components/Accordion/Accordion.jsx +8 -3
- package/dist/components/AspectBox/AspectBox.d.ts +6 -0
- package/dist/components/BackToTop/BackToTop.d.ts +5 -0
- package/dist/components/Breadcrumbs/Breadcrumbs.d.ts +9 -0
- package/dist/components/Button/Button.d.ts +5 -0
- package/dist/components/ButtonGroup/ButtonGroup.d.ts +5 -0
- package/dist/components/ButtonGroup/ButtonGroup.jsx +13 -0
- package/dist/components/CategoryItem/CategoryItem.d.ts +5 -0
- package/dist/components/CategoryList/CategoryList.d.ts +6 -0
- package/dist/components/Checkbox/Checkbox.d.ts +5 -0
- package/dist/components/Checkbox/CheckboxGroup.d.ts +6 -0
- package/dist/components/ConfirmationMessage/ConfirmationMessage.d.ts +5 -0
- package/dist/components/ContentsNav/ContentsNav.d.ts +10 -0
- package/dist/components/CookieBanner/CookieBanner.d.ts +9 -0
- package/dist/components/DatePicker/DatePicker.d.ts +5 -0
- package/dist/components/Details/Details.d.ts +5 -0
- package/dist/components/ErrorMessage/ErrorMessage.d.ts +5 -0
- package/dist/components/ErrorSummary/ErrorSummary.d.ts +9 -0
- package/dist/components/FileDownload/FileDownload.d.ts +5 -0
- package/dist/components/HideThisPage/HideThisPage.d.ts +6 -0
- package/dist/components/InsetText/InsetText.d.ts +5 -0
- package/dist/components/NotificationBanner/NotificationBanner.d.ts +9 -0
- package/dist/components/NotificationPanel/NotificationPanel.d.ts +5 -0
- package/dist/components/PageHeader/PageHeader.d.ts +5 -0
- package/dist/components/PageHeader/PageHeader.jsx +2 -2
- package/dist/components/PageMetadata/PageMetadata.d.ts +9 -0
- package/dist/components/Pagination/Pagination.d.ts +7 -0
- package/dist/components/PhaseBanner/PhaseBanner.d.ts +5 -0
- package/dist/components/Question/Question.d.ts +5 -0
- package/dist/components/RadioButton/RadioButton.d.ts +5 -0
- package/dist/components/RadioButton/RadioGroup.d.ts +6 -0
- package/dist/components/RadioButton/RadioGroup.jsx +1 -1
- package/dist/components/SearchFacets/SearchFacets.d.ts +14 -0
- package/dist/components/SearchFacets/SearchFacets.jsx +101 -0
- package/dist/components/SearchFilters/SearchFilters.d.ts +16 -0
- package/dist/components/SearchFilters/SearchFilters.jsx +63 -0
- package/dist/components/SearchResult/SearchResult.d.ts +28 -0
- package/dist/components/SearchResult/SearchResult.jsx +93 -0
- package/dist/components/SearchSort/SearchSort.d.ts +10 -0
- package/dist/components/SearchSort/SearchSort.jsx +28 -0
- package/dist/components/Select/Select.d.ts +5 -0
- package/dist/components/SequentialNavigation/SequentialNavigation.d.ts +13 -0
- package/dist/components/SequentialNavigation/SequentialNavigation.jsx +0 -1
- package/dist/components/SideNavigation/SideNavigation.d.ts +13 -0
- package/dist/components/SideNavigation/SideNavigation.jsx +2 -2
- package/dist/components/SiteFooter/SiteFooter.d.ts +22 -0
- package/dist/components/SiteHeader/SiteHeader.d.ts +22 -0
- package/dist/components/SiteHeader/SiteHeader.jsx +0 -1
- package/dist/components/SiteNavigation/SiteNavigation.d.ts +9 -0
- package/dist/components/SiteSearch/SiteSearch.d.ts +5 -0
- package/dist/components/SkipLinks/SkipLinks.d.ts +10 -0
- package/dist/components/SkipLinks/SkipLinks.jsx +42 -0
- package/dist/components/SummaryCard/SummaryCard.d.ts +10 -0
- package/dist/components/SummaryList/SummaryList.d.ts +18 -0
- package/dist/components/Table/Table.d.ts +5 -0
- package/dist/components/Tabs/Tabs.d.ts +10 -0
- package/dist/components/Tag/Tag.d.ts +5 -0
- package/dist/components/TaskList/TaskList.d.ts +13 -0
- package/dist/components/TextInput/TextInput.d.ts +5 -0
- package/dist/components/Textarea/Textarea.d.ts +5 -0
- package/dist/components/WarningText/WarningText.d.ts +5 -0
- package/dist/hooks/useTracking.d.ts +1 -0
- package/dist/images/documents/audio.d.ts +4 -0
- package/dist/images/documents/csv.d.ts +4 -0
- package/dist/images/documents/excel.d.ts +4 -0
- package/dist/images/documents/file.d.ts +4 -0
- package/dist/images/documents/generic.d.ts +4 -0
- package/dist/images/documents/geodata.d.ts +4 -0
- package/dist/images/documents/ical.d.ts +4 -0
- package/dist/images/documents/ico.d.ts +4 -0
- package/dist/images/documents/image.d.ts +4 -0
- package/dist/images/documents/index.d.ts +22 -0
- package/dist/images/documents/odf.d.ts +4 -0
- package/dist/images/documents/odg.d.ts +4 -0
- package/dist/images/documents/odp.d.ts +4 -0
- package/dist/images/documents/ods.d.ts +4 -0
- package/dist/images/documents/odt.d.ts +4 -0
- package/dist/images/documents/pdf.d.ts +4 -0
- package/dist/images/documents/ppt.d.ts +4 -0
- package/dist/images/documents/rtf.d.ts +4 -0
- package/dist/images/documents/text.d.ts +4 -0
- package/dist/images/documents/video.d.ts +4 -0
- package/dist/images/documents/word.d.ts +4 -0
- package/dist/images/documents/xml.d.ts +4 -0
- package/dist/images/documents/zip.d.ts +4 -0
- package/dist/images/icons/arrow_upward.d.ts +4 -0
- package/dist/images/icons/calendar_today.d.ts +4 -0
- package/dist/images/icons/cancel.d.ts +4 -0
- package/dist/images/icons/check_circle.d.ts +4 -0
- package/dist/images/icons/chevron_left.d.ts +4 -0
- package/dist/images/icons/chevron_right.d.ts +4 -0
- package/dist/images/icons/close.d.ts +4 -0
- package/dist/images/icons/description.d.ts +4 -0
- package/dist/images/icons/double_chevron_left.d.ts +4 -0
- package/dist/images/icons/double_chevron_right.d.ts +4 -0
- package/dist/images/icons/error.d.ts +4 -0
- package/dist/images/icons/expand_less.d.ts +4 -0
- package/dist/images/icons/expand_more.d.ts +4 -0
- package/dist/images/icons/index.d.ts +17 -0
- package/dist/images/icons/list.d.ts +4 -0
- package/dist/images/icons/menu.d.ts +4 -0
- package/dist/images/icons/priority_high.d.ts +4 -0
- package/dist/images/icons/search.d.ts +4 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utils/context.d.ts +4 -0
- package/package.json +6 -6
- package/src/components/Accordion/Accordion.Item.stories.tsx +10 -9
- package/src/components/Accordion/Accordion.stories.tsx +4 -4
- package/src/components/Accordion/Accordion.test.tsx +48 -14
- package/src/components/Accordion/Accordion.tsx +12 -1
- package/src/components/Breadcrumbs/Breadcrumbs.Item.stories.tsx +8 -1
- package/src/components/Button/Button.stories.tsx +1 -1
- package/src/components/ButtonGroup/ButtonGroup.stories.tsx +41 -0
- package/src/components/ButtonGroup/ButtonGroup.test.tsx +45 -0
- package/src/components/ButtonGroup/ButtonGroup.tsx +20 -0
- package/src/components/ContentsNav/ContentsNav.Item.stories.tsx +8 -0
- package/src/components/ErrorSummary/ErrorSummary.Item.stories.tsx +7 -0
- package/src/components/PageHeader/PageHeader.tsx +2 -1
- package/src/components/PageMetadata/PageMetadata.Item.stories.tsx +9 -0
- package/src/components/RadioButton/RadioGroup.tsx +2 -2
- package/src/components/SearchFacets/SearchFacets.Group.stories.tsx +56 -0
- package/src/components/SearchFacets/SearchFacets.Item.stories.tsx +53 -0
- package/src/components/SearchFacets/SearchFacets.stories.tsx +38 -0
- package/src/components/SearchFacets/SearchFacets.test.tsx +214 -0
- package/src/components/SearchFacets/SearchFacets.tsx +99 -0
- package/src/components/SearchFilters/SearchFilters.Panel.stories.tsx +201 -0
- package/src/components/SearchFilters/SearchFilters.stories.tsx +137 -0
- package/src/components/SearchFilters/SearchFilters.test.tsx +161 -0
- package/src/components/SearchFilters/SearchFilters.tsx +89 -0
- package/src/components/SearchResult/SearchResult.stories.tsx +111 -0
- package/src/components/SearchResult/SearchResult.test.tsx +215 -0
- package/src/components/SearchResult/SearchResult.tsx +137 -0
- package/src/components/SearchSort/SearchSort.stories.tsx +32 -0
- package/src/components/SearchSort/SearchSort.test.tsx +129 -0
- package/src/components/SearchSort/SearchSort.tsx +45 -0
- package/src/components/SequentialNavigation/SequentialNavigation.Next.stories.tsx +1 -1
- package/src/components/SequentialNavigation/SequentialNavigation.Previous.stories.tsx +1 -1
- package/src/components/SequentialNavigation/SequentialNavigation.tsx +0 -1
- package/src/components/SideNavigation/SideNavigation.Item.stories.tsx +9 -0
- package/src/components/SideNavigation/SideNavigation.List.stories.tsx +7 -0
- package/src/components/SideNavigation/SideNavigation.tsx +2 -1
- package/src/components/SiteFooter/SiteFooter.License.stories.tsx +7 -0
- package/src/components/SiteFooter/SiteFooter.Link.stories.tsx +9 -0
- package/src/components/SiteFooter/SiteFooter.Org.stories.tsx +7 -0
- package/src/components/SiteHeader/SiteHeader.tsx +0 -2
- package/src/components/SiteNavigation/SiteNavigation.Item.stories.tsx +10 -0
- package/src/components/SkipLinks/SkipLinks.Item.stories.tsx +11 -1
- package/src/components/SkipLinks/SkipLinks.tsx +10 -0
- package/src/components/SummaryCard/SummaryCard.Action.stories.tsx +7 -0
- package/src/components/SummaryCard/SummaryCard.stories.tsx +7 -0
- package/src/components/SummaryList/SummaryList.Item.stories.tsx +15 -0
- package/src/components/SummaryList/SummaryList.Value.stories.tsx +5 -2
- package/src/components/Tabs/Tabs.Item.stories.tsx +4 -1
- package/src/components/TaskList/TaskList.Group.stories.tsx +9 -0
- package/src/components/TaskList/TaskList.Item.stories.tsx +7 -0
- package/tsconfig.json +14 -14
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { test, expect, vi } from 'vitest';
|
|
2
|
+
import { render, screen, within } from '@testing-library/react';
|
|
3
|
+
import Facets from './SearchFacets';
|
|
4
|
+
|
|
5
|
+
test('search facets boilerplate renders correctly', () => {
|
|
6
|
+
render(
|
|
7
|
+
<Facets data-testid="searchfacets"/>
|
|
8
|
+
);
|
|
9
|
+
|
|
10
|
+
const facets = screen.getByTestId('searchfacets');
|
|
11
|
+
|
|
12
|
+
expect(facets).toBeInTheDocument();
|
|
13
|
+
expect(facets).toHaveClass('ds_facets');
|
|
14
|
+
expect(facets.tagName).toEqual('DIV');
|
|
15
|
+
|
|
16
|
+
const status = facets.querySelector('p');
|
|
17
|
+
expect(status).toBeInTheDocument();
|
|
18
|
+
expect(status).toHaveClass('visually-hidden');
|
|
19
|
+
expect(status?.textContent).toEqual('There are 0 search filters applied');
|
|
20
|
+
expect(status?.parentElement).toEqual(facets);
|
|
21
|
+
|
|
22
|
+
const list = facets.querySelector('dl');
|
|
23
|
+
expect(list).toBeInTheDocument();
|
|
24
|
+
expect(list).toHaveClass('ds_facets__list');
|
|
25
|
+
expect(list?.parentElement).toEqual(facets);
|
|
26
|
+
expect(list?.previousElementSibling).toEqual(status);
|
|
27
|
+
|
|
28
|
+
// clear button is not present if there are no facets
|
|
29
|
+
const clearButton = within(facets).queryByRole('button', { name: /clear all filters/i });
|
|
30
|
+
expect(clearButton).not.toBeInTheDocument();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test('search facets count with one facet', () => {
|
|
34
|
+
render(
|
|
35
|
+
<Facets data-testid="searchfacets">
|
|
36
|
+
<Facets.Item title="Facet 1" />
|
|
37
|
+
</Facets>
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
const facets = screen.getByTestId('searchfacets');
|
|
41
|
+
const status = within(facets).getByText('There is 1 search filter applied');
|
|
42
|
+
expect(status).toBeInTheDocument();
|
|
43
|
+
|
|
44
|
+
const clearButton = within(facets).getByRole('button', { name: /clear all filters/i });
|
|
45
|
+
expect(clearButton).toBeInTheDocument();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test('search facets count with multiple facets', () => {
|
|
49
|
+
render(
|
|
50
|
+
<Facets data-testid="searchfacets">
|
|
51
|
+
<Facets.Item title="Facet 1" />
|
|
52
|
+
<Facets.Item title="Facet 2" />
|
|
53
|
+
</Facets>
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const facets = screen.getByTestId('searchfacets');
|
|
57
|
+
const facetItems = facets.querySelectorAll('.ds_facet');
|
|
58
|
+
const status = within(facets).getByText(`There are ${facetItems.length} search filters applied`);
|
|
59
|
+
expect(status).toBeInTheDocument();
|
|
60
|
+
|
|
61
|
+
const clearButton = within(facets).getByRole('button', { name: /clear all filters/i });
|
|
62
|
+
expect(clearButton).toBeInTheDocument();
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test('search filters count with facet groups', () => {
|
|
66
|
+
render(
|
|
67
|
+
<Facets data-testid="searchfacets">
|
|
68
|
+
<Facets.Group title="Group 1">
|
|
69
|
+
<Facets.Item title="Facet 1" />
|
|
70
|
+
<Facets.Item title="Facet 2" />
|
|
71
|
+
</Facets.Group>
|
|
72
|
+
<Facets.Group title="Group 2">
|
|
73
|
+
<Facets.Item title="Facet 3" />
|
|
74
|
+
</Facets.Group>
|
|
75
|
+
</Facets>
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
const facets = screen.getByTestId('searchfacets');
|
|
79
|
+
const facetItems = facets.querySelectorAll('.ds_facet');
|
|
80
|
+
const status = within(facets).getByText(`There are ${facetItems.length} search filters applied`);
|
|
81
|
+
expect(status).toBeInTheDocument();
|
|
82
|
+
|
|
83
|
+
const clearButton = within(facets).getByRole('button', { name: /clear all filters/i });
|
|
84
|
+
expect(clearButton).toBeInTheDocument();
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test('search facet renders correctly', () => {
|
|
88
|
+
const FACET_TITLE = 'Facet 1';
|
|
89
|
+
|
|
90
|
+
render(
|
|
91
|
+
<Facets.Item title={FACET_TITLE} data-testid="searchfacet" />
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
const facetWrapper = screen.getByTestId('searchfacet');
|
|
95
|
+
expect(facetWrapper).toBeInTheDocument();
|
|
96
|
+
expect(facetWrapper).toHaveClass('ds_facet-wrapper');
|
|
97
|
+
expect(facetWrapper.tagName).toEqual('DD');
|
|
98
|
+
|
|
99
|
+
const facetButton = within(facetWrapper).getByRole('button');
|
|
100
|
+
expect(facetButton).toHaveClass('ds_facet__button');
|
|
101
|
+
expect(facetButton).toHaveAttribute('aria-label', `Remove '${FACET_TITLE}' filter`);
|
|
102
|
+
|
|
103
|
+
const facet = facetButton.parentElement;
|
|
104
|
+
expect(facet).toHaveClass('ds_facet');
|
|
105
|
+
expect(facet?.textContent).toEqual(FACET_TITLE);
|
|
106
|
+
|
|
107
|
+
const facetIcon = within(facetButton).getByRole('img', { hidden: true });
|
|
108
|
+
expect(facetIcon).toHaveClass('ds_facet__button-icon');
|
|
109
|
+
expect(facetIcon).toHaveAttribute('aria-hidden', 'true');
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test('search facet with accessible name', () => {
|
|
113
|
+
const FACET_TITLE = 'Facet 1';
|
|
114
|
+
const ACCESSIBLE_NAME = 'Custom facet name';
|
|
115
|
+
|
|
116
|
+
render(
|
|
117
|
+
<Facets.Item title={FACET_TITLE} accessibleName={ACCESSIBLE_NAME} data-testid="searchfacet" />
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
const facetWrapper = screen.getByTestId('searchfacet');
|
|
121
|
+
const facetButton = within(facetWrapper).getByRole('button');
|
|
122
|
+
expect(facetButton).toHaveAttribute('aria-label', `Remove '${ACCESSIBLE_NAME}' filter`);
|
|
123
|
+
|
|
124
|
+
const facet = facetButton.parentElement;
|
|
125
|
+
expect(facet).toHaveClass('ds_facet');
|
|
126
|
+
expect(facet?.textContent).toEqual(FACET_TITLE);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
test('facet button onClick works', async () => {
|
|
130
|
+
const FACET_TITLE = 'Facet 1';
|
|
131
|
+
const handleClick = vi.fn();
|
|
132
|
+
|
|
133
|
+
render(
|
|
134
|
+
<Facets.Item title={FACET_TITLE} onClick={handleClick} data-testid="searchfacet" />
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
const facetWrapper = screen.getByTestId('searchfacet');
|
|
138
|
+
const facetButton = within(facetWrapper).getByRole('button');
|
|
139
|
+
|
|
140
|
+
await facetButton.click();
|
|
141
|
+
expect(handleClick).toHaveBeenCalledTimes(1);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
test('facet group renders correctly', () => {
|
|
145
|
+
const GROUP_TITLE = 'Group 1';
|
|
146
|
+
|
|
147
|
+
render(
|
|
148
|
+
<Facets.Group title={GROUP_TITLE} data-testid="searchfacetgroup">
|
|
149
|
+
<Facets.Item title="Facet 1" />
|
|
150
|
+
<Facets.Item title="Facet 2" />
|
|
151
|
+
</Facets.Group>
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
const facetGroup = screen.getByTestId('searchfacetgroup');
|
|
155
|
+
expect(facetGroup).toBeInTheDocument();
|
|
156
|
+
expect(facetGroup).toHaveClass('ds_facet-group');
|
|
157
|
+
expect(facetGroup.tagName).toEqual('DIV');
|
|
158
|
+
|
|
159
|
+
const groupTitle = within(facetGroup).getByText(`${GROUP_TITLE}:`);
|
|
160
|
+
expect(groupTitle).toBeInTheDocument();
|
|
161
|
+
expect(groupTitle).toHaveClass('ds_facet__group-title');
|
|
162
|
+
|
|
163
|
+
const facetWrappers = facetGroup.querySelectorAll('.ds_facet-wrapper');
|
|
164
|
+
expect(facetWrappers.length).toEqual(2);
|
|
165
|
+
|
|
166
|
+
const firstFacet = facetWrappers[0];
|
|
167
|
+
expect(firstFacet?.textContent).toContain('Facet 1');
|
|
168
|
+
expect(firstFacet?.textContent).not.toContain('or');
|
|
169
|
+
|
|
170
|
+
const secondFacet = facetWrappers[1];
|
|
171
|
+
expect(secondFacet?.textContent).toContain('Facet 2');
|
|
172
|
+
expect(secondFacet?.textContent).toContain('or');
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
test('facet group with custom join content', () => {
|
|
176
|
+
const GROUP_TITLE = 'Group 1';
|
|
177
|
+
const JOIN_CONTENT = 'and';
|
|
178
|
+
|
|
179
|
+
render(
|
|
180
|
+
<Facets.Group title={GROUP_TITLE} joinContent={JOIN_CONTENT} data-testid="searchfacetgroup">
|
|
181
|
+
<Facets.Item title="Facet 1" />
|
|
182
|
+
<Facets.Item title="Facet 2" />
|
|
183
|
+
</Facets.Group>
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
const facetGroup = screen.getByTestId('searchfacetgroup');
|
|
187
|
+
const facetWrappers = facetGroup.querySelectorAll('.ds_facet-wrapper');
|
|
188
|
+
|
|
189
|
+
const firstFacet = facetWrappers[0];
|
|
190
|
+
expect(firstFacet?.textContent).toContain('Facet 1');
|
|
191
|
+
expect(firstFacet?.textContent).not.toContain(JOIN_CONTENT);
|
|
192
|
+
|
|
193
|
+
const secondFacet = facetWrappers[1];
|
|
194
|
+
expect(secondFacet?.textContent).toContain('Facet 2');
|
|
195
|
+
expect(secondFacet?.textContent).toContain(JOIN_CONTENT);
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
test('passing additional props', () => {
|
|
199
|
+
render(
|
|
200
|
+
<Facets data-test="foo" data-testid="searchfacets"/>
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
const searchFacets = screen.getByTestId('searchfacets');
|
|
204
|
+
expect(searchFacets?.dataset.test).toEqual('foo');
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
test('passing additional CSS classes', () => {
|
|
208
|
+
render(
|
|
209
|
+
<Facets className="foo" data-testid="searchfacets"/>
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
const searchFacets = screen.getByTestId('searchfacets');
|
|
213
|
+
expect(searchFacets).toHaveClass('foo');
|
|
214
|
+
});
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import React, { Children } from 'react';
|
|
2
|
+
import Icon from "../../common/Icon";
|
|
3
|
+
import { Cancel } from '../../../src/images/icons';
|
|
4
|
+
|
|
5
|
+
const FacetsItem = ({
|
|
6
|
+
accessibleName,
|
|
7
|
+
joinContent,
|
|
8
|
+
onClick,
|
|
9
|
+
title,
|
|
10
|
+
...props
|
|
11
|
+
}: SGDS.Component.SearchFacets.Item) => {
|
|
12
|
+
accessibleName = accessibleName ? accessibleName : title;
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<dd className="ds_facet-wrapper" {...props}>
|
|
16
|
+
{joinContent &&
|
|
17
|
+
<span aria-hidden="true">{joinContent}</span>
|
|
18
|
+
}
|
|
19
|
+
<span className="ds_facet">
|
|
20
|
+
{title}
|
|
21
|
+
<button type="button" onClick={onClick} aria-label={`Remove '${accessibleName}' filter`} className="ds_facet__button">
|
|
22
|
+
<Icon className="ds_facet__button-icon" aria-hidden="true" role="img" icon="Cancel"/>
|
|
23
|
+
</button>
|
|
24
|
+
</span>
|
|
25
|
+
</dd>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const FacetsGroup = ({
|
|
30
|
+
children,
|
|
31
|
+
joinContent = 'or',
|
|
32
|
+
title,
|
|
33
|
+
...props
|
|
34
|
+
}: SGDS.Component.SearchFacets.Group) => {
|
|
35
|
+
return (
|
|
36
|
+
<div className="ds_facet-group" {...props}>
|
|
37
|
+
<dt className="ds_facet__group-title">
|
|
38
|
+
{title.trim()}:
|
|
39
|
+
</dt>
|
|
40
|
+
{
|
|
41
|
+
Children.map(children, (child, index) => {
|
|
42
|
+
const thisChild = child as React.ReactElement<SGDS.Component.SearchFacets.Item>
|
|
43
|
+
return React.cloneElement(thisChild, { joinContent: index > 0 ? joinContent : undefined, key: 'facet' + index });
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
</div>
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const Facets = ({
|
|
51
|
+
children,
|
|
52
|
+
className,
|
|
53
|
+
...props
|
|
54
|
+
}: SGDS.Component.SearchFacets) => {
|
|
55
|
+
let facetCount = 0;
|
|
56
|
+
|
|
57
|
+
function processChild(item: any) {
|
|
58
|
+
if (item.type.displayName === 'Facets.Item') {
|
|
59
|
+
facetCount = facetCount + 1;
|
|
60
|
+
|
|
61
|
+
} else if (item.type.displayName === 'Facets.Group') {
|
|
62
|
+
Children.forEach(item.props.children, child => {
|
|
63
|
+
processChild(child);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
Children.forEach(children, child => {
|
|
69
|
+
processChild(child);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<div className={[
|
|
74
|
+
"ds_facets",
|
|
75
|
+
className
|
|
76
|
+
].join(' ')}
|
|
77
|
+
{...props}
|
|
78
|
+
>
|
|
79
|
+
<p className="visually-hidden">There {facetCount === 1 ? 'is' : 'are'} {facetCount} search {facetCount === 1 ? 'filter' : 'filters'} applied</p>
|
|
80
|
+
<dl className="ds_facets__list">
|
|
81
|
+
{children}
|
|
82
|
+
</dl>
|
|
83
|
+
{facetCount > 0 &&
|
|
84
|
+
<button className="ds_button ds_button--secondary ds_button--has-icon ds_facets__clear-button" type="button">
|
|
85
|
+
Clear all filters
|
|
86
|
+
<Cancel className="ds_facet__button-icon"/>
|
|
87
|
+
</button>
|
|
88
|
+
}
|
|
89
|
+
</div>
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
Facets.displayName = 'Facets';
|
|
94
|
+
FacetsItem.displayName = 'Facets.Item';
|
|
95
|
+
FacetsGroup.displayName = 'Facets.Group';
|
|
96
|
+
Facets.Item = FacetsItem;
|
|
97
|
+
Facets.Group = FacetsGroup;
|
|
98
|
+
|
|
99
|
+
export default Facets;
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
|
+
import argTypes from '../../../.storybook/sgdsArgTypes';
|
|
3
|
+
|
|
4
|
+
import Filters from './SearchFilters';
|
|
5
|
+
import DatePicker from '../DatePicker/DatePicker';
|
|
6
|
+
import Checkbox from '../Checkbox/Checkbox';
|
|
7
|
+
|
|
8
|
+
const meta = {
|
|
9
|
+
title: 'Components/Search results/Filters/Filter panel',
|
|
10
|
+
component: Filters.Panel,
|
|
11
|
+
decorators: [(Story) => (
|
|
12
|
+
<div className="ds_accordion ds_accordion--small ds_!_margin-top--0">
|
|
13
|
+
<Story />
|
|
14
|
+
</div>
|
|
15
|
+
)],
|
|
16
|
+
argTypes: {
|
|
17
|
+
children: argTypes.children(),
|
|
18
|
+
isScrollable: {
|
|
19
|
+
description: 'Puts internal scrollbars around the filter fields',
|
|
20
|
+
control: 'boolean',
|
|
21
|
+
},
|
|
22
|
+
legend: {
|
|
23
|
+
description: 'Content for the (visually hidden) legend element',
|
|
24
|
+
type: {
|
|
25
|
+
name: 'string',
|
|
26
|
+
required: true
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
heading: {
|
|
30
|
+
description: 'Heading of the filter panel item',
|
|
31
|
+
type: {
|
|
32
|
+
name: 'string',
|
|
33
|
+
required: true
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
activeFilterCount: {
|
|
37
|
+
description: 'Number of active filter fields in this panel',
|
|
38
|
+
type: {
|
|
39
|
+
name: 'number'
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
} satisfies Meta<typeof Filters.Panel>;
|
|
44
|
+
|
|
45
|
+
export default meta;
|
|
46
|
+
type Story = StoryObj<typeof meta>;
|
|
47
|
+
|
|
48
|
+
const CONTENT_TYPES = [
|
|
49
|
+
{
|
|
50
|
+
label: 'Advice and guidance',
|
|
51
|
+
value: 'advice-and-guidance'
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
label: 'Agreement',
|
|
55
|
+
value: 'agreement'
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
label: 'Consultation analysis',
|
|
59
|
+
value: 'consultation-analysis'
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
label: 'Consultation paper',
|
|
63
|
+
value: 'consultation-paper'
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
label: 'Corporate report',
|
|
67
|
+
value: 'corporate-report'
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
label: 'Correspondence',
|
|
71
|
+
value: 'correspondence'
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
label: 'FOI/EIR release',
|
|
75
|
+
value: 'foi-eir-release'
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
label: 'Factsheet',
|
|
79
|
+
value: 'factsheet'
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
label: 'Form',
|
|
83
|
+
value: 'form'
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
label: 'Impact assessment',
|
|
87
|
+
value: 'impact-assessment'
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
label: 'Independent report',
|
|
91
|
+
value: 'independent-report'
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
label: 'Map',
|
|
95
|
+
value: 'map'
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
label: 'Minutes',
|
|
99
|
+
value: 'minutes'
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
label: 'Progress report',
|
|
103
|
+
value: 'progress-report'
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
label: 'Regulation/directive/order',
|
|
107
|
+
value: 'regulation-directive-order'
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
label: 'Research and analysis',
|
|
111
|
+
value: 'research-and-analysis'
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
label: 'Speech/statement',
|
|
115
|
+
value: 'speech-statement'
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
label: 'Statistics',
|
|
119
|
+
value: 'statistics'
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
label: 'Strategy/plan',
|
|
123
|
+
value: 'strategy-plan'
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
label: 'Transparency data',
|
|
127
|
+
value: 'transparency-data'
|
|
128
|
+
}
|
|
129
|
+
];
|
|
130
|
+
|
|
131
|
+
const CONTENT_TYPES_WITH_SELECTED = JSON.parse(JSON.stringify(CONTENT_TYPES));
|
|
132
|
+
CONTENT_TYPES_WITH_SELECTED[1].checked = true;
|
|
133
|
+
CONTENT_TYPES_WITH_SELECTED[4].checked = true;
|
|
134
|
+
CONTENT_TYPES_WITH_SELECTED[7].checked = true;
|
|
135
|
+
|
|
136
|
+
export const Default: Story = {
|
|
137
|
+
render: (args: any) => (
|
|
138
|
+
<Filters.Panel
|
|
139
|
+
heading="Filter by date"
|
|
140
|
+
legend="Filter by date"
|
|
141
|
+
>
|
|
142
|
+
<DatePicker
|
|
143
|
+
hintText="For example, 21/01/2022"
|
|
144
|
+
id="date-from"
|
|
145
|
+
label="Updated after"
|
|
146
|
+
/>
|
|
147
|
+
|
|
148
|
+
<DatePicker
|
|
149
|
+
hintText="For example, 21/01/2022"
|
|
150
|
+
id="date-to"
|
|
151
|
+
label="Updated before"
|
|
152
|
+
/>
|
|
153
|
+
</Filters.Panel>
|
|
154
|
+
)
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
export const Scrollable: Story = {
|
|
158
|
+
render: (args: any) => (
|
|
159
|
+
<Filters.Panel
|
|
160
|
+
heading="Content type"
|
|
161
|
+
isScrollable
|
|
162
|
+
legend="Select which publication types you would like to see"
|
|
163
|
+
{...args}
|
|
164
|
+
>
|
|
165
|
+
<Filters.CheckboxGroup>
|
|
166
|
+
{CONTENT_TYPES.map((type) => (
|
|
167
|
+
<Checkbox
|
|
168
|
+
key={type.value}
|
|
169
|
+
label={type.label}
|
|
170
|
+
value={type.value}
|
|
171
|
+
id={type.value}
|
|
172
|
+
/>
|
|
173
|
+
))}
|
|
174
|
+
</Filters.CheckboxGroup>
|
|
175
|
+
</Filters.Panel>
|
|
176
|
+
)
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
export const WithActiveFilterCount: Story = {
|
|
180
|
+
render: (args: any) => (
|
|
181
|
+
<Filters.Panel
|
|
182
|
+
activeFilterCount={CONTENT_TYPES_WITH_SELECTED.filter((item: any) => item.checked).length}
|
|
183
|
+
heading="Content type"
|
|
184
|
+
isScrollable
|
|
185
|
+
legend="Select which publication types you would like to see"
|
|
186
|
+
{...args}
|
|
187
|
+
>
|
|
188
|
+
<Filters.CheckboxGroup>
|
|
189
|
+
{CONTENT_TYPES_WITH_SELECTED.map((type: any) => (
|
|
190
|
+
<Checkbox
|
|
191
|
+
checked={type.checked || false}
|
|
192
|
+
key={type.value}
|
|
193
|
+
label={type.label}
|
|
194
|
+
value={type.value}
|
|
195
|
+
id={type.value}
|
|
196
|
+
/>
|
|
197
|
+
))}
|
|
198
|
+
</Filters.CheckboxGroup>
|
|
199
|
+
</Filters.Panel>
|
|
200
|
+
)
|
|
201
|
+
};
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
|
+
import argTypes from '../../../.storybook/sgdsArgTypes';
|
|
3
|
+
|
|
4
|
+
import Filters from './SearchFilters';
|
|
5
|
+
import DatePicker from '../DatePicker/DatePicker';
|
|
6
|
+
import Checkbox from '../Checkbox/Checkbox';
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
const meta = {
|
|
10
|
+
title: 'Components/Search results/Filters',
|
|
11
|
+
component: Filters,
|
|
12
|
+
argTypes: {
|
|
13
|
+
children: argTypes.children()
|
|
14
|
+
},
|
|
15
|
+
args: {
|
|
16
|
+
title: 'Content type'
|
|
17
|
+
}
|
|
18
|
+
} satisfies Meta<typeof Filters>;
|
|
19
|
+
|
|
20
|
+
export default meta;
|
|
21
|
+
type Story = StoryObj<typeof meta>;
|
|
22
|
+
|
|
23
|
+
const CONTENT_TYPES = [
|
|
24
|
+
{
|
|
25
|
+
label: 'Advice and guidance',
|
|
26
|
+
value: 'advice-and-guidance'
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
label: 'Agreement',
|
|
30
|
+
value: 'agreement'
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
label: 'Consultation analysis',
|
|
34
|
+
value: 'consultation-analysis'
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
label: 'Consultation paper',
|
|
38
|
+
value: 'consultation-paper'
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
label: 'Corporate report',
|
|
42
|
+
value: 'corporate-report'
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
label: 'Correspondence',
|
|
46
|
+
value: 'correspondence'
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
label: 'FOI/EIR release',
|
|
50
|
+
value: 'foi-eir-release'
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
label: 'Factsheet',
|
|
54
|
+
value: 'factsheet'
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
label: 'Form',
|
|
58
|
+
value: 'form'
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
label: 'Impact assessment',
|
|
62
|
+
value: 'impact-assessment'
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
label: 'Independent report',
|
|
66
|
+
value: 'independent-report'
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
label: 'Map',
|
|
70
|
+
value: 'map'
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
label: 'Minutes',
|
|
74
|
+
value: 'minutes'
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
label: 'Progress report',
|
|
78
|
+
value: 'progress-report'
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
label: 'Regulation/directive/order',
|
|
82
|
+
value: 'regulation-directive-order'
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
label: 'Research and analysis',
|
|
86
|
+
value: 'research-and-analysis'
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
label: 'Speech/statement',
|
|
90
|
+
value: 'speech-statement'
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
label: 'Statistics',
|
|
94
|
+
value: 'statistics'
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
label: 'Strategy/plan',
|
|
98
|
+
value: 'strategy-plan'
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
label: 'Transparency data',
|
|
102
|
+
value: 'transparency-data'
|
|
103
|
+
}
|
|
104
|
+
];
|
|
105
|
+
|
|
106
|
+
export const Default: Story = {
|
|
107
|
+
render: (args: any) => (
|
|
108
|
+
<Filters {...args}>
|
|
109
|
+
<Filters.Panel legend="Select which publication types you would like to see" heading="Content type">
|
|
110
|
+
<Filters.CheckboxGroup>
|
|
111
|
+
{CONTENT_TYPES.map((type) => (
|
|
112
|
+
<Checkbox
|
|
113
|
+
key={type.value}
|
|
114
|
+
label={type.label}
|
|
115
|
+
value={type.value}
|
|
116
|
+
id={type.value}
|
|
117
|
+
/>
|
|
118
|
+
))}
|
|
119
|
+
</Filters.CheckboxGroup>
|
|
120
|
+
</Filters.Panel>
|
|
121
|
+
|
|
122
|
+
<Filters.Panel heading="Filter by date" legend="Filter by date">
|
|
123
|
+
<DatePicker
|
|
124
|
+
hintText="For example, 21/01/2022"
|
|
125
|
+
id="date-from"
|
|
126
|
+
label="Updated after"
|
|
127
|
+
/>
|
|
128
|
+
|
|
129
|
+
<DatePicker
|
|
130
|
+
hintText="For example, 21/01/2022"
|
|
131
|
+
id="date-to"
|
|
132
|
+
label="Updated before"
|
|
133
|
+
/>
|
|
134
|
+
</Filters.Panel>
|
|
135
|
+
</Filters>
|
|
136
|
+
)
|
|
137
|
+
};
|