@furystack/shades-common-components 12.3.0 → 12.5.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/CHANGELOG.md +86 -0
- package/esm/components/app-bar-link.spec.js +16 -19
- package/esm/components/app-bar-link.spec.js.map +1 -1
- package/esm/components/app-bar.spec.js +6 -4
- package/esm/components/app-bar.spec.js.map +1 -1
- package/esm/components/avatar.spec.js +9 -9
- package/esm/components/avatar.spec.js.map +1 -1
- package/esm/components/breadcrumb.spec.js +2 -2
- package/esm/components/breadcrumb.spec.js.map +1 -1
- package/esm/components/button-group.d.ts +32 -0
- package/esm/components/button-group.d.ts.map +1 -1
- package/esm/components/button-group.js +26 -2
- package/esm/components/button-group.js.map +1 -1
- package/esm/components/button-group.spec.js +127 -11
- package/esm/components/button-group.spec.js.map +1 -1
- package/esm/components/button.spec.js +4 -4
- package/esm/components/button.spec.js.map +1 -1
- package/esm/components/cache-view.spec.js +2 -3
- package/esm/components/cache-view.spec.js.map +1 -1
- package/esm/components/carousel.spec.js +47 -47
- package/esm/components/carousel.spec.js.map +1 -1
- package/esm/components/circular-progress.spec.js +2 -2
- package/esm/components/command-palette/command-palette-input.spec.js +23 -19
- package/esm/components/command-palette/command-palette-input.spec.js.map +1 -1
- package/esm/components/command-palette/command-palette-suggestion-list.spec.js +27 -27
- package/esm/components/command-palette/command-palette-suggestion-list.spec.js.map +1 -1
- package/esm/components/command-palette/index.spec.js +64 -51
- package/esm/components/command-palette/index.spec.js.map +1 -1
- package/esm/components/context-menu/context-menu.spec.js +33 -33
- package/esm/components/context-menu/context-menu.spec.js.map +1 -1
- package/esm/components/data-grid/body.spec.js +13 -13
- package/esm/components/data-grid/body.spec.js.map +1 -1
- package/esm/components/data-grid/data-grid-row.spec.js +8 -8
- package/esm/components/data-grid/data-grid-row.spec.js.map +1 -1
- package/esm/components/data-grid/data-grid.d.ts +40 -2
- package/esm/components/data-grid/data-grid.d.ts.map +1 -1
- package/esm/components/data-grid/data-grid.js +7 -10
- package/esm/components/data-grid/data-grid.js.map +1 -1
- package/esm/components/data-grid/data-grid.spec.js +71 -28
- package/esm/components/data-grid/data-grid.spec.js.map +1 -1
- package/esm/components/data-grid/filters/boolean-filter.d.ts +12 -0
- package/esm/components/data-grid/filters/boolean-filter.d.ts.map +1 -0
- package/esm/components/data-grid/filters/boolean-filter.js +27 -0
- package/esm/components/data-grid/filters/boolean-filter.js.map +1 -0
- package/esm/components/data-grid/filters/boolean-filter.spec.d.ts +2 -0
- package/esm/components/data-grid/filters/boolean-filter.spec.d.ts.map +1 -0
- package/esm/components/data-grid/filters/boolean-filter.spec.js +114 -0
- package/esm/components/data-grid/filters/boolean-filter.spec.js.map +1 -0
- package/esm/components/data-grid/filters/date-filter.d.ts +12 -0
- package/esm/components/data-grid/filters/date-filter.d.ts.map +1 -0
- package/esm/components/data-grid/filters/date-filter.js +109 -0
- package/esm/components/data-grid/filters/date-filter.js.map +1 -0
- package/esm/components/data-grid/filters/date-filter.spec.d.ts +2 -0
- package/esm/components/data-grid/filters/date-filter.spec.d.ts.map +1 -0
- package/esm/components/data-grid/filters/date-filter.spec.js +145 -0
- package/esm/components/data-grid/filters/date-filter.spec.js.map +1 -0
- package/esm/components/data-grid/filters/enum-filter.d.ts +16 -0
- package/esm/components/data-grid/filters/enum-filter.d.ts.map +1 -0
- package/esm/components/data-grid/filters/enum-filter.js +72 -0
- package/esm/components/data-grid/filters/enum-filter.js.map +1 -0
- package/esm/components/data-grid/filters/enum-filter.spec.d.ts +2 -0
- package/esm/components/data-grid/filters/enum-filter.spec.d.ts.map +1 -0
- package/esm/components/data-grid/filters/enum-filter.spec.js +136 -0
- package/esm/components/data-grid/filters/enum-filter.spec.js.map +1 -0
- package/esm/components/data-grid/filters/filter-dropdown.d.ts +6 -0
- package/esm/components/data-grid/filters/filter-dropdown.d.ts.map +1 -0
- package/esm/components/data-grid/filters/filter-dropdown.js +41 -0
- package/esm/components/data-grid/filters/filter-dropdown.js.map +1 -0
- package/esm/components/data-grid/filters/filter-dropdown.spec.d.ts +2 -0
- package/esm/components/data-grid/filters/filter-dropdown.spec.d.ts.map +1 -0
- package/esm/components/data-grid/filters/filter-dropdown.spec.js +69 -0
- package/esm/components/data-grid/filters/filter-dropdown.spec.js.map +1 -0
- package/esm/components/data-grid/filters/filter-styles.d.ts +24 -0
- package/esm/components/data-grid/filters/filter-styles.d.ts.map +1 -0
- package/esm/components/data-grid/filters/filter-styles.js +25 -0
- package/esm/components/data-grid/filters/filter-styles.js.map +1 -0
- package/esm/components/data-grid/filters/index.d.ts +7 -0
- package/esm/components/data-grid/filters/index.d.ts.map +1 -0
- package/esm/components/data-grid/filters/index.js +7 -0
- package/esm/components/data-grid/filters/index.js.map +1 -0
- package/esm/components/data-grid/filters/number-filter.d.ts +12 -0
- package/esm/components/data-grid/filters/number-filter.d.ts.map +1 -0
- package/esm/components/data-grid/filters/number-filter.js +65 -0
- package/esm/components/data-grid/filters/number-filter.js.map +1 -0
- package/esm/components/data-grid/filters/number-filter.spec.d.ts +2 -0
- package/esm/components/data-grid/filters/number-filter.spec.d.ts.map +1 -0
- package/esm/components/data-grid/filters/number-filter.spec.js +142 -0
- package/esm/components/data-grid/filters/number-filter.spec.js.map +1 -0
- package/esm/components/data-grid/filters/string-filter.d.ts +12 -0
- package/esm/components/data-grid/filters/string-filter.d.ts.map +1 -0
- package/esm/components/data-grid/filters/string-filter.js +63 -0
- package/esm/components/data-grid/filters/string-filter.js.map +1 -0
- package/esm/components/data-grid/filters/string-filter.spec.d.ts +2 -0
- package/esm/components/data-grid/filters/string-filter.spec.d.ts.map +1 -0
- package/esm/components/data-grid/filters/string-filter.spec.js +128 -0
- package/esm/components/data-grid/filters/string-filter.spec.js.map +1 -0
- package/esm/components/data-grid/footer.d.ts.map +1 -1
- package/esm/components/data-grid/footer.js +24 -9
- package/esm/components/data-grid/footer.js.map +1 -1
- package/esm/components/data-grid/footer.spec.js +38 -36
- package/esm/components/data-grid/footer.spec.js.map +1 -1
- package/esm/components/data-grid/header.d.ts +6 -9
- package/esm/components/data-grid/header.d.ts.map +1 -1
- package/esm/components/data-grid/header.js +51 -117
- package/esm/components/data-grid/header.js.map +1 -1
- package/esm/components/data-grid/header.spec.js +116 -187
- package/esm/components/data-grid/header.spec.js.map +1 -1
- package/esm/components/data-grid/index.d.ts +1 -0
- package/esm/components/data-grid/index.d.ts.map +1 -1
- package/esm/components/data-grid/index.js +1 -0
- package/esm/components/data-grid/index.js.map +1 -1
- package/esm/components/data-grid/selection-cell.spec.js +8 -8
- package/esm/components/data-grid/selection-cell.spec.js.map +1 -1
- package/esm/components/drawer/drawer-toggle-button.spec.js +22 -22
- package/esm/components/drawer/drawer-toggle-button.spec.js.map +1 -1
- package/esm/components/drawer/index.spec.js +36 -36
- package/esm/components/drawer/index.spec.js.map +1 -1
- package/esm/components/dropdown.spec.js +38 -30
- package/esm/components/dropdown.spec.js.map +1 -1
- package/esm/components/fab.spec.js +4 -4
- package/esm/components/fab.spec.js.map +1 -1
- package/esm/components/form.d.ts +5 -2
- package/esm/components/form.d.ts.map +1 -1
- package/esm/components/form.js +28 -6
- package/esm/components/form.js.map +1 -1
- package/esm/components/form.spec.js +227 -20
- package/esm/components/form.spec.js.map +1 -1
- package/esm/components/grid.spec.js +3 -3
- package/esm/components/grid.spec.js.map +1 -1
- package/esm/components/image.spec.js +55 -52
- package/esm/components/image.spec.js.map +1 -1
- package/esm/components/inputs/autocomplete.spec.js +7 -14
- package/esm/components/inputs/autocomplete.spec.js.map +1 -1
- package/esm/components/inputs/checkbox.spec.js +22 -22
- package/esm/components/inputs/checkbox.spec.js.map +1 -1
- package/esm/components/inputs/input-number.spec.js +47 -47
- package/esm/components/inputs/input-number.spec.js.map +1 -1
- package/esm/components/inputs/input.spec.js +53 -53
- package/esm/components/inputs/input.spec.js.map +1 -1
- package/esm/components/inputs/radio-group.spec.js +14 -14
- package/esm/components/inputs/radio-group.spec.js.map +1 -1
- package/esm/components/inputs/radio.spec.js +16 -16
- package/esm/components/inputs/radio.spec.js.map +1 -1
- package/esm/components/inputs/select.spec.js +74 -74
- package/esm/components/inputs/select.spec.js.map +1 -1
- package/esm/components/inputs/slider.spec.js +16 -16
- package/esm/components/inputs/slider.spec.js.map +1 -1
- package/esm/components/inputs/switch.spec.js +24 -24
- package/esm/components/inputs/switch.spec.js.map +1 -1
- package/esm/components/inputs/text-area.spec.js +17 -17
- package/esm/components/inputs/text-area.spec.js.map +1 -1
- package/esm/components/linear-progress.spec.js +2 -2
- package/esm/components/list/list.spec.js +36 -36
- package/esm/components/list/list.spec.js.map +1 -1
- package/esm/components/markdown/markdown-display.spec.js +15 -15
- package/esm/components/markdown/markdown-display.spec.js.map +1 -1
- package/esm/components/markdown/markdown-editor.spec.js +8 -8
- package/esm/components/markdown/markdown-editor.spec.js.map +1 -1
- package/esm/components/markdown/markdown-input.spec.js +17 -17
- package/esm/components/markdown/markdown-input.spec.js.map +1 -1
- package/esm/components/menu/menu.spec.js +28 -28
- package/esm/components/menu/menu.spec.js.map +1 -1
- package/esm/components/modal.spec.js +15 -18
- package/esm/components/modal.spec.js.map +1 -1
- package/esm/components/noty-list.spec.js +25 -23
- package/esm/components/noty-list.spec.js.map +1 -1
- package/esm/components/page-container/index.spec.js +16 -16
- package/esm/components/page-container/index.spec.js.map +1 -1
- package/esm/components/page-container/page-header.spec.js +16 -16
- package/esm/components/page-container/page-header.spec.js.map +1 -1
- package/esm/components/page-layout/index.spec.js +29 -29
- package/esm/components/page-layout/index.spec.js.map +1 -1
- package/esm/components/paper.spec.js +3 -3
- package/esm/components/paper.spec.js.map +1 -1
- package/esm/components/rating.spec.js +61 -61
- package/esm/components/rating.spec.js.map +1 -1
- package/esm/components/skeleton.spec.js +10 -6
- package/esm/components/skeleton.spec.js.map +1 -1
- package/esm/components/suggest/suggest-input.spec.js +4 -10
- package/esm/components/suggest/suggest-input.spec.js.map +1 -1
- package/esm/components/tabs.spec.js +30 -30
- package/esm/components/tabs.spec.js.map +1 -1
- package/esm/components/tree/tree.spec.js +27 -27
- package/esm/components/tree/tree.spec.js.map +1 -1
- package/esm/components/typography.spec.js +3 -3
- package/esm/components/typography.spec.js.map +1 -1
- package/esm/components/wizard/index.spec.js +5 -5
- package/esm/components/wizard/index.spec.js.map +1 -1
- package/esm/utils/promisify-animation.d.ts.map +1 -1
- package/esm/utils/promisify-animation.js +3 -0
- package/esm/utils/promisify-animation.js.map +1 -1
- package/package.json +2 -2
- package/src/components/app-bar-link.spec.tsx +16 -19
- package/src/components/app-bar.spec.tsx +6 -4
- package/src/components/avatar.spec.tsx +9 -9
- package/src/components/breadcrumb.spec.tsx +2 -2
- package/src/components/button-group.spec.tsx +155 -11
- package/src/components/button-group.tsx +49 -2
- package/src/components/button.spec.tsx +4 -4
- package/src/components/cache-view.spec.tsx +3 -3
- package/src/components/carousel.spec.tsx +47 -47
- package/src/components/circular-progress.spec.tsx +2 -2
- package/src/components/command-palette/command-palette-input.spec.tsx +23 -19
- package/src/components/command-palette/command-palette-suggestion-list.spec.tsx +27 -27
- package/src/components/command-palette/index.spec.tsx +64 -51
- package/src/components/context-menu/context-menu.spec.tsx +33 -33
- package/src/components/data-grid/body.spec.tsx +13 -13
- package/src/components/data-grid/data-grid-row.spec.tsx +8 -8
- package/src/components/data-grid/data-grid.spec.tsx +106 -28
- package/src/components/data-grid/data-grid.tsx +44 -11
- package/src/components/data-grid/filters/boolean-filter.spec.tsx +142 -0
- package/src/components/data-grid/filters/boolean-filter.tsx +45 -0
- package/src/components/data-grid/filters/date-filter.spec.tsx +181 -0
- package/src/components/data-grid/filters/date-filter.tsx +162 -0
- package/src/components/data-grid/filters/enum-filter.spec.tsx +168 -0
- package/src/components/data-grid/filters/enum-filter.tsx +119 -0
- package/src/components/data-grid/filters/filter-dropdown.spec.tsx +89 -0
- package/src/components/data-grid/filters/filter-dropdown.tsx +60 -0
- package/src/components/data-grid/filters/filter-styles.ts +26 -0
- package/src/components/data-grid/filters/index.ts +6 -0
- package/src/components/data-grid/filters/number-filter.spec.tsx +174 -0
- package/src/components/data-grid/filters/number-filter.tsx +115 -0
- package/src/components/data-grid/filters/string-filter.spec.tsx +157 -0
- package/src/components/data-grid/filters/string-filter.tsx +112 -0
- package/src/components/data-grid/footer.spec.tsx +38 -36
- package/src/components/data-grid/footer.tsx +21 -8
- package/src/components/data-grid/header.spec.tsx +128 -212
- package/src/components/data-grid/header.tsx +95 -183
- package/src/components/data-grid/index.tsx +1 -0
- package/src/components/data-grid/selection-cell.spec.tsx +8 -8
- package/src/components/drawer/drawer-toggle-button.spec.tsx +22 -22
- package/src/components/drawer/index.spec.tsx +36 -36
- package/src/components/dropdown.spec.tsx +38 -30
- package/src/components/fab.spec.tsx +4 -4
- package/src/components/form.spec.tsx +329 -20
- package/src/components/form.tsx +31 -8
- package/src/components/grid.spec.tsx +3 -3
- package/src/components/image.spec.tsx +55 -52
- package/src/components/inputs/autocomplete.spec.tsx +7 -14
- package/src/components/inputs/checkbox.spec.tsx +22 -22
- package/src/components/inputs/input-number.spec.tsx +47 -47
- package/src/components/inputs/input.spec.tsx +53 -53
- package/src/components/inputs/radio-group.spec.tsx +14 -14
- package/src/components/inputs/radio.spec.tsx +16 -16
- package/src/components/inputs/select.spec.tsx +74 -74
- package/src/components/inputs/slider.spec.tsx +16 -16
- package/src/components/inputs/switch.spec.tsx +24 -24
- package/src/components/inputs/text-area.spec.tsx +17 -17
- package/src/components/linear-progress.spec.tsx +2 -2
- package/src/components/list/list.spec.tsx +36 -36
- package/src/components/markdown/markdown-display.spec.tsx +15 -15
- package/src/components/markdown/markdown-editor.spec.tsx +8 -8
- package/src/components/markdown/markdown-input.spec.tsx +17 -17
- package/src/components/menu/menu.spec.tsx +28 -28
- package/src/components/modal.spec.tsx +15 -18
- package/src/components/noty-list.spec.tsx +25 -23
- package/src/components/page-container/index.spec.tsx +16 -16
- package/src/components/page-container/page-header.spec.tsx +16 -16
- package/src/components/page-layout/index.spec.tsx +29 -29
- package/src/components/paper.spec.tsx +3 -3
- package/src/components/rating.spec.tsx +61 -61
- package/src/components/skeleton.spec.tsx +10 -6
- package/src/components/suggest/suggest-input.spec.tsx +4 -10
- package/src/components/tabs.spec.tsx +30 -30
- package/src/components/tree/tree.spec.tsx +27 -27
- package/src/components/typography.spec.tsx +3 -3
- package/src/components/wizard/index.spec.tsx +5 -5
- package/src/utils/promisify-animation.ts +3 -0
|
@@ -1,29 +1,27 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { FindOptions } from '@furystack/core'
|
|
2
2
|
import type { ChildrenList } from '@furystack/shades'
|
|
3
3
|
import { Shade, createComponent } from '@furystack/shades'
|
|
4
4
|
import type { ObservableValue } from '@furystack/utils'
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { Button } from '../button.js'
|
|
8
|
-
import { Form } from '../form.js'
|
|
5
|
+
import { ToggleButton } from '../button-group.js'
|
|
6
|
+
import { arrowDown, arrowUp, arrowUpDown, filter as filterIcon } from '../icons/icon-definitions.js'
|
|
9
7
|
import { Icon } from '../icons/icon.js'
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
import type { ColumnFilterConfig, FilterableFindOptions } from './data-grid.js'
|
|
9
|
+
import { BooleanFilter } from './filters/boolean-filter.js'
|
|
10
|
+
import { DateFilter } from './filters/date-filter.js'
|
|
11
|
+
import { EnumFilter } from './filters/enum-filter.js'
|
|
12
|
+
import { FilterDropdown } from './filters/filter-dropdown.js'
|
|
13
|
+
import { NumberFilter } from './filters/number-filter.js'
|
|
14
|
+
import { StringFilter } from './filters/string-filter.js'
|
|
15
|
+
|
|
16
|
+
export type DataGridHeaderProps<T, Column extends string> = {
|
|
14
17
|
field: Column
|
|
15
18
|
findOptions: ObservableValue<FindOptions<T, Array<keyof T>>>
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
export interface DataGridHeaderState<T, K extends keyof T> {
|
|
19
|
-
findOptions: FindOptions<T, K[]>
|
|
20
|
-
isSearchOpened: boolean
|
|
21
|
-
updateSearchValue: (value: string) => void
|
|
19
|
+
filterConfig?: ColumnFilterConfig
|
|
22
20
|
}
|
|
23
21
|
|
|
24
22
|
export const OrderButton = Shade<{
|
|
25
23
|
field: string
|
|
26
|
-
findOptions: ObservableValue<
|
|
24
|
+
findOptions: ObservableValue<FilterableFindOptions>
|
|
27
25
|
}>({
|
|
28
26
|
shadowDomName: 'data-grid-order-button',
|
|
29
27
|
css: {
|
|
@@ -35,14 +33,15 @@ export const OrderButton = Shade<{
|
|
|
35
33
|
const currentOrder = Object.keys(findOptions.order || {})[0]
|
|
36
34
|
const currentOrderDirection = Object.values(findOptions.order || {})[0]
|
|
37
35
|
return (
|
|
38
|
-
<
|
|
36
|
+
<ToggleButton
|
|
39
37
|
title="Change order"
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
pressed={currentOrder === props.field}
|
|
39
|
+
size="small"
|
|
40
|
+
value={props.field}
|
|
42
41
|
onclick={(ev) => {
|
|
43
42
|
ev.stopPropagation()
|
|
44
43
|
let newDirection: 'ASC' | 'DESC' = 'ASC'
|
|
45
|
-
const newOrder:
|
|
44
|
+
const newOrder: Record<string, 'ASC' | 'DESC'> = {}
|
|
46
45
|
|
|
47
46
|
if (currentOrder === props.field) {
|
|
48
47
|
newDirection = currentOrderDirection === 'ASC' ? 'DESC' : 'ASC'
|
|
@@ -56,220 +55,133 @@ export const OrderButton = Shade<{
|
|
|
56
55
|
>
|
|
57
56
|
{(currentOrder === props.field &&
|
|
58
57
|
(currentOrderDirection === 'ASC' ? (
|
|
59
|
-
<Icon icon={arrowDown} size={
|
|
58
|
+
<Icon icon={arrowDown} size={14} />
|
|
60
59
|
) : (
|
|
61
|
-
<Icon icon={arrowUp} size={
|
|
62
|
-
))) || <Icon icon={arrowUpDown} size={
|
|
63
|
-
</
|
|
60
|
+
<Icon icon={arrowUp} size={14} />
|
|
61
|
+
))) || <Icon icon={arrowUpDown} size={14} />}
|
|
62
|
+
</ToggleButton>
|
|
64
63
|
)
|
|
65
64
|
},
|
|
66
65
|
})
|
|
67
66
|
|
|
68
|
-
const
|
|
69
|
-
|
|
67
|
+
const FilterButton = Shade<{
|
|
68
|
+
field: string
|
|
69
|
+
findOptions: ObservableValue<FilterableFindOptions>
|
|
70
70
|
onclick: () => void
|
|
71
|
-
findOptions: ObservableValue<FindOptions<any, any[]>>
|
|
72
71
|
}>({
|
|
73
|
-
shadowDomName: 'data-grid-
|
|
72
|
+
shadowDomName: 'data-grid-filter-button',
|
|
74
73
|
css: {
|
|
75
74
|
display: 'inline-block',
|
|
76
75
|
},
|
|
77
76
|
render: ({ props, useObservable }) => {
|
|
78
|
-
const [findOptions] = useObservable('currentValue', props.findOptions
|
|
79
|
-
filter: (newValue) => {
|
|
80
|
-
return !!newValue.filter?.[props.fieldName]
|
|
81
|
-
},
|
|
82
|
-
})
|
|
77
|
+
const [findOptions] = useObservable('currentValue', props.findOptions)
|
|
83
78
|
|
|
84
|
-
const
|
|
85
|
-
(findOptions.filter?.[props.fieldName] as FilterType<{ [K in typeof props.fieldName]: string }>)?.$regex || ''
|
|
79
|
+
const hasActiveFilter = !!findOptions.filter?.[props.field]
|
|
86
80
|
|
|
87
81
|
return (
|
|
88
|
-
<
|
|
82
|
+
<ToggleButton
|
|
89
83
|
type="button"
|
|
90
84
|
title="Filter"
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
)
|
|
98
|
-
},
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
const SearchForm = Shade<{
|
|
102
|
-
onSubmit: (newValue: string) => void
|
|
103
|
-
onClear: () => void
|
|
104
|
-
fieldName: string
|
|
105
|
-
findOptions: ObservableValue<FindOptions<any, any[]>>
|
|
106
|
-
}>({
|
|
107
|
-
shadowDomName: 'data-grid-search-form',
|
|
108
|
-
css: {
|
|
109
|
-
display: 'block',
|
|
110
|
-
'& .search-form': {
|
|
111
|
-
display: 'flex',
|
|
112
|
-
width: '100%',
|
|
113
|
-
overflow: 'hidden',
|
|
114
|
-
height: '0px',
|
|
115
|
-
justifyContent: 'space-around',
|
|
116
|
-
opacity: '0',
|
|
117
|
-
},
|
|
118
|
-
'& .search-form-actions': {
|
|
119
|
-
display: 'flex',
|
|
120
|
-
width: '64px',
|
|
121
|
-
alignItems: 'center',
|
|
122
|
-
justifyContent: 'center',
|
|
123
|
-
gap: '8px',
|
|
124
|
-
},
|
|
125
|
-
},
|
|
126
|
-
render: ({ props, useObservable }) => {
|
|
127
|
-
type SearchSubmitType = { searchValue: string }
|
|
128
|
-
|
|
129
|
-
const [findOptions] = useObservable('currentValue', props.findOptions, {
|
|
130
|
-
filter: (newValue, lastValue) => {
|
|
131
|
-
const newFilter = newValue.filter?.[props.fieldName] as FilterType<{ [K in typeof props.fieldName]: string }>
|
|
132
|
-
const lastFilter = lastValue.filter?.[props.fieldName] as FilterType<{ [K in typeof props.fieldName]: string }>
|
|
133
|
-
return newFilter?.$regex !== lastFilter?.$regex
|
|
134
|
-
},
|
|
135
|
-
})
|
|
136
|
-
|
|
137
|
-
const currentValue = (findOptions.filter?.[props.fieldName] as FilterType<Record<string, string>>)?.$regex || ''
|
|
138
|
-
|
|
139
|
-
return (
|
|
140
|
-
<Form<SearchSubmitType>
|
|
141
|
-
className="search-form"
|
|
142
|
-
validate={(data): data is SearchSubmitType =>
|
|
143
|
-
typeof (data as SearchSubmitType).searchValue?.length === 'number'
|
|
144
|
-
}
|
|
145
|
-
onSubmit={({ searchValue }) => {
|
|
146
|
-
props.onSubmit(searchValue)
|
|
85
|
+
size="small"
|
|
86
|
+
value={props.field}
|
|
87
|
+
pressed={hasActiveFilter}
|
|
88
|
+
onclick={(ev) => {
|
|
89
|
+
ev.stopPropagation()
|
|
90
|
+
props.onclick()
|
|
147
91
|
}}
|
|
148
92
|
>
|
|
149
|
-
<
|
|
150
|
-
|
|
151
|
-
autofocus
|
|
152
|
-
labelTitle={`${props.fieldName}`}
|
|
153
|
-
name="searchValue"
|
|
154
|
-
value={typeof currentValue === 'string' ? currentValue : ''}
|
|
155
|
-
labelProps={{
|
|
156
|
-
style: { padding: '0px 2em' },
|
|
157
|
-
}}
|
|
158
|
-
/>
|
|
159
|
-
<div className="search-form-actions">
|
|
160
|
-
<Button
|
|
161
|
-
type="reset"
|
|
162
|
-
variant="outlined"
|
|
163
|
-
onclick={(ev) => {
|
|
164
|
-
ev.preventDefault()
|
|
165
|
-
ev.stopPropagation()
|
|
166
|
-
props.onClear()
|
|
167
|
-
}}
|
|
168
|
-
>
|
|
169
|
-
<Icon icon={closeIcon} size={16} />
|
|
170
|
-
</Button>
|
|
171
|
-
<Button variant="outlined" type="submit">
|
|
172
|
-
<Icon icon={searchIcon} size={16} />
|
|
173
|
-
</Button>
|
|
174
|
-
</div>
|
|
175
|
-
</Form>
|
|
93
|
+
<Icon icon={filterIcon} size={14} />
|
|
94
|
+
</ToggleButton>
|
|
176
95
|
)
|
|
177
96
|
},
|
|
178
97
|
})
|
|
179
98
|
|
|
99
|
+
const renderFilterComponent = (
|
|
100
|
+
filterConfig: ColumnFilterConfig,
|
|
101
|
+
field: string,
|
|
102
|
+
findOptions: ObservableValue<FilterableFindOptions>,
|
|
103
|
+
onClose: () => void,
|
|
104
|
+
): JSX.Element => {
|
|
105
|
+
switch (filterConfig.type) {
|
|
106
|
+
case 'number':
|
|
107
|
+
return <NumberFilter field={field} findOptions={findOptions} onClose={onClose} />
|
|
108
|
+
case 'boolean':
|
|
109
|
+
return <BooleanFilter field={field} findOptions={findOptions} onClose={onClose} />
|
|
110
|
+
case 'enum':
|
|
111
|
+
return <EnumFilter field={field} values={filterConfig.values} findOptions={findOptions} onClose={onClose} />
|
|
112
|
+
case 'date':
|
|
113
|
+
return <DateFilter field={field} findOptions={findOptions} onClose={onClose} />
|
|
114
|
+
case 'string':
|
|
115
|
+
return <StringFilter field={field} findOptions={findOptions} onClose={onClose} />
|
|
116
|
+
default: {
|
|
117
|
+
const _exhaustive: never = filterConfig
|
|
118
|
+
throw new Error(`Unknown filter type: ${(_exhaustive as ColumnFilterConfig).type}`)
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
180
123
|
export const DataGridHeader: <T, Column extends string>(
|
|
181
124
|
props: DataGridHeaderProps<T, Column>,
|
|
182
125
|
children: ChildrenList,
|
|
183
|
-
findOptions: ObservableValue<FindOptions<T, Array<keyof T>>>,
|
|
184
126
|
) => JSX.Element<any> = Shade({
|
|
185
127
|
shadowDomName: 'data-grid-header',
|
|
186
128
|
css: {
|
|
187
129
|
display: 'block',
|
|
130
|
+
position: 'relative',
|
|
188
131
|
'& .header-content': {
|
|
189
132
|
display: 'flex',
|
|
190
133
|
width: '100%',
|
|
191
|
-
height: '
|
|
134
|
+
height: '36px',
|
|
192
135
|
justifyContent: 'space-between',
|
|
193
136
|
alignItems: 'center',
|
|
194
|
-
gap: '
|
|
137
|
+
gap: '8px',
|
|
195
138
|
overflow: 'hidden',
|
|
196
139
|
},
|
|
197
140
|
'& .header-field-name': {
|
|
198
|
-
|
|
141
|
+
overflow: 'hidden',
|
|
142
|
+
textOverflow: 'ellipsis',
|
|
143
|
+
whiteSpace: 'nowrap',
|
|
199
144
|
},
|
|
200
145
|
'& .header-controls': {
|
|
201
146
|
display: 'flex',
|
|
202
|
-
justifyContent: 'center',
|
|
203
147
|
alignItems: 'center',
|
|
204
|
-
gap: '
|
|
148
|
+
gap: '2px',
|
|
149
|
+
flexShrink: '0',
|
|
205
150
|
},
|
|
206
151
|
},
|
|
207
|
-
render: ({ props,
|
|
208
|
-
const
|
|
209
|
-
const headerContentRef = useRef<HTMLDivElement>('headerContent')
|
|
210
|
-
|
|
211
|
-
const [, setIsSearchOpened] = useState('isSearchOpened', false)
|
|
212
|
-
|
|
213
|
-
const openSearch = () => {
|
|
214
|
-
setIsSearchOpened(true)
|
|
215
|
-
const searchForm = searchFormRef.current?.querySelector('.search-form') as HTMLElement | null
|
|
216
|
-
const headerContent = headerContentRef.current
|
|
217
|
-
if (!searchForm || !headerContent) return
|
|
218
|
-
searchForm.style.display = 'flex'
|
|
219
|
-
void expand(searchForm).then(async () => {
|
|
220
|
-
await sleepAsync(100)
|
|
221
|
-
searchForm.querySelector('input')?.focus()
|
|
222
|
-
})
|
|
223
|
-
void collapse(headerContent)
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
const closeSearch = () => {
|
|
227
|
-
setIsSearchOpened(false)
|
|
228
|
-
const searchForm = searchFormRef.current?.querySelector('.search-form') as HTMLElement | null
|
|
229
|
-
const headerContent = headerContentRef.current
|
|
230
|
-
if (!searchForm || !headerContent) return
|
|
231
|
-
void collapse(searchForm)
|
|
232
|
-
void expand(headerContent)
|
|
233
|
-
}
|
|
152
|
+
render: ({ props, useState }) => {
|
|
153
|
+
const [isFilterOpen, setIsFilterOpen] = useState('isFilterOpen', false)
|
|
234
154
|
|
|
235
|
-
const
|
|
236
|
-
|
|
237
|
-
const updateSearchValue = (value?: string) => {
|
|
238
|
-
if (value) {
|
|
239
|
-
const newSettings = {
|
|
240
|
-
...findOptions,
|
|
241
|
-
filter: {
|
|
242
|
-
...findOptions.filter,
|
|
243
|
-
[props.field]: { $regex: value },
|
|
244
|
-
},
|
|
245
|
-
} as typeof findOptions
|
|
246
|
-
setFindOptions(newSettings)
|
|
247
|
-
} else {
|
|
248
|
-
const { [props.field]: _, ...newFilter } = findOptions.filter || {}
|
|
249
|
-
setFindOptions({ ...findOptions, filter: newFilter })
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
closeSearch()
|
|
253
|
-
}
|
|
155
|
+
const closeFilter = () => setIsFilterOpen(false)
|
|
254
156
|
|
|
255
157
|
return (
|
|
256
158
|
<>
|
|
257
|
-
<div
|
|
258
|
-
<SearchForm
|
|
259
|
-
onSubmit={updateSearchValue}
|
|
260
|
-
onClear={updateSearchValue}
|
|
261
|
-
fieldName={props.field}
|
|
262
|
-
findOptions={props.findOptions}
|
|
263
|
-
/>
|
|
264
|
-
</div>
|
|
265
|
-
<div ref={headerContentRef} className="header-content">
|
|
159
|
+
<div className="header-content">
|
|
266
160
|
<div className="header-field-name">{props.field}</div>
|
|
267
161
|
<div className="header-controls">
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
162
|
+
{props.filterConfig && (
|
|
163
|
+
<FilterButton
|
|
164
|
+
onclick={() => setIsFilterOpen(!isFilterOpen)}
|
|
165
|
+
findOptions={props.findOptions as ObservableValue<FilterableFindOptions>}
|
|
166
|
+
field={props.field}
|
|
167
|
+
/>
|
|
168
|
+
)}
|
|
169
|
+
<OrderButton
|
|
170
|
+
field={props.field}
|
|
171
|
+
findOptions={props.findOptions as ObservableValue<FilterableFindOptions>}
|
|
172
|
+
/>
|
|
271
173
|
</div>
|
|
272
174
|
</div>
|
|
175
|
+
{isFilterOpen && props.filterConfig && (
|
|
176
|
+
<FilterDropdown onClose={closeFilter}>
|
|
177
|
+
{renderFilterComponent(
|
|
178
|
+
props.filterConfig,
|
|
179
|
+
props.field,
|
|
180
|
+
props.findOptions as ObservableValue<FilterableFindOptions>,
|
|
181
|
+
closeFilter,
|
|
182
|
+
)}
|
|
183
|
+
</FilterDropdown>
|
|
184
|
+
)}
|
|
273
185
|
</>
|
|
274
186
|
)
|
|
275
187
|
},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Injector } from '@furystack/inject'
|
|
2
|
-
import { createComponent, initializeShadeRoot } from '@furystack/shades'
|
|
3
|
-
import {
|
|
2
|
+
import { createComponent, flushUpdates, initializeShadeRoot } from '@furystack/shades'
|
|
3
|
+
import { usingAsync } from '@furystack/utils'
|
|
4
4
|
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
|
|
5
5
|
import { CollectionService } from '../../services/collection-service.js'
|
|
6
6
|
import { SelectionCell } from './selection-cell.js'
|
|
@@ -24,7 +24,7 @@ describe('SelectionCell', () => {
|
|
|
24
24
|
rootElement: root,
|
|
25
25
|
jsxElement: <SelectionCell entry={entry} service={service} />,
|
|
26
26
|
})
|
|
27
|
-
await
|
|
27
|
+
await flushUpdates()
|
|
28
28
|
return {
|
|
29
29
|
injector,
|
|
30
30
|
cell: root.querySelector('shades-data-grid-selection-cell') as HTMLElement,
|
|
@@ -76,12 +76,12 @@ describe('SelectionCell', () => {
|
|
|
76
76
|
expect(getCheckbox()?.checked).toBe(false)
|
|
77
77
|
|
|
78
78
|
service.selection.setValue([entry])
|
|
79
|
-
await
|
|
79
|
+
await flushUpdates()
|
|
80
80
|
|
|
81
81
|
expect(getCheckbox()?.checked).toBe(true)
|
|
82
82
|
|
|
83
83
|
service.selection.setValue([])
|
|
84
|
-
await
|
|
84
|
+
await flushUpdates()
|
|
85
85
|
|
|
86
86
|
expect(getCheckbox()?.checked).toBe(false)
|
|
87
87
|
})
|
|
@@ -109,7 +109,7 @@ describe('SelectionCell', () => {
|
|
|
109
109
|
|
|
110
110
|
const checkbox = getCheckbox()
|
|
111
111
|
checkbox?.dispatchEvent(new Event('change', { bubbles: true }))
|
|
112
|
-
await
|
|
112
|
+
await flushUpdates()
|
|
113
113
|
|
|
114
114
|
expect(service.selection.getValue()).toContain(entry)
|
|
115
115
|
})
|
|
@@ -125,7 +125,7 @@ describe('SelectionCell', () => {
|
|
|
125
125
|
|
|
126
126
|
const checkbox = getCheckbox()
|
|
127
127
|
checkbox?.dispatchEvent(new Event('change', { bubbles: true }))
|
|
128
|
-
await
|
|
128
|
+
await flushUpdates()
|
|
129
129
|
|
|
130
130
|
expect(service.selection.getValue()).not.toContain(entry)
|
|
131
131
|
})
|
|
@@ -140,7 +140,7 @@ describe('SelectionCell', () => {
|
|
|
140
140
|
await usingAsync(await renderSelectionCell(entry, service), async ({ getCheckbox }) => {
|
|
141
141
|
const checkbox = getCheckbox()
|
|
142
142
|
checkbox?.dispatchEvent(new Event('change', { bubbles: true }))
|
|
143
|
-
await
|
|
143
|
+
await flushUpdates()
|
|
144
144
|
|
|
145
145
|
expect(service.selection.getValue()).toContain(entry)
|
|
146
146
|
expect(service.selection.getValue()).toContain(otherEntry)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Injector } from '@furystack/inject'
|
|
2
|
-
import { createComponent, initializeShadeRoot } from '@furystack/shades'
|
|
3
|
-
import {
|
|
2
|
+
import { createComponent, flushUpdates, initializeShadeRoot } from '@furystack/shades'
|
|
3
|
+
import { usingAsync } from '@furystack/utils'
|
|
4
4
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
5
5
|
import { LayoutService } from '../../services/layout-service.js'
|
|
6
6
|
import { DrawerToggleButton } from './drawer-toggle-button.js'
|
|
@@ -37,7 +37,7 @@ describe('DrawerToggleButton component', () => {
|
|
|
37
37
|
jsxElement: <DrawerToggleButton position="left" />,
|
|
38
38
|
})
|
|
39
39
|
|
|
40
|
-
await
|
|
40
|
+
await flushUpdates()
|
|
41
41
|
const element = document.querySelector('shade-drawer-toggle-button')
|
|
42
42
|
expect(element).not.toBeNull()
|
|
43
43
|
expect(element?.tagName.toLowerCase()).toBe('shade-drawer-toggle-button')
|
|
@@ -56,7 +56,7 @@ describe('DrawerToggleButton component', () => {
|
|
|
56
56
|
jsxElement: <DrawerToggleButton position="left" />,
|
|
57
57
|
})
|
|
58
58
|
|
|
59
|
-
await
|
|
59
|
+
await flushUpdates()
|
|
60
60
|
const button = document.querySelector('button')
|
|
61
61
|
expect(button).not.toBeNull()
|
|
62
62
|
})
|
|
@@ -74,7 +74,7 @@ describe('DrawerToggleButton component', () => {
|
|
|
74
74
|
jsxElement: <DrawerToggleButton position="left" />,
|
|
75
75
|
})
|
|
76
76
|
|
|
77
|
-
await
|
|
77
|
+
await flushUpdates()
|
|
78
78
|
const hamburger = document.querySelector('.hamburger')
|
|
79
79
|
expect(hamburger).not.toBeNull()
|
|
80
80
|
|
|
@@ -102,7 +102,7 @@ describe('DrawerToggleButton component', () => {
|
|
|
102
102
|
jsxElement: <DrawerToggleButton position="left" />,
|
|
103
103
|
})
|
|
104
104
|
|
|
105
|
-
await
|
|
105
|
+
await flushUpdates()
|
|
106
106
|
const button = document.querySelector('[data-testid="drawer-toggle-left"]') as HTMLButtonElement
|
|
107
107
|
expect(button).not.toBeNull()
|
|
108
108
|
// Button is rendered, aria-label is set in JSX (may not be visible in JSDOM)
|
|
@@ -121,7 +121,7 @@ describe('DrawerToggleButton component', () => {
|
|
|
121
121
|
jsxElement: <DrawerToggleButton position="left" ariaLabel="Toggle navigation menu" />,
|
|
122
122
|
})
|
|
123
123
|
|
|
124
|
-
await
|
|
124
|
+
await flushUpdates()
|
|
125
125
|
const button = document.querySelector('[data-testid="drawer-toggle-left"]') as HTMLButtonElement
|
|
126
126
|
expect(button).not.toBeNull()
|
|
127
127
|
// Button is rendered with custom ariaLabel prop (may not be visible in JSDOM)
|
|
@@ -143,7 +143,7 @@ describe('DrawerToggleButton component', () => {
|
|
|
143
143
|
jsxElement: <DrawerToggleButton position="left" />,
|
|
144
144
|
})
|
|
145
145
|
|
|
146
|
-
await
|
|
146
|
+
await flushUpdates()
|
|
147
147
|
const button = document.querySelector('[data-testid="drawer-toggle-left"]') as HTMLButtonElement
|
|
148
148
|
expect(button).not.toBeNull()
|
|
149
149
|
|
|
@@ -153,7 +153,7 @@ describe('DrawerToggleButton component', () => {
|
|
|
153
153
|
|
|
154
154
|
// Close drawer
|
|
155
155
|
layoutService.setDrawerOpen('left', false)
|
|
156
|
-
await
|
|
156
|
+
await flushUpdates()
|
|
157
157
|
|
|
158
158
|
// Verify hamburger doesn't have open class when drawer is closed
|
|
159
159
|
hamburger = document.querySelector('.hamburger')
|
|
@@ -173,7 +173,7 @@ describe('DrawerToggleButton component', () => {
|
|
|
173
173
|
jsxElement: <DrawerToggleButton position="left" />,
|
|
174
174
|
})
|
|
175
175
|
|
|
176
|
-
await
|
|
176
|
+
await flushUpdates()
|
|
177
177
|
const button = document.querySelector('button')
|
|
178
178
|
expect(button?.getAttribute('type')).toBe('button')
|
|
179
179
|
})
|
|
@@ -196,19 +196,19 @@ describe('DrawerToggleButton component', () => {
|
|
|
196
196
|
jsxElement: <DrawerToggleButton position="left" />,
|
|
197
197
|
})
|
|
198
198
|
|
|
199
|
-
await
|
|
199
|
+
await flushUpdates()
|
|
200
200
|
expect(layoutService.drawerState.getValue().left?.open).toBe(true)
|
|
201
201
|
|
|
202
202
|
// Click the button
|
|
203
203
|
const button = document.querySelector('button') as HTMLButtonElement
|
|
204
204
|
button.click()
|
|
205
|
-
await
|
|
205
|
+
await flushUpdates()
|
|
206
206
|
|
|
207
207
|
expect(layoutService.drawerState.getValue().left?.open).toBe(false)
|
|
208
208
|
|
|
209
209
|
// Click again
|
|
210
210
|
button.click()
|
|
211
|
-
await
|
|
211
|
+
await flushUpdates()
|
|
212
212
|
|
|
213
213
|
expect(layoutService.drawerState.getValue().left?.open).toBe(true)
|
|
214
214
|
})
|
|
@@ -229,13 +229,13 @@ describe('DrawerToggleButton component', () => {
|
|
|
229
229
|
jsxElement: <DrawerToggleButton position="right" />,
|
|
230
230
|
})
|
|
231
231
|
|
|
232
|
-
await
|
|
232
|
+
await flushUpdates()
|
|
233
233
|
expect(layoutService.drawerState.getValue().right?.open).toBe(true)
|
|
234
234
|
|
|
235
235
|
// Click the button
|
|
236
236
|
const button = document.querySelector('button') as HTMLButtonElement
|
|
237
237
|
button.click()
|
|
238
|
-
await
|
|
238
|
+
await flushUpdates()
|
|
239
239
|
|
|
240
240
|
expect(layoutService.drawerState.getValue().right?.open).toBe(false)
|
|
241
241
|
})
|
|
@@ -253,7 +253,7 @@ describe('DrawerToggleButton component', () => {
|
|
|
253
253
|
jsxElement: <DrawerToggleButton position="left" />,
|
|
254
254
|
})
|
|
255
255
|
|
|
256
|
-
await
|
|
256
|
+
await flushUpdates()
|
|
257
257
|
|
|
258
258
|
// Should not throw when clicking even though drawer isn't initialized
|
|
259
259
|
const button = document.querySelector('button') as HTMLButtonElement
|
|
@@ -278,7 +278,7 @@ describe('DrawerToggleButton component', () => {
|
|
|
278
278
|
jsxElement: <DrawerToggleButton position="left" />,
|
|
279
279
|
})
|
|
280
280
|
|
|
281
|
-
await
|
|
281
|
+
await flushUpdates()
|
|
282
282
|
const hamburger = document.querySelector('.hamburger')
|
|
283
283
|
expect(hamburger?.classList.contains('open')).toBe(false)
|
|
284
284
|
})
|
|
@@ -299,7 +299,7 @@ describe('DrawerToggleButton component', () => {
|
|
|
299
299
|
jsxElement: <DrawerToggleButton position="left" />,
|
|
300
300
|
})
|
|
301
301
|
|
|
302
|
-
await
|
|
302
|
+
await flushUpdates()
|
|
303
303
|
const hamburger = document.querySelector('.hamburger')
|
|
304
304
|
expect(hamburger?.classList.contains('open')).toBe(true)
|
|
305
305
|
})
|
|
@@ -320,13 +320,13 @@ describe('DrawerToggleButton component', () => {
|
|
|
320
320
|
jsxElement: <DrawerToggleButton position="left" />,
|
|
321
321
|
})
|
|
322
322
|
|
|
323
|
-
await
|
|
323
|
+
await flushUpdates()
|
|
324
324
|
let hamburger = document.querySelector('.hamburger')
|
|
325
325
|
expect(hamburger?.classList.contains('open')).toBe(true)
|
|
326
326
|
|
|
327
327
|
// Close drawer via LayoutService
|
|
328
328
|
layoutService.setDrawerOpen('left', false)
|
|
329
|
-
await
|
|
329
|
+
await flushUpdates()
|
|
330
330
|
|
|
331
331
|
hamburger = document.querySelector('.hamburger')
|
|
332
332
|
expect(hamburger?.classList.contains('open')).toBe(false)
|
|
@@ -347,7 +347,7 @@ describe('DrawerToggleButton component', () => {
|
|
|
347
347
|
jsxElement: <DrawerToggleButton position="left" />,
|
|
348
348
|
})
|
|
349
349
|
|
|
350
|
-
await
|
|
350
|
+
await flushUpdates()
|
|
351
351
|
const button = document.querySelector('[data-testid="drawer-toggle-left"]')
|
|
352
352
|
expect(button).not.toBeNull()
|
|
353
353
|
})
|
|
@@ -365,7 +365,7 @@ describe('DrawerToggleButton component', () => {
|
|
|
365
365
|
jsxElement: <DrawerToggleButton position="right" />,
|
|
366
366
|
})
|
|
367
367
|
|
|
368
|
-
await
|
|
368
|
+
await flushUpdates()
|
|
369
369
|
const button = document.querySelector('[data-testid="drawer-toggle-right"]')
|
|
370
370
|
expect(button).not.toBeNull()
|
|
371
371
|
})
|