@kaizen/components 1.68.2 → 1.68.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.
- package/dist/cjs/Filter/FilterBar/context/FilterBarContext.cjs +13 -3
- package/dist/cjs/Filter/FilterBar/context/reducer/filterBarStateReducer.cjs +1 -1
- package/dist/cjs/Filter/FilterBar/context/reducer/setupFilterBarState.cjs +4 -0
- package/dist/cjs/Filter/FilterBar/context/utils/updateDependentFilters.cjs +1 -1
- package/dist/cjs/Filter/FilterBar/subcomponents/ClearAllButton/ClearAllButton.cjs +7 -2
- package/dist/cjs/Filter/FilterBar/subcomponents/ClearAllButton/ClearAllButton.module.scss.cjs +2 -1
- package/dist/cjs/Filter/FilterDateRangePicker/subcomponents/FilterDateRangePickerField/FilterDateRangePickerField.cjs +3 -0
- package/dist/cjs/Tile/subcomponents/GenericTile/GenericTile.cjs +16 -3
- package/dist/esm/Filter/FilterBar/context/FilterBarContext.mjs +13 -3
- package/dist/esm/Filter/FilterBar/context/reducer/filterBarStateReducer.mjs +1 -1
- package/dist/esm/Filter/FilterBar/context/reducer/setupFilterBarState.mjs +4 -0
- package/dist/esm/Filter/FilterBar/context/utils/updateDependentFilters.mjs +1 -1
- package/dist/esm/Filter/FilterBar/subcomponents/ClearAllButton/ClearAllButton.mjs +6 -2
- package/dist/esm/Filter/FilterBar/subcomponents/ClearAllButton/ClearAllButton.module.scss.mjs +2 -1
- package/dist/esm/Filter/FilterDateRangePicker/subcomponents/FilterDateRangePickerField/FilterDateRangePickerField.mjs +3 -0
- package/dist/esm/Tile/subcomponents/GenericTile/GenericTile.mjs +16 -3
- package/dist/styles.css +81 -77
- package/dist/types/Filter/FilterBar/context/FilterBarContext.d.ts +1 -0
- package/dist/types/Filter/FilterBar/context/types.d.ts +1 -0
- package/dist/types/Tile/subcomponents/GenericTile/GenericTile.d.ts +3 -1
- package/locales/en.json +8 -0
- package/package.json +1 -1
- package/src/Avatar/_docs/Avatar.stickersheet.stories.tsx +30 -32
- package/src/AvatarGroup/_docs/AvatarGroup.stickersheet.stories.tsx +14 -16
- package/src/Badge/_docs/Badge.stickersheet.stories.tsx +22 -22
- package/src/Brand/_docs/Brand.stickersheet.stories.tsx +24 -26
- package/src/BrandMoment/_docs/BrandMoment.stickersheet.stories.tsx +35 -39
- package/src/ButtonGroup/_docs/ButtonGroup.stickersheet.stories.tsx +117 -122
- package/src/Calendar/CalendarPopover/_docs/CalendarPopover.stickersheet.stories.tsx +4 -4
- package/src/Calendar/CalendarRange/_docs/CalendarRange.stickersheet.stories.tsx +22 -30
- package/src/Calendar/CalendarSingle/_docs/CalendarSingle.stickersheet.stories.tsx +58 -58
- package/src/Card/_docs/Card.stickersheet.stories.tsx +12 -16
- package/src/Checkbox/Checkbox/_docs/Checkbox.stickersheet.stories.tsx +24 -27
- package/src/Checkbox/CheckboxField/_docs/CheckboxField.stickersheet.stories.tsx +31 -34
- package/src/Checkbox/CheckboxGroup/_docs/CheckboxGroup.stickersheet.stories.tsx +25 -29
- package/src/ClearButton/_docs/ClearButton.stickersheet.stories.tsx +9 -9
- package/src/Collapsible/Collapsible/_docs/Collapsible.stickersheet.stories.tsx +56 -62
- package/src/Collapsible/CollapsibleGroup/_docs/CollapsibleGroup.stickersheet.stories.tsx +19 -21
- package/src/Collapsible/ExpertAdviceCollapsible/_docs/ExpertAdviceCollapsible.stickersheets.stories.tsx +6 -8
- package/src/DatePicker/_docs/DatePicker.stickersheet.stories.tsx +129 -144
- package/src/DatePicker/_docs/getLocale.stickersheet.stories.tsx +9 -11
- package/src/DateRangePicker/_docs/DateRangePicker.stickersheet.stories.tsx +26 -28
- package/src/Divider/_docs/Divider.stickersheet.stories.tsx +13 -10
- package/src/EmptyState/_docs/EmptyState.stickersheet.stories.tsx +7 -2
- package/src/ErrorPage/_docs/ErrorPage.stickersheet.stories.tsx +16 -20
- package/src/FieldGroup/_docs/FieldGroup.stickersheet.stories.tsx +5 -8
- package/src/FieldMessage/_docs/FieldMessage.stickersheet.stories.tsx +10 -20
- package/src/Filter/Filter/_docs/Filter.stickersheet.stories.tsx +13 -15
- package/src/Filter/FilterBar/FilterBar.spec.tsx +0 -64
- package/src/Filter/FilterBar/_docs/FilterBar.spec.stories.tsx +249 -0
- package/src/Filter/FilterBar/_docs/FilterBar.stickersheet.stories.tsx +34 -48
- package/src/Filter/FilterBar/_docs/FilterBar.stories.tsx +1 -1
- package/src/Filter/FilterBar/context/FilterBarContext.tsx +17 -5
- package/src/Filter/FilterBar/context/reducer/filterBarStateReducer.spec.ts +3 -0
- package/src/Filter/FilterBar/context/reducer/filterBarStateReducer.ts +1 -1
- package/src/Filter/FilterBar/context/reducer/setupFilterBarState.spec.tsx +40 -0
- package/src/Filter/FilterBar/context/reducer/setupFilterBarState.ts +5 -0
- package/src/Filter/FilterBar/context/reducer/updateSingleFilter.spec.ts +2 -0
- package/src/Filter/FilterBar/context/reducer/updateValues.spec.ts +5 -0
- package/src/Filter/FilterBar/context/types.ts +1 -0
- package/src/Filter/FilterBar/context/utils/checkShouldUpdateValues.spec.ts +1 -0
- package/src/Filter/FilterBar/context/utils/getInactiveFilters.spec.ts +2 -0
- package/src/Filter/FilterBar/context/utils/getIsUsableWhenArgs.spec.ts +1 -0
- package/src/Filter/FilterBar/context/utils/updateDependentFilters.spec.ts +8 -0
- package/src/Filter/FilterBar/context/utils/updateDependentFilters.ts +1 -1
- package/src/Filter/FilterBar/subcomponents/ClearAllButton/ClearAllButton.module.scss +4 -0
- package/src/Filter/FilterBar/subcomponents/ClearAllButton/ClearAllButton.tsx +5 -2
- package/src/Filter/FilterButton/_docs/filter-buttons.stickersheet.stories.tsx +45 -51
- package/src/Filter/FilterDatePicker/_docs/FilterDatePicker.stickersheet.stories.tsx +74 -93
- package/src/Filter/FilterDateRangePicker/_docs/FilterDateRangePicker.stickersheet.stories.tsx +110 -128
- package/src/Filter/FilterDateRangePicker/subcomponents/FilterDateRangePickerField/FilterDateRangePickerField.tsx +4 -0
- package/src/Filter/FilterSelect/_docs/FilterSelect.stickersheet.stories.tsx +239 -249
- package/src/GuidanceBlock/_docs/GuidanceBlock.stickersheet.stories.tsx +38 -40
- package/src/Heading/_docs/Heading.stickersheet.stories.tsx +101 -111
- package/src/Icon/_docs/Icon.stickersheet.stories.tsx +13 -19
- package/src/Illustration/Scene/BrandMomentCaptureIntro/_docs/BrandMomentCaptureIntro.stickersheet.stories.tsx +8 -8
- package/src/Illustration/Scene/_docs/Scene.stickersheet.stories.tsx +139 -185
- package/src/Illustration/subcomponents/VideoPlayer/VideoPlayer.stickersheet.stories.tsx +39 -41
- package/src/Input/Input/_docs/Input.stickersheet.stories.tsx +30 -33
- package/src/Input/InputRange/_docs/InputRange.stickersheet.stories.tsx +21 -20
- package/src/Input/InputSearch/_docs/InputSearch.stickersheet.stories.tsx +137 -144
- package/src/Label/_docs/Label.stickersheet.stories.tsx +78 -85
- package/src/LabelledMessage/_docs/LabelledMessage.stickersheet.stories.tsx +3 -5
- package/src/LikertScaleLegacy/_docs/LikertScaleLegacy.stickersheet.stories.tsx +82 -82
- package/src/Loading/LoadingGraphic/_docs/LoadingGraphic.stickersheet.stories.tsx +18 -20
- package/src/Loading/LoadingGraphic/_docs/LoadingGraphic.stories.tsx +46 -52
- package/src/Loading/LoadingHeading/_docs/LoadingHeading.stickersheet.stories.tsx +14 -18
- package/src/Loading/LoadingHeading/_docs/LoadingHeading.stories.tsx +7 -13
- package/src/Loading/LoadingParagraph/_docs/LoadingParagraph.stickersheet.stories.tsx +14 -16
- package/src/Loading/LoadingSpinner/_docs/LoadingSpinner.stickersheet.stories.tsx +13 -15
- package/src/MultiSelect/_docs/MultiSelect.stickersheet.stories.tsx +69 -74
- package/src/MultiSelect/subcomponents/Checkbox/_docs/Checkbox.stickersheet.stories.tsx +22 -28
- package/src/MultiSelect/subcomponents/MultiSelectOptionField/_docs/MultiSelectOptionField.stickersheet.stories.tsx +62 -67
- package/src/MultiSelect/subcomponents/MultiSelectOptions/_docs/MultiSelectOptions.stickersheet.stories.tsx +21 -28
- package/src/MultiSelect/subcomponents/MultiSelectToggle/_docs/MultiSelectToggle.stickersheet.stories.tsx +69 -93
- package/src/Notification/GlobalNotification/_docs/GlobalNotification.stickersheet.stories.tsx +13 -16
- package/src/Notification/InlineNotification/_docs/InlineNotification.stickersheet.stories.tsx +13 -16
- package/src/Pagination/_docs/Pagination.stickersheet.stories.tsx +60 -74
- package/src/Pagination/subcomponents/DirectionalLink/_docs/DirectionalLink.stickersheet.stories.tsx +21 -23
- package/src/Pagination/subcomponents/PaginationLink/_docs/PaginationLink.stickersheet.stories.tsx +24 -28
- package/src/Popover/_docs/Popover.stickersheet.stories.tsx +33 -45
- package/src/ProgressBar/_docs/ProgressBar.stickersheet.stories.tsx +15 -26
- package/src/Radio/Radio/_docs/Radio.stickersheet.stories.tsx +46 -54
- package/src/Radio/RadioField/_docs/RadioField.stickersheet.stories.tsx +51 -54
- package/src/Radio/RadioGroup/_docs/RadioGroup.stickersheet.stories.tsx +80 -86
- package/src/RichTextEditor/EditableRichTextContent/_docs/EditableRichTextContent.stickersheet.stories.tsx +42 -58
- package/src/RichTextEditor/RichTextEditor/subcomponents/ToggleIconButton/_docs/ToggleIconButton.stickersheet.stories.tsx +34 -57
- package/src/SearchField/_docs/SearchField.stickersheet.stories.tsx +32 -31
- package/src/Select/_docs/Select.stickersheet.stories.tsx +128 -127
- package/src/Slider/_docs/Slider.stickersheet.stories.tsx +85 -96
- package/src/SplitButton/_docs/SplitButton.stickersheet.stories.tsx +62 -68
- package/src/Tag/_docs/Tag.stickersheet.stories.tsx +49 -57
- package/src/Text/_docs/Text.stickersheet.stories.tsx +43 -47
- package/src/TextArea/_docs/TextArea.stickersheet.stories.tsx +28 -31
- package/src/TextAreaField/_docs/TextAreaField.stickersheet.stories.tsx +71 -89
- package/src/TextField/_docs/TextField.stickersheet.stories.tsx +47 -50
- package/src/Tile/InformationTile/_docs/InformationTile.mdx +4 -0
- package/src/Tile/InformationTile/_docs/InformationTile.stickersheet.stories.tsx +15 -21
- package/src/Tile/InformationTile/_docs/InformationTile.stories.tsx +7 -0
- package/src/Tile/MultiActionTile/_docs/MultiActionTile.stickersheet.stories.tsx +15 -21
- package/src/Tile/TileGrid/_docs/TileGrid.stickersheet.stories.tsx +91 -99
- package/src/Tile/subcomponents/GenericTile/GenericTile.spec.stories.tsx +65 -5
- package/src/Tile/subcomponents/GenericTile/GenericTile.tsx +20 -2
- package/src/Tile/subcomponents/GenericTile/_docs/GenericTile.stickersheet.stories.tsx +15 -21
- package/src/TimeField/_docs/TimeField.stickersheet.stories.tsx +74 -83
- package/src/TitleBlockZen/_docs/TitleBlockZen.stories.tsx +73 -75
- package/src/ToggleSwitch/ToggleSwitch/_docs/ToggleSwitch.stickersheet.stories.tsx +24 -27
- package/src/ToggleSwitch/ToggleSwitchField/_docs/ToggleSwitchField.stickersheet.stories.tsx +47 -50
- package/src/Well/_docs/Well.stickersheet.stories.tsx +31 -41
- package/src/__actions__/Button/v1/Button/_docs/Button.stickersheet.stories.tsx +107 -146
- package/src/__actions__/Button/v1/IconButton/_docs/IconButton.stickersheet.stories.tsx +26 -29
- package/src/__actions__/Button/v3/_docs/Button.stickersheet.stories.tsx +141 -159
- package/src/__actions__/Menu/v1/_docs/Menu.stickersheet.stories.tsx +33 -36
- package/src/__future__/Icon/_docs/Icon.docs.stories.tsx +17 -23
- package/src/__future__/Icon/_docs/Icon.stickersheet.stories.tsx +63 -72
- package/src/__future__/Select/_docs/Select.stickersheet.stories.tsx +287 -309
- package/src/__future__/Tag/RemovableTag/_docs/RemovableTag.stickersheet.stories.tsx +42 -46
- package/src/__future__/Tag/Tag/_docs/Tag.stickersheet.stories.tsx +14 -17
- package/src/__overlays__/Tooltip/v1/_docs/Tooltip.stickersheet.stories.tsx +101 -103
- package/src/__overlays__/Tooltip/v3/_docs/Tooltip.stickersheet.stories.tsx +3 -4
|
@@ -35,23 +35,21 @@ const StickerSheetTemplate: StickerSheetStory = {
|
|
|
35
35
|
|
|
36
36
|
return (
|
|
37
37
|
<StickerSheet
|
|
38
|
-
|
|
38
|
+
title="Filter"
|
|
39
39
|
style={{ paddingBottom: IS_CHROMATIC ? "6rem" : undefined }}
|
|
40
|
+
headers={["Open"]}
|
|
40
41
|
>
|
|
41
|
-
<StickerSheet.
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
</Filter>
|
|
53
|
-
</StickerSheet.Row>
|
|
54
|
-
</StickerSheet.Body>
|
|
42
|
+
<StickerSheet.Row>
|
|
43
|
+
<Filter
|
|
44
|
+
isOpen={isOpen}
|
|
45
|
+
setIsOpen={setIsOpen}
|
|
46
|
+
renderTrigger={(triggerProps): JSX.Element => (
|
|
47
|
+
<FilterButton label="Label" {...triggerProps} />
|
|
48
|
+
)}
|
|
49
|
+
>
|
|
50
|
+
<FilterContents>Filter Contents</FilterContents>
|
|
51
|
+
</Filter>
|
|
52
|
+
</StickerSheet.Row>
|
|
55
53
|
</StickerSheet>
|
|
56
54
|
)
|
|
57
55
|
},
|
|
@@ -722,70 +722,6 @@ describe("<FilterBar />", () => {
|
|
|
722
722
|
})
|
|
723
723
|
})
|
|
724
724
|
|
|
725
|
-
describe("Clear all", () => {
|
|
726
|
-
it("clears all the values of all the filters", async () => {
|
|
727
|
-
const { getByRole } = render(
|
|
728
|
-
<FilterBarWrapper<ValuesSimple>
|
|
729
|
-
filters={simpleFilters}
|
|
730
|
-
defaultValues={{
|
|
731
|
-
flavour: "jasmine-milk-tea",
|
|
732
|
-
sugarLevel: 50,
|
|
733
|
-
iceLevel: 100,
|
|
734
|
-
}}
|
|
735
|
-
/>
|
|
736
|
-
)
|
|
737
|
-
await waitForI18nContent()
|
|
738
|
-
|
|
739
|
-
const flavourButton = getByRole("button", {
|
|
740
|
-
name: "Flavour : Jasmine Milk Tea",
|
|
741
|
-
})
|
|
742
|
-
const sugarLevelButton = getByRole("button", {
|
|
743
|
-
name: "Sugar Level : 50%",
|
|
744
|
-
})
|
|
745
|
-
const iceLevelButton = getByRole("button", { name: "Ice Level : 100%" })
|
|
746
|
-
|
|
747
|
-
expect(flavourButton).toHaveAccessibleName("Flavour : Jasmine Milk Tea")
|
|
748
|
-
expect(sugarLevelButton).toHaveAccessibleName("Sugar Level : 50%")
|
|
749
|
-
expect(iceLevelButton).toHaveAccessibleName("Ice Level : 100%")
|
|
750
|
-
|
|
751
|
-
await user.click(getByRole("button", { name: "Clear all filters" }))
|
|
752
|
-
|
|
753
|
-
await waitFor(() => {
|
|
754
|
-
expect(flavourButton).toHaveAccessibleName("Flavour")
|
|
755
|
-
expect(sugarLevelButton).toHaveAccessibleName("Sugar Level")
|
|
756
|
-
expect(iceLevelButton).toHaveAccessibleName("Ice Level")
|
|
757
|
-
})
|
|
758
|
-
})
|
|
759
|
-
|
|
760
|
-
it("removes all removable filters", async () => {
|
|
761
|
-
const { getByRole } = render(
|
|
762
|
-
<FilterBarWrapper<ValuesRemovable>
|
|
763
|
-
filters={filtersRemovable}
|
|
764
|
-
defaultValues={{
|
|
765
|
-
flavour: "jasmine-milk-tea",
|
|
766
|
-
topping: "pearls",
|
|
767
|
-
}}
|
|
768
|
-
/>
|
|
769
|
-
)
|
|
770
|
-
await waitForI18nContent()
|
|
771
|
-
|
|
772
|
-
const flavourButton = getByRole("button", {
|
|
773
|
-
name: "Flavour : Jasmine Milk Tea",
|
|
774
|
-
})
|
|
775
|
-
const toppingButton = getByRole("button", { name: "Topping : Pearls" })
|
|
776
|
-
|
|
777
|
-
expect(flavourButton).toBeVisible()
|
|
778
|
-
expect(toppingButton).toBeVisible()
|
|
779
|
-
|
|
780
|
-
await user.click(getByRole("button", { name: "Clear all filters" }))
|
|
781
|
-
|
|
782
|
-
await waitFor(() => {
|
|
783
|
-
expect(flavourButton).not.toBeInTheDocument()
|
|
784
|
-
expect(toppingButton).not.toBeInTheDocument()
|
|
785
|
-
})
|
|
786
|
-
})
|
|
787
|
-
})
|
|
788
|
-
|
|
789
725
|
describe("External events", () => {
|
|
790
726
|
it("allows updating the values via an external event", async () => {
|
|
791
727
|
const Wrapper = (): JSX.Element => {
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import React, { useState } from "react"
|
|
2
|
+
import { Meta, StoryObj } from "@storybook/react"
|
|
3
|
+
import { expect, userEvent, waitFor, within, fn } from "@storybook/test"
|
|
4
|
+
import { FilterMultiSelect } from "~components/Filter/FilterMultiSelect"
|
|
5
|
+
import { DateRange } from "~components/index"
|
|
6
|
+
import { FilterBar, Filters } from "../index"
|
|
7
|
+
|
|
8
|
+
const meta = {
|
|
9
|
+
title: "Components/FilterBar/FilterBar Tests",
|
|
10
|
+
component: FilterBar,
|
|
11
|
+
argTypes: {
|
|
12
|
+
filters: { control: false },
|
|
13
|
+
values: { control: false },
|
|
14
|
+
onValuesChange: { control: false },
|
|
15
|
+
},
|
|
16
|
+
args: {
|
|
17
|
+
filters: [], // Defined in stories
|
|
18
|
+
values: {}, // Defined in stories
|
|
19
|
+
onValuesChange: fn(),
|
|
20
|
+
},
|
|
21
|
+
} satisfies Meta<typeof FilterBar>
|
|
22
|
+
|
|
23
|
+
export default meta
|
|
24
|
+
|
|
25
|
+
type Story = StoryObj<typeof meta>
|
|
26
|
+
|
|
27
|
+
type Values = {
|
|
28
|
+
flavour: string
|
|
29
|
+
deliveryDates: DateRange
|
|
30
|
+
toppings: string[]
|
|
31
|
+
drank: Date
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const filters = [
|
|
35
|
+
{
|
|
36
|
+
id: "flavour",
|
|
37
|
+
name: "Flavour",
|
|
38
|
+
Component: (
|
|
39
|
+
<FilterBar.Select
|
|
40
|
+
items={[
|
|
41
|
+
{ value: "jasmine-milk-tea", label: "Jasmine Milk Tea" },
|
|
42
|
+
{ value: "honey-milk-tea", label: "Honey Milk Tea" },
|
|
43
|
+
{ value: "lychee-green-tea", label: "Lychee Green Tea" },
|
|
44
|
+
]}
|
|
45
|
+
/>
|
|
46
|
+
),
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
id: "deliveryDates",
|
|
50
|
+
name: "Delivery Dates",
|
|
51
|
+
Component: <FilterBar.DateRangePicker />,
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: "toppings",
|
|
55
|
+
name: "Toppings",
|
|
56
|
+
Component: (
|
|
57
|
+
<FilterBar.MultiSelect
|
|
58
|
+
items={[
|
|
59
|
+
{ value: "none", label: "None" },
|
|
60
|
+
{ value: "pearls", label: "Pearls" },
|
|
61
|
+
{ value: "fruit-jelly", label: "Fruit Jelly" },
|
|
62
|
+
{ value: "peanuts", label: "Peanuts" },
|
|
63
|
+
{ value: "coconut", label: "Coconut" },
|
|
64
|
+
{ value: "aloe", label: "Aloe Vera" },
|
|
65
|
+
{ value: "mochi", label: "Mini Mochi" },
|
|
66
|
+
{ value: "popping-pearls", label: "Popping Pearls" },
|
|
67
|
+
]}
|
|
68
|
+
>
|
|
69
|
+
{(): JSX.Element => (
|
|
70
|
+
<>
|
|
71
|
+
<FilterMultiSelect.SearchInput />
|
|
72
|
+
<FilterMultiSelect.ListBox>
|
|
73
|
+
{({ allItems }): JSX.Element | JSX.Element[] =>
|
|
74
|
+
allItems.map(item => (
|
|
75
|
+
<FilterMultiSelect.Option key={item.key} item={item} />
|
|
76
|
+
))
|
|
77
|
+
}
|
|
78
|
+
</FilterMultiSelect.ListBox>
|
|
79
|
+
<FilterMultiSelect.MenuFooter>
|
|
80
|
+
<FilterMultiSelect.SelectAllButton />
|
|
81
|
+
<FilterMultiSelect.ClearButton />
|
|
82
|
+
</FilterMultiSelect.MenuFooter>
|
|
83
|
+
</>
|
|
84
|
+
)}
|
|
85
|
+
</FilterBar.MultiSelect>
|
|
86
|
+
),
|
|
87
|
+
isRemovable: true,
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
id: "drank",
|
|
91
|
+
name: "Drank",
|
|
92
|
+
Component: <FilterBar.DatePicker />,
|
|
93
|
+
isRemovable: true,
|
|
94
|
+
},
|
|
95
|
+
] satisfies Filters<Values>
|
|
96
|
+
|
|
97
|
+
export const ClearAllFromValue: Story = {
|
|
98
|
+
render: args => {
|
|
99
|
+
const [activeValues, onActiveValuesChange] = useState<Partial<Values>>({})
|
|
100
|
+
return (
|
|
101
|
+
<FilterBar<Values>
|
|
102
|
+
{...args}
|
|
103
|
+
filters={filters}
|
|
104
|
+
values={activeValues}
|
|
105
|
+
onValuesChange={onActiveValuesChange}
|
|
106
|
+
/>
|
|
107
|
+
)
|
|
108
|
+
},
|
|
109
|
+
play: async ({ canvasElement, step }) => {
|
|
110
|
+
const canvas = within(canvasElement.parentElement!)
|
|
111
|
+
|
|
112
|
+
await step(
|
|
113
|
+
"Clear all button hidden by default given no values",
|
|
114
|
+
async () => {
|
|
115
|
+
expect(
|
|
116
|
+
canvas.queryByRole("button", {
|
|
117
|
+
name: "Clear all filters",
|
|
118
|
+
})
|
|
119
|
+
).not.toBeInTheDocument()
|
|
120
|
+
}
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
await step("filter value is added", async () => {
|
|
124
|
+
await userEvent.click(canvas.getByRole("button", { name: "Flavour" }))
|
|
125
|
+
await userEvent.click(
|
|
126
|
+
canvas.getByRole("option", { name: "Jasmine Milk Tea" })
|
|
127
|
+
)
|
|
128
|
+
expect(
|
|
129
|
+
canvas.getByRole("button", { name: "Flavour: Jasmine Milk Tea" })
|
|
130
|
+
).toBeInTheDocument()
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
await step(
|
|
134
|
+
"'Clear all' press removes the value and hides itself",
|
|
135
|
+
async () => {
|
|
136
|
+
const clearAllButton = canvas.getByRole("button", {
|
|
137
|
+
name: "Clear all filters",
|
|
138
|
+
})
|
|
139
|
+
userEvent.click(clearAllButton)
|
|
140
|
+
|
|
141
|
+
waitFor(() =>
|
|
142
|
+
expect(
|
|
143
|
+
canvas.getByRole("button", { name: "Flavour" })
|
|
144
|
+
).toBeInTheDocument()
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
waitFor(() =>
|
|
148
|
+
expect(
|
|
149
|
+
canvas.queryByRole("button", {
|
|
150
|
+
name: "Clear all filters",
|
|
151
|
+
})
|
|
152
|
+
).not.toBeInTheDocument()
|
|
153
|
+
)
|
|
154
|
+
}
|
|
155
|
+
)
|
|
156
|
+
},
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export const ClearAllFromRemovable: Story = {
|
|
160
|
+
render: args => {
|
|
161
|
+
const [activeValues, onActiveValuesChange] = useState<Partial<Values>>({})
|
|
162
|
+
return (
|
|
163
|
+
<FilterBar<Values>
|
|
164
|
+
{...args}
|
|
165
|
+
filters={filters}
|
|
166
|
+
values={activeValues}
|
|
167
|
+
onValuesChange={onActiveValuesChange}
|
|
168
|
+
/>
|
|
169
|
+
)
|
|
170
|
+
},
|
|
171
|
+
play: async ({ canvasElement, step }) => {
|
|
172
|
+
const canvas = within(canvasElement.parentElement!)
|
|
173
|
+
|
|
174
|
+
await step("removable filter is added with no value", async () => {
|
|
175
|
+
await waitFor(() => {
|
|
176
|
+
userEvent.click(canvas.getByRole("button", { name: "Add Filters" }))
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
await waitFor(() => {
|
|
180
|
+
userEvent.click(canvas.getByRole("button", { name: "Toppings" }))
|
|
181
|
+
})
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
await step("'Clear all' press removes removable filter", async () => {
|
|
185
|
+
await waitFor(() => {
|
|
186
|
+
userEvent.click(
|
|
187
|
+
canvas.getByRole("button", {
|
|
188
|
+
name: "Clear all filters",
|
|
189
|
+
})
|
|
190
|
+
)
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
waitFor(() =>
|
|
194
|
+
expect(
|
|
195
|
+
canvas.queryByRole("button", { name: "Toppings" })
|
|
196
|
+
).not.toBeInTheDocument()
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
waitFor(() =>
|
|
200
|
+
expect(
|
|
201
|
+
canvas.queryByRole("button", {
|
|
202
|
+
name: "Clear all filters",
|
|
203
|
+
})
|
|
204
|
+
).not.toBeInTheDocument()
|
|
205
|
+
)
|
|
206
|
+
})
|
|
207
|
+
},
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export const ClearAllRemovesItself: Story = {
|
|
211
|
+
render: args => {
|
|
212
|
+
const [activeValues, onActiveValuesChange] = useState<Partial<Values>>({})
|
|
213
|
+
return (
|
|
214
|
+
<FilterBar<Values>
|
|
215
|
+
{...args}
|
|
216
|
+
filters={filters}
|
|
217
|
+
values={activeValues}
|
|
218
|
+
onValuesChange={onActiveValuesChange}
|
|
219
|
+
/>
|
|
220
|
+
)
|
|
221
|
+
},
|
|
222
|
+
play: async ({ canvasElement, step }) => {
|
|
223
|
+
const canvas = within(canvasElement.parentElement!)
|
|
224
|
+
|
|
225
|
+
await step("removable filter is added with no value", async () => {
|
|
226
|
+
await waitFor(() =>
|
|
227
|
+
userEvent.click(canvas.getByRole("button", { name: "Add Filters" }))
|
|
228
|
+
)
|
|
229
|
+
await userEvent.click(canvas.getByRole("button", { name: "Drank" }))
|
|
230
|
+
})
|
|
231
|
+
|
|
232
|
+
await step(
|
|
233
|
+
"Clear all button hides by itself after removing filter",
|
|
234
|
+
async () => {
|
|
235
|
+
await userEvent.click(
|
|
236
|
+
canvas.getByRole("button", { name: "Remove filter - Drank" })
|
|
237
|
+
)
|
|
238
|
+
}
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
waitFor(() =>
|
|
242
|
+
expect(
|
|
243
|
+
canvas.queryByRole("button", {
|
|
244
|
+
name: "Clear all filters",
|
|
245
|
+
})
|
|
246
|
+
).not.toBeInTheDocument()
|
|
247
|
+
)
|
|
248
|
+
},
|
|
249
|
+
}
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
import { FilterBar, Filters } from "../index"
|
|
8
8
|
|
|
9
9
|
export default {
|
|
10
|
-
title: "Components/
|
|
10
|
+
title: "Components/FilterBar",
|
|
11
11
|
parameters: {
|
|
12
12
|
chromatic: { disable: false },
|
|
13
13
|
controls: { disable: true },
|
|
@@ -122,60 +122,46 @@ const StickerSheetTemplate: StickerSheetStory = {
|
|
|
122
122
|
|
|
123
123
|
return (
|
|
124
124
|
<>
|
|
125
|
-
<StickerSheet
|
|
126
|
-
<StickerSheet.
|
|
127
|
-
<
|
|
125
|
+
<StickerSheet title="Filter Bar" layout="stretch">
|
|
126
|
+
<StickerSheet.Row>
|
|
127
|
+
<FilterBar<Values>
|
|
128
|
+
filters={filters}
|
|
129
|
+
values={activeValues}
|
|
130
|
+
onValuesChange={setActiveValues}
|
|
131
|
+
/>
|
|
132
|
+
</StickerSheet.Row>
|
|
133
|
+
</StickerSheet>
|
|
134
|
+
|
|
135
|
+
<StickerSheet title="Overflow (container 500px)" layout="stretch">
|
|
136
|
+
<StickerSheet.Row>
|
|
137
|
+
<div style={{ maxWidth: "500px" }}>
|
|
128
138
|
<FilterBar<Values>
|
|
129
139
|
filters={filters}
|
|
130
|
-
values={
|
|
131
|
-
onValuesChange={
|
|
140
|
+
values={activeValuesOverflow}
|
|
141
|
+
onValuesChange={setActiveValuesOverflow}
|
|
132
142
|
/>
|
|
133
|
-
</
|
|
134
|
-
</StickerSheet.
|
|
135
|
-
</StickerSheet>
|
|
136
|
-
|
|
137
|
-
<StickerSheet
|
|
138
|
-
heading="Overflow (container 500px)"
|
|
139
|
-
style={{ width: "100%" }}
|
|
140
|
-
>
|
|
141
|
-
<StickerSheet.Body>
|
|
142
|
-
<StickerSheet.Row>
|
|
143
|
-
<div style={{ maxWidth: "500px" }}>
|
|
144
|
-
<FilterBar<Values>
|
|
145
|
-
filters={filters}
|
|
146
|
-
values={activeValuesOverflow}
|
|
147
|
-
onValuesChange={setActiveValuesOverflow}
|
|
148
|
-
/>
|
|
149
|
-
</div>
|
|
150
|
-
</StickerSheet.Row>
|
|
151
|
-
</StickerSheet.Body>
|
|
143
|
+
</div>
|
|
144
|
+
</StickerSheet.Row>
|
|
152
145
|
</StickerSheet>
|
|
153
146
|
|
|
154
|
-
<StickerSheet
|
|
155
|
-
<StickerSheet.
|
|
156
|
-
<
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
</StickerSheet.Row>
|
|
163
|
-
</StickerSheet.Body>
|
|
147
|
+
<StickerSheet title="Removable; All active" layout="stretch">
|
|
148
|
+
<StickerSheet.Row>
|
|
149
|
+
<FilterBar<ValuesRemovable>
|
|
150
|
+
filters={removableFilters}
|
|
151
|
+
values={valuesRemovableAllActive}
|
|
152
|
+
onValuesChange={setValuesRemovableAllActive}
|
|
153
|
+
/>
|
|
154
|
+
</StickerSheet.Row>
|
|
164
155
|
</StickerSheet>
|
|
165
156
|
|
|
166
|
-
<StickerSheet
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
values={valuesRemovablePartialActive}
|
|
175
|
-
onValuesChange={setValuesRemovablePartialActive}
|
|
176
|
-
/>
|
|
177
|
-
</StickerSheet.Row>
|
|
178
|
-
</StickerSheet.Body>
|
|
157
|
+
<StickerSheet title="Removable; Partial active" layout="stretch">
|
|
158
|
+
<StickerSheet.Row>
|
|
159
|
+
<FilterBar<ValuesRemovable>
|
|
160
|
+
filters={removableFilters}
|
|
161
|
+
values={valuesRemovablePartialActive}
|
|
162
|
+
onValuesChange={setValuesRemovablePartialActive}
|
|
163
|
+
/>
|
|
164
|
+
</StickerSheet.Row>
|
|
179
165
|
</StickerSheet>
|
|
180
166
|
</>
|
|
181
167
|
)
|
|
@@ -21,7 +21,7 @@ import { FilterBar, Filters, useFilterBarContext } from "../index"
|
|
|
21
21
|
import { FilterBarMultiSelectProps } from "../subcomponents"
|
|
22
22
|
|
|
23
23
|
const meta = {
|
|
24
|
-
title: "Components/
|
|
24
|
+
title: "Components/FilterBar",
|
|
25
25
|
component: FilterBar,
|
|
26
26
|
argTypes: {
|
|
27
27
|
filters: { control: false },
|
|
@@ -22,6 +22,7 @@ export type FilterBarContextValue<
|
|
|
22
22
|
getFilterState: <Id extends keyof ValuesMap>(
|
|
23
23
|
id: Id
|
|
24
24
|
) => FilterState<keyof ValuesMap, ValuesMap[Id]>
|
|
25
|
+
isClearable: boolean
|
|
25
26
|
getActiveFilterValues: () => Partial<ValuesMap>
|
|
26
27
|
/**
|
|
27
28
|
* @deprecated Use `setFilterOpenState` instead.
|
|
@@ -90,12 +91,28 @@ export const FilterBarProvider = <ValuesMap extends FiltersValues>({
|
|
|
90
91
|
setupFilterBarState<ValuesMap>(filters, values)
|
|
91
92
|
)
|
|
92
93
|
|
|
94
|
+
const activeFilters = Array.from(
|
|
95
|
+
state.activeFilterIds,
|
|
96
|
+
id => mappedFilters[id]
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
// Workaround for DateRangePicker populating the values object before the value is valid
|
|
100
|
+
// (it purposefully persists a state with a 'from' date but no 'to' date, but hides it on the filter button)
|
|
101
|
+
const isDraftDateRange = (v: ValuesMap): boolean =>
|
|
102
|
+
v && v.from !== undefined && v.to === undefined
|
|
103
|
+
const hasDraftDateRangeOnly = Object.values(values).every(isDraftDateRange)
|
|
104
|
+
|
|
105
|
+
const isClearable =
|
|
106
|
+
(Object.keys(values).length > 0 && !hasDraftDateRangeOnly) ||
|
|
107
|
+
(state.hasRemovableFilter && activeFilters.some(f => f.isRemovable))
|
|
108
|
+
|
|
93
109
|
const value = {
|
|
94
110
|
getFilterState: <Id extends keyof ValuesMap>(id: Id) => ({
|
|
95
111
|
...state.filters[id],
|
|
96
112
|
isActive: state.activeFilterIds.has(id),
|
|
97
113
|
value: values[id],
|
|
98
114
|
}),
|
|
115
|
+
isClearable,
|
|
99
116
|
getActiveFilterValues: () => values,
|
|
100
117
|
toggleOpenFilter: <Id extends keyof ValuesMap>(
|
|
101
118
|
id: Id,
|
|
@@ -163,11 +180,6 @@ export const FilterBarProvider = <ValuesMap extends FiltersValues>({
|
|
|
163
180
|
}
|
|
164
181
|
}, [filters])
|
|
165
182
|
|
|
166
|
-
const activeFilters = Array.from(
|
|
167
|
-
state.activeFilterIds,
|
|
168
|
-
id => mappedFilters[id]
|
|
169
|
-
)
|
|
170
|
-
|
|
171
183
|
return (
|
|
172
184
|
<FilterBarContext.Provider
|
|
173
185
|
// @note: Context object cannot be generic, thus the type-casting to a looser type
|
|
@@ -32,6 +32,7 @@ describe("filterBarStateReducer", () => {
|
|
|
32
32
|
values: {},
|
|
33
33
|
dependentFilterIds: new Set(),
|
|
34
34
|
hasUpdatedValues: true,
|
|
35
|
+
hasRemovableFilter: false,
|
|
35
36
|
} satisfies FilterBarState<Values>
|
|
36
37
|
|
|
37
38
|
const newState = filterBarStateReducer<Values>(state, {
|
|
@@ -50,6 +51,7 @@ describe("filterBarStateReducer", () => {
|
|
|
50
51
|
values: {},
|
|
51
52
|
dependentFilterIds: new Set(),
|
|
52
53
|
hasUpdatedValues: false,
|
|
54
|
+
hasRemovableFilter: false,
|
|
53
55
|
} satisfies FilterBarState<Values>
|
|
54
56
|
|
|
55
57
|
const newState = filterBarStateReducer<Values>(state, {
|
|
@@ -71,6 +73,7 @@ describe("filterBarStateReducer", () => {
|
|
|
71
73
|
values: { flavour: "jasmine" },
|
|
72
74
|
dependentFilterIds: new Set(),
|
|
73
75
|
hasUpdatedValues: false,
|
|
76
|
+
hasRemovableFilter: false,
|
|
74
77
|
} satisfies FilterBarState<Values>
|
|
75
78
|
|
|
76
79
|
const newState = filterBarStateReducer<Values>(state, {
|
|
@@ -49,7 +49,7 @@ export const filterBarStateReducer = <ValuesMap extends FiltersValues>(
|
|
|
49
49
|
|
|
50
50
|
case "deactivate_filter":
|
|
51
51
|
state.activeFilterIds.delete(action.id)
|
|
52
|
-
state.values[action.id]
|
|
52
|
+
delete state.values[action.id]
|
|
53
53
|
return {
|
|
54
54
|
...updateDependentFilters(state),
|
|
55
55
|
hasUpdatedValues: true,
|
|
@@ -17,6 +17,16 @@ const filters = [
|
|
|
17
17
|
},
|
|
18
18
|
] satisfies Filters<Values>
|
|
19
19
|
|
|
20
|
+
const filtersNoRemovable = [
|
|
21
|
+
{ id: "flavour", name: "Flavour", Component: <div /> },
|
|
22
|
+
{
|
|
23
|
+
id: "sugarLevel",
|
|
24
|
+
name: "Sugar Level",
|
|
25
|
+
Component: <div />,
|
|
26
|
+
isRemovable: false,
|
|
27
|
+
},
|
|
28
|
+
] satisfies Filters<Values>
|
|
29
|
+
|
|
20
30
|
describe("setupFilterBarState()", () => {
|
|
21
31
|
it("sets up the base state correctly", () => {
|
|
22
32
|
const values = { flavour: "jasmine", sugarLevel: 50 }
|
|
@@ -41,6 +51,7 @@ describe("setupFilterBarState()", () => {
|
|
|
41
51
|
values,
|
|
42
52
|
dependentFilterIds: new Set<keyof Values>(),
|
|
43
53
|
hasUpdatedValues: false,
|
|
54
|
+
hasRemovableFilter: true,
|
|
44
55
|
})
|
|
45
56
|
})
|
|
46
57
|
|
|
@@ -65,4 +76,33 @@ describe("setupFilterBarState()", () => {
|
|
|
65
76
|
expect(state.hasUpdatedValues).toBe(true)
|
|
66
77
|
})
|
|
67
78
|
})
|
|
79
|
+
|
|
80
|
+
describe("Removable filters", () => {
|
|
81
|
+
it("hasRemovableFilter as false when there's no removable filters", () => {
|
|
82
|
+
const values = {}
|
|
83
|
+
expect(setupFilterBarState<Values>(filtersNoRemovable, values)).toEqual({
|
|
84
|
+
filters: {
|
|
85
|
+
flavour: {
|
|
86
|
+
id: "flavour",
|
|
87
|
+
name: "Flavour",
|
|
88
|
+
isRemovable: false,
|
|
89
|
+
isOpen: false,
|
|
90
|
+
isUsable: true,
|
|
91
|
+
},
|
|
92
|
+
sugarLevel: {
|
|
93
|
+
id: "sugarLevel",
|
|
94
|
+
name: "Sugar Level",
|
|
95
|
+
isRemovable: false,
|
|
96
|
+
isOpen: false,
|
|
97
|
+
isUsable: true,
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
activeFilterIds: new Set(["flavour", "sugarLevel"]),
|
|
101
|
+
values,
|
|
102
|
+
dependentFilterIds: new Set<keyof Values>(),
|
|
103
|
+
hasUpdatedValues: false,
|
|
104
|
+
hasRemovableFilter: false,
|
|
105
|
+
})
|
|
106
|
+
})
|
|
107
|
+
})
|
|
68
108
|
})
|
|
@@ -27,6 +27,10 @@ export const setupFilterBarState = <ValuesMap extends FiltersValues>(
|
|
|
27
27
|
baseState.activeFilterIds.add(id)
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
if (isRemovable) {
|
|
31
|
+
baseState.hasRemovableFilter = true
|
|
32
|
+
}
|
|
33
|
+
|
|
30
34
|
return baseState
|
|
31
35
|
},
|
|
32
36
|
{
|
|
@@ -35,6 +39,7 @@ export const setupFilterBarState = <ValuesMap extends FiltersValues>(
|
|
|
35
39
|
values,
|
|
36
40
|
dependentFilterIds: new Set(),
|
|
37
41
|
hasUpdatedValues: false,
|
|
42
|
+
hasRemovableFilter: false,
|
|
38
43
|
focusId: undefined,
|
|
39
44
|
} as FilterBarState<ValuesMap>
|
|
40
45
|
)
|
|
@@ -31,6 +31,7 @@ describe("filterBarStateReducer: update_single_filter", () => {
|
|
|
31
31
|
values: {},
|
|
32
32
|
dependentFilterIds: new Set(),
|
|
33
33
|
hasUpdatedValues: false,
|
|
34
|
+
hasRemovableFilter: false,
|
|
34
35
|
} satisfies FilterBarState<Values>
|
|
35
36
|
|
|
36
37
|
const newState = filterBarStateReducer<Values>(state, {
|
|
@@ -49,6 +50,7 @@ describe("filterBarStateReducer: update_single_filter", () => {
|
|
|
49
50
|
values: {},
|
|
50
51
|
dependentFilterIds: new Set(),
|
|
51
52
|
hasUpdatedValues: false,
|
|
53
|
+
hasRemovableFilter: false,
|
|
52
54
|
} satisfies FilterBarState<Values>
|
|
53
55
|
|
|
54
56
|
expect(state.filters.flavour.isOpen).toBe(false)
|
|
@@ -35,6 +35,7 @@ describe("filterBarStateReducer: update_values", () => {
|
|
|
35
35
|
values: {},
|
|
36
36
|
dependentFilterIds: new Set(),
|
|
37
37
|
hasUpdatedValues: false,
|
|
38
|
+
hasRemovableFilter: false,
|
|
38
39
|
} satisfies FilterBarState<Values>
|
|
39
40
|
|
|
40
41
|
const newState = filterBarStateReducer<Values>(state, {
|
|
@@ -65,6 +66,7 @@ describe("filterBarStateReducer: update_values", () => {
|
|
|
65
66
|
values: { sugarLevel: 50 },
|
|
66
67
|
dependentFilterIds: new Set<keyof Values>(["sugarLevel"]),
|
|
67
68
|
hasUpdatedValues: false,
|
|
69
|
+
hasRemovableFilter: false,
|
|
68
70
|
} satisfies FilterBarState<Values>
|
|
69
71
|
|
|
70
72
|
const newState = filterBarStateReducer<Values>(state, {
|
|
@@ -93,6 +95,7 @@ describe("filterBarStateReducer: update_values", () => {
|
|
|
93
95
|
values: {},
|
|
94
96
|
dependentFilterIds: new Set<keyof Values>(["sugarLevel"]),
|
|
95
97
|
hasUpdatedValues: false,
|
|
98
|
+
hasRemovableFilter: false,
|
|
96
99
|
} satisfies FilterBarState<Values>
|
|
97
100
|
|
|
98
101
|
const newState = filterBarStateReducer<Values>(state, {
|
|
@@ -122,6 +125,7 @@ describe("filterBarStateReducer: update_values", () => {
|
|
|
122
125
|
values: {},
|
|
123
126
|
dependentFilterIds: new Set<keyof Values>(["sugarLevel"]),
|
|
124
127
|
hasUpdatedValues: false,
|
|
128
|
+
hasRemovableFilter: false,
|
|
125
129
|
} satisfies FilterBarState<Values>
|
|
126
130
|
|
|
127
131
|
const newState = filterBarStateReducer<Values>(state, {
|
|
@@ -149,6 +153,7 @@ describe("filterBarStateReducer: update_values", () => {
|
|
|
149
153
|
values: {},
|
|
150
154
|
dependentFilterIds: new Set<keyof Values>(["sugarLevel"]),
|
|
151
155
|
hasUpdatedValues: false,
|
|
156
|
+
hasRemovableFilter: false,
|
|
152
157
|
} satisfies FilterBarState<Values>
|
|
153
158
|
|
|
154
159
|
const newState = filterBarStateReducer<Values>(state, {
|