@axinom/mosaic-ui 0.75.0-rc.5 → 0.77.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/dist/THIRD-PARTY-LICENSES.txt +1296 -0
- package/dist/cjs/components/ActionBar/ActionBar.d.ts +26 -0
- package/dist/cjs/components/ActionBar/ActionBar.d.ts.map +1 -0
- package/dist/cjs/components/ActionBar/ActionBar.model.d.ts +49 -0
- package/dist/cjs/components/ActionBar/ActionBar.model.d.ts.map +1 -0
- package/dist/cjs/components/ActionBar/ActionBarButton/ActionBarButton.d.ts +22 -0
- package/dist/cjs/components/ActionBar/ActionBarButton/ActionBarButton.d.ts.map +1 -0
- package/dist/cjs/components/ActionBar/helpers.d.ts +22 -0
- package/dist/cjs/components/ActionBar/helpers.d.ts.map +1 -0
- package/dist/cjs/components/ActionBar/index.d.ts +3 -0
- package/dist/cjs/components/ActionBar/index.d.ts.map +1 -0
- package/dist/cjs/components/Actions/Action/Action.d.ts.map +1 -1
- package/dist/cjs/components/ConfirmDialog/index.d.ts +1 -0
- package/dist/cjs/components/ConfirmDialog/index.d.ts.map +1 -1
- package/dist/cjs/components/ConfirmDialog/useConfirmableAction.d.ts +55 -0
- package/dist/cjs/components/ConfirmDialog/useConfirmableAction.d.ts.map +1 -0
- package/dist/cjs/components/Explorer/BulkEdit/useBulkEdit.d.ts.map +1 -1
- package/dist/cjs/components/Explorer/Explorer.d.ts.map +1 -1
- package/dist/cjs/components/Explorer/QuickEdit/useQuickEdit.d.ts +14 -3
- package/dist/cjs/components/Explorer/QuickEdit/useQuickEdit.d.ts.map +1 -1
- package/dist/cjs/components/Explorer/helpers/useActions.d.ts +15 -4
- package/dist/cjs/components/Explorer/helpers/useActions.d.ts.map +1 -1
- package/dist/cjs/components/Explorer/helpers/useSubtitle.d.ts.map +1 -1
- package/dist/cjs/components/List/List.d.ts +17 -3
- package/dist/cjs/components/List/List.d.ts.map +1 -1
- package/dist/cjs/components/List/List.model.d.ts +5 -1
- package/dist/cjs/components/List/List.model.d.ts.map +1 -1
- package/dist/cjs/components/List/ListHeader/ListHeader.d.ts +10 -1
- package/dist/cjs/components/List/ListHeader/ListHeader.d.ts.map +1 -1
- package/dist/cjs/components/List/ListRow/ListRow.d.ts +16 -5
- package/dist/cjs/components/List/ListRow/ListRow.d.ts.map +1 -1
- package/dist/cjs/components/List/ListRowRenderer/ListRowRenderer.d.ts.map +1 -1
- package/dist/cjs/components/List/helpers.d.ts +11 -3
- package/dist/cjs/components/List/helpers.d.ts.map +1 -1
- package/dist/cjs/components/List/useColumnsSize.d.ts +4 -2
- package/dist/cjs/components/List/useColumnsSize.d.ts.map +1 -1
- package/dist/cjs/components/PageHeader/PageHeader.d.ts +4 -1
- package/dist/cjs/components/PageHeader/PageHeader.d.ts.map +1 -1
- package/dist/cjs/components/PageHeader/PageHeader.model.d.ts +37 -1
- package/dist/cjs/components/PageHeader/PageHeader.model.d.ts.map +1 -1
- package/dist/cjs/components/PageHeader/PageHeaderAction/PageHeaderAction.d.ts +3 -0
- package/dist/cjs/components/PageHeader/PageHeaderAction/PageHeaderAction.d.ts.map +1 -1
- package/dist/cjs/components/PageHeader/PageHeaderAction/PageHeaderAction.model.d.ts +8 -0
- package/dist/cjs/components/PageHeader/PageHeaderAction/PageHeaderAction.model.d.ts.map +1 -1
- package/dist/cjs/components/PageHeader/helpers.d.ts +9 -0
- package/dist/cjs/components/PageHeader/helpers.d.ts.map +1 -0
- package/dist/cjs/components/index.d.ts +1 -0
- package/dist/cjs/components/index.d.ts.map +1 -1
- package/dist/cjs/hooks/index.d.ts +1 -0
- package/dist/cjs/hooks/index.d.ts.map +1 -1
- package/dist/cjs/hooks/useElementWidthObserver/useElementWidthObserver.d.ts.map +1 -0
- package/dist/cjs/index.js +4 -4
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/components/ActionBar/ActionBar.d.ts +26 -0
- package/dist/esm/components/ActionBar/ActionBar.d.ts.map +1 -0
- package/dist/esm/components/ActionBar/ActionBar.model.d.ts +49 -0
- package/dist/esm/components/ActionBar/ActionBar.model.d.ts.map +1 -0
- package/dist/esm/components/ActionBar/ActionBarButton/ActionBarButton.d.ts +22 -0
- package/dist/esm/components/ActionBar/ActionBarButton/ActionBarButton.d.ts.map +1 -0
- package/dist/esm/components/ActionBar/helpers.d.ts +22 -0
- package/dist/esm/components/ActionBar/helpers.d.ts.map +1 -0
- package/dist/esm/components/ActionBar/index.d.ts +3 -0
- package/dist/esm/components/ActionBar/index.d.ts.map +1 -0
- package/dist/esm/components/Actions/Action/Action.d.ts.map +1 -1
- package/dist/esm/components/ConfirmDialog/index.d.ts +1 -0
- package/dist/esm/components/ConfirmDialog/index.d.ts.map +1 -1
- package/dist/esm/components/ConfirmDialog/useConfirmableAction.d.ts +55 -0
- package/dist/esm/components/ConfirmDialog/useConfirmableAction.d.ts.map +1 -0
- package/dist/esm/components/Explorer/BulkEdit/useBulkEdit.d.ts.map +1 -1
- package/dist/esm/components/Explorer/Explorer.d.ts.map +1 -1
- package/dist/esm/components/Explorer/QuickEdit/useQuickEdit.d.ts +14 -3
- package/dist/esm/components/Explorer/QuickEdit/useQuickEdit.d.ts.map +1 -1
- package/dist/esm/components/Explorer/helpers/useActions.d.ts +15 -4
- package/dist/esm/components/Explorer/helpers/useActions.d.ts.map +1 -1
- package/dist/esm/components/Explorer/helpers/useSubtitle.d.ts.map +1 -1
- package/dist/esm/components/List/List.d.ts +17 -3
- package/dist/esm/components/List/List.d.ts.map +1 -1
- package/dist/esm/components/List/List.model.d.ts +5 -1
- package/dist/esm/components/List/List.model.d.ts.map +1 -1
- package/dist/esm/components/List/ListHeader/ListHeader.d.ts +10 -1
- package/dist/esm/components/List/ListHeader/ListHeader.d.ts.map +1 -1
- package/dist/esm/components/List/ListRow/ListRow.d.ts +16 -5
- package/dist/esm/components/List/ListRow/ListRow.d.ts.map +1 -1
- package/dist/esm/components/List/ListRowRenderer/ListRowRenderer.d.ts.map +1 -1
- package/dist/esm/components/List/helpers.d.ts +11 -3
- package/dist/esm/components/List/helpers.d.ts.map +1 -1
- package/dist/esm/components/List/useColumnsSize.d.ts +4 -2
- package/dist/esm/components/List/useColumnsSize.d.ts.map +1 -1
- package/dist/esm/components/PageHeader/PageHeader.d.ts +4 -1
- package/dist/esm/components/PageHeader/PageHeader.d.ts.map +1 -1
- package/dist/esm/components/PageHeader/PageHeader.model.d.ts +37 -1
- package/dist/esm/components/PageHeader/PageHeader.model.d.ts.map +1 -1
- package/dist/esm/components/PageHeader/PageHeaderAction/PageHeaderAction.d.ts +3 -0
- package/dist/esm/components/PageHeader/PageHeaderAction/PageHeaderAction.d.ts.map +1 -1
- package/dist/esm/components/PageHeader/PageHeaderAction/PageHeaderAction.model.d.ts +8 -0
- package/dist/esm/components/PageHeader/PageHeaderAction/PageHeaderAction.model.d.ts.map +1 -1
- package/dist/esm/components/PageHeader/helpers.d.ts +9 -0
- package/dist/esm/components/PageHeader/helpers.d.ts.map +1 -0
- package/dist/esm/components/index.d.ts +1 -0
- package/dist/esm/components/index.d.ts.map +1 -1
- package/dist/esm/hooks/index.d.ts +1 -0
- package/dist/esm/hooks/index.d.ts.map +1 -1
- package/dist/esm/hooks/useElementWidthObserver/useElementWidthObserver.d.ts.map +1 -0
- package/dist/esm/index.js +4 -4
- package/dist/esm/index.js.map +1 -1
- package/package.json +7 -3
- package/src/components/ActionBar/ActionBar.model.ts +61 -0
- package/src/components/ActionBar/ActionBar.module.scss +64 -0
- package/src/components/ActionBar/ActionBar.spec.tsx +398 -0
- package/src/components/ActionBar/ActionBar.stories.tsx +205 -0
- package/src/components/ActionBar/ActionBar.tsx +170 -0
- package/src/components/ActionBar/ActionBarButton/ActionBarButton.module.scss +140 -0
- package/src/components/ActionBar/ActionBarButton/ActionBarButton.tsx +193 -0
- package/src/components/ActionBar/helpers.spec.ts +41 -0
- package/src/components/ActionBar/helpers.ts +54 -0
- package/src/components/ActionBar/index.ts +2 -0
- package/src/components/Actions/Action/Action.spec.tsx +64 -2
- package/src/components/Actions/Action/Action.tsx +6 -1
- package/src/components/ConfirmDialog/index.ts +1 -0
- package/src/components/ConfirmDialog/useConfirmableAction.tsx +159 -0
- package/src/components/EmptyStation/EmptyStation.stories.tsx +97 -0
- package/src/components/Explorer/BulkEdit/useBulkEdit.tsx +2 -0
- package/src/components/Explorer/Explorer.spec.tsx +97 -8
- package/src/components/Explorer/Explorer.tsx +26 -13
- package/src/components/Explorer/NavigationExplorer/NavigationExplorer.stories.tsx +124 -1
- package/src/components/Explorer/QuickEdit/useQuickEdit.spec.tsx +94 -50
- package/src/components/Explorer/QuickEdit/useQuickEdit.tsx +101 -42
- package/src/components/Explorer/SelectionExplorer/SelectionExplorer.spec.tsx +46 -13
- package/src/components/Explorer/helpers/useActions.ts +125 -73
- package/src/components/Explorer/helpers/useSubtitle.spec.tsx +33 -23
- package/src/components/Explorer/helpers/useSubtitle.tsx +18 -26
- package/src/components/List/List.model.ts +5 -1
- package/src/components/List/List.module.scss +25 -6
- package/src/components/List/List.spec.tsx +498 -1
- package/src/components/List/List.stories.tsx +137 -8
- package/src/components/List/List.tsx +305 -194
- package/src/components/List/ListHeader/ListHeader.module.scss +14 -0
- package/src/components/List/ListHeader/ListHeader.spec.tsx +1 -0
- package/src/components/List/ListHeader/ListHeader.tsx +25 -8
- package/src/components/List/ListRow/ListRow.module.scss +1 -1
- package/src/components/List/ListRow/ListRow.spec.tsx +109 -22
- package/src/components/List/ListRow/ListRow.tsx +52 -13
- package/src/components/List/ListRowRenderer/ListRowRenderer.tsx +28 -22
- package/src/components/List/helpers.spec.ts +29 -0
- package/src/components/List/helpers.ts +17 -9
- package/src/components/List/useColumnsSize.ts +17 -7
- package/src/components/PageHeader/PageHeader.model.ts +38 -1
- package/src/components/PageHeader/PageHeader.module.scss +39 -18
- package/src/components/PageHeader/PageHeader.spec.tsx +407 -18
- package/src/components/PageHeader/PageHeader.stories.tsx +95 -12
- package/src/components/PageHeader/PageHeader.tsx +89 -38
- package/src/components/PageHeader/PageHeaderAction/PageHeaderAction.model.ts +8 -0
- package/src/components/PageHeader/PageHeaderAction/PageHeaderAction.module.scss +50 -42
- package/src/components/PageHeader/PageHeaderAction/PageHeaderAction.spec.tsx +193 -1
- package/src/components/PageHeader/PageHeaderAction/PageHeaderAction.stories.tsx +36 -0
- package/src/components/PageHeader/PageHeaderAction/PageHeaderAction.tsx +81 -130
- package/src/components/PageHeader/helpers.spec.ts +60 -0
- package/src/components/PageHeader/helpers.ts +36 -0
- package/src/components/index.ts +1 -0
- package/src/hooks/index.ts +1 -0
- package/src/styles/variables.scss +41 -7
- package/dist/cjs/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroup.d.ts +0 -35
- package/dist/cjs/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroup.d.ts.map +0 -1
- package/dist/cjs/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroupsContext.d.ts +0 -6
- package/dist/cjs/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroupsContext.d.ts.map +0 -1
- package/dist/cjs/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroupsContextProvider.d.ts +0 -3
- package/dist/cjs/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroupsContextProvider.d.ts.map +0 -1
- package/dist/cjs/components/PageHeader/helpers/useElementWidthObserver.d.ts.map +0 -1
- package/dist/esm/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroup.d.ts +0 -35
- package/dist/esm/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroup.d.ts.map +0 -1
- package/dist/esm/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroupsContext.d.ts +0 -6
- package/dist/esm/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroupsContext.d.ts.map +0 -1
- package/dist/esm/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroupsContextProvider.d.ts +0 -3
- package/dist/esm/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroupsContextProvider.d.ts.map +0 -1
- package/dist/esm/components/PageHeader/helpers/useElementWidthObserver.d.ts.map +0 -1
- package/src/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroup.module.scss +0 -77
- package/src/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroup.spec.tsx +0 -122
- package/src/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroup.tsx +0 -235
- package/src/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroupsContext.ts +0 -15
- package/src/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroupsContextProvider.tsx +0 -37
- /package/dist/cjs/{components/PageHeader/helpers → hooks/useElementWidthObserver}/useElementWidthObserver.d.ts +0 -0
- /package/dist/esm/{components/PageHeader/helpers → hooks/useElementWidthObserver}/useElementWidthObserver.d.ts +0 -0
- /package/src/{components/PageHeader/helpers → hooks/useElementWidthObserver}/useElementWidthObserver.tsx +0 -0
|
@@ -3,13 +3,16 @@
|
|
|
3
3
|
.container {
|
|
4
4
|
@include boxSizing;
|
|
5
5
|
|
|
6
|
-
height: $page-header-height;
|
|
7
6
|
display: grid;
|
|
8
|
-
|
|
9
|
-
grid
|
|
7
|
+
// Actions that do not fit overflow their column rather than widening the
|
|
8
|
+
// grid, which keeps the action bar spanning the columns as wide as the header.
|
|
9
|
+
grid-template-columns: minmax(30%, 1fr) minmax(0, auto);
|
|
10
|
+
// The titles and the actions share the first row. The action bar of an open
|
|
11
|
+
// actions group takes a row of its own below them.
|
|
12
|
+
grid-template-rows: $page-header-height;
|
|
10
13
|
|
|
11
14
|
@media only screen and (min-width: $XL-min-size) {
|
|
12
|
-
grid-template-columns: minmax(25%, 1fr)
|
|
15
|
+
grid-template-columns: minmax(25%, 1fr) repeat(2, minmax(0, max-content));
|
|
13
16
|
}
|
|
14
17
|
|
|
15
18
|
color: var(--page-header-color, $page-header-color);
|
|
@@ -18,28 +21,38 @@
|
|
|
18
21
|
$page-header-background-color
|
|
19
22
|
);
|
|
20
23
|
|
|
24
|
+
// Centered vertically, so that a title without a subtitle sits in the middle
|
|
25
|
+
// of the header.
|
|
21
26
|
.titles {
|
|
27
|
+
min-width: 0;
|
|
28
|
+
|
|
22
29
|
display: grid;
|
|
23
30
|
grid-template-columns: 1fr;
|
|
24
|
-
|
|
31
|
+
align-content: center;
|
|
32
|
+
row-gap: 4px;
|
|
25
33
|
|
|
26
|
-
padding:
|
|
34
|
+
padding: 0 var(--page-header-padding, $page-header-padding);
|
|
27
35
|
|
|
28
36
|
.title {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
37
|
+
font-size: var(
|
|
38
|
+
--page-header-title-font-size,
|
|
39
|
+
$page-header-title-font-size
|
|
40
|
+
);
|
|
41
|
+
line-height: 1.2;
|
|
34
42
|
}
|
|
35
43
|
|
|
36
44
|
.subtitle {
|
|
37
|
-
justify-items: start;
|
|
38
|
-
|
|
39
|
-
margin-top: 12px;
|
|
40
|
-
|
|
41
45
|
color: var(--page-header-subtitle-color, $page-header-subtitle-color);
|
|
42
|
-
font-size:
|
|
46
|
+
font-size: var(
|
|
47
|
+
--page-header-subtitle-font-size,
|
|
48
|
+
$page-header-subtitle-font-size
|
|
49
|
+
);
|
|
50
|
+
line-height: 1.2;
|
|
51
|
+
|
|
52
|
+
// Takes no room without a subtitle, which would push the title up.
|
|
53
|
+
&:empty {
|
|
54
|
+
display: none;
|
|
55
|
+
}
|
|
43
56
|
}
|
|
44
57
|
|
|
45
58
|
.title,
|
|
@@ -53,11 +66,19 @@
|
|
|
53
66
|
.actions {
|
|
54
67
|
display: grid;
|
|
55
68
|
grid-auto-flow: column;
|
|
56
|
-
grid-gap:
|
|
69
|
+
grid-gap: var(--page-header-actions-gap, $page-header-actions-gap);
|
|
57
70
|
}
|
|
58
71
|
|
|
72
|
+
// The gaps on both sides of the spacer add to the distance between groups.
|
|
59
73
|
.spacer {
|
|
60
74
|
display: grid;
|
|
61
|
-
width:
|
|
75
|
+
width: calc(
|
|
76
|
+
var(--page-header-spacer-width, $page-header-spacer-width) - 2 *
|
|
77
|
+
var(--page-header-actions-gap, $page-header-actions-gap)
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.actionBar {
|
|
82
|
+
grid-column: 1 / -1;
|
|
62
83
|
}
|
|
63
84
|
}
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import { render } from '@testing-library/react';
|
|
1
|
+
import { act, fireEvent, render, screen, within } from '@testing-library/react';
|
|
2
2
|
import React from 'react';
|
|
3
|
+
import { MemoryRouter } from 'react-router-dom';
|
|
3
4
|
import { describe, expect, it, vi } from 'vitest';
|
|
4
5
|
import { noop } from '../../helpers/utils';
|
|
5
6
|
import { PageHeader } from './PageHeader';
|
|
6
|
-
import type {
|
|
7
|
+
import type {
|
|
8
|
+
PageHeaderActionItemProps,
|
|
9
|
+
PageHeaderProps,
|
|
10
|
+
} from './PageHeader.model';
|
|
7
11
|
import type { PageHeaderActionProps } from './PageHeaderAction';
|
|
8
12
|
|
|
9
13
|
vi.mock('../../hooks/useTabTitle/useTabTitle');
|
|
@@ -15,6 +19,36 @@ const defaultbulkActions: PageHeaderActionProps[] = [
|
|
|
15
19
|
},
|
|
16
20
|
];
|
|
17
21
|
|
|
22
|
+
const renderHeader = (props: PageHeaderProps): ReturnType<typeof render> =>
|
|
23
|
+
render(
|
|
24
|
+
<MemoryRouter>
|
|
25
|
+
<PageHeader {...props} />
|
|
26
|
+
</MemoryRouter>,
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
/** The action on the page header that opens the group with the given label. */
|
|
30
|
+
const groupAction = (label: string): HTMLElement =>
|
|
31
|
+
within(screen.getByTestId('page-header-actions'))
|
|
32
|
+
.getByText(label)
|
|
33
|
+
.closest('[data-test-id="action"]') as HTMLElement;
|
|
34
|
+
|
|
35
|
+
/** Labels of the actions on the action bar, if the bar is rendered. */
|
|
36
|
+
const barLabels = (): string[] | undefined => {
|
|
37
|
+
const bar = screen.queryByTestId('action-bar');
|
|
38
|
+
|
|
39
|
+
return bar
|
|
40
|
+
? within(bar)
|
|
41
|
+
.getAllByTestId('label')
|
|
42
|
+
.map((label) => label.textContent ?? '')
|
|
43
|
+
: undefined;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const clickGroup = async (label: string): Promise<void> => {
|
|
47
|
+
await act(async () => {
|
|
48
|
+
fireEvent.click(groupAction(label));
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
|
|
18
52
|
describe('PageHeader', () => {
|
|
19
53
|
it('renders the component without crashing', () => {
|
|
20
54
|
const { container } = render(<PageHeader />);
|
|
@@ -48,22 +82,6 @@ describe('PageHeader', () => {
|
|
|
48
82
|
expect(action).toBeInTheDocument();
|
|
49
83
|
});
|
|
50
84
|
|
|
51
|
-
it(`renders actions groups`, () => {
|
|
52
|
-
const actions: PageHeaderActionItemProps[] = [
|
|
53
|
-
{
|
|
54
|
-
label: 'Bulk Actions',
|
|
55
|
-
kind: 'group',
|
|
56
|
-
actions: defaultbulkActions,
|
|
57
|
-
},
|
|
58
|
-
];
|
|
59
|
-
const { container } = render(<PageHeader actions={actions} />);
|
|
60
|
-
|
|
61
|
-
const actionsGroup = container.querySelector(
|
|
62
|
-
'.page-header-group-action-container',
|
|
63
|
-
);
|
|
64
|
-
expect(actionsGroup).toBeInTheDocument();
|
|
65
|
-
});
|
|
66
|
-
|
|
67
85
|
it('renders spacers', () => {
|
|
68
86
|
const actions: PageHeaderActionItemProps[] = [
|
|
69
87
|
{
|
|
@@ -75,4 +93,375 @@ describe('PageHeader', () => {
|
|
|
75
93
|
const spacer = container.querySelector('.spacer');
|
|
76
94
|
expect(spacer).toBeInTheDocument();
|
|
77
95
|
});
|
|
96
|
+
|
|
97
|
+
describe('actions groups', () => {
|
|
98
|
+
const bulkGroup: PageHeaderActionItemProps = {
|
|
99
|
+
label: 'Bulk Actions',
|
|
100
|
+
kind: 'group',
|
|
101
|
+
actions: [
|
|
102
|
+
{ label: 'Publish', onClick: noop },
|
|
103
|
+
{ label: 'Delete', onClick: noop },
|
|
104
|
+
],
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const exportGroup: PageHeaderActionItemProps = {
|
|
108
|
+
label: 'Export',
|
|
109
|
+
kind: 'group',
|
|
110
|
+
actions: [{ label: 'Export as CSV', onClick: noop }],
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
it('renders the action of a group, without the action bar while it is closed', () => {
|
|
114
|
+
renderHeader({ actions: [bulkGroup] });
|
|
115
|
+
|
|
116
|
+
expect(groupAction('Bulk Actions')).toHaveAttribute(
|
|
117
|
+
'aria-pressed',
|
|
118
|
+
'false',
|
|
119
|
+
);
|
|
120
|
+
expect(groupAction('Bulk Actions').classList.contains('context')).toBe(
|
|
121
|
+
true,
|
|
122
|
+
);
|
|
123
|
+
expect(screen.queryByTestId('action-bar')).toBeNull();
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it('opens the action bar with the actions of the group', async () => {
|
|
127
|
+
renderHeader({ actions: [bulkGroup] });
|
|
128
|
+
|
|
129
|
+
await clickGroup('Bulk Actions');
|
|
130
|
+
|
|
131
|
+
expect(barLabels()).toEqual(['Publish', 'Delete']);
|
|
132
|
+
expect(groupAction('Bulk Actions')).toHaveAttribute(
|
|
133
|
+
'aria-pressed',
|
|
134
|
+
'true',
|
|
135
|
+
);
|
|
136
|
+
expect(groupAction('Bulk Actions').classList.contains('active')).toBe(
|
|
137
|
+
true,
|
|
138
|
+
);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('closes the action bar when the group is clicked again', async () => {
|
|
142
|
+
renderHeader({ actions: [bulkGroup] });
|
|
143
|
+
|
|
144
|
+
await clickGroup('Bulk Actions');
|
|
145
|
+
await clickGroup('Bulk Actions');
|
|
146
|
+
|
|
147
|
+
expect(screen.queryByTestId('action-bar')).toBeNull();
|
|
148
|
+
expect(groupAction('Bulk Actions')).toHaveAttribute(
|
|
149
|
+
'aria-pressed',
|
|
150
|
+
'false',
|
|
151
|
+
);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('raises onActionsGroupToggled when the group opens and closes', async () => {
|
|
155
|
+
const onActionsGroupToggled = vi.fn().mockResolvedValue(undefined);
|
|
156
|
+
renderHeader({ actions: [{ ...bulkGroup, onActionsGroupToggled }] });
|
|
157
|
+
|
|
158
|
+
await clickGroup('Bulk Actions');
|
|
159
|
+
await clickGroup('Bulk Actions');
|
|
160
|
+
|
|
161
|
+
expect(onActionsGroupToggled.mock.calls).toEqual([[true], [false]]);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it('closes the open group when another group is opened', async () => {
|
|
165
|
+
const onBulkToggled = vi.fn().mockResolvedValue(undefined);
|
|
166
|
+
const onExportToggled = vi.fn().mockResolvedValue(undefined);
|
|
167
|
+
renderHeader({
|
|
168
|
+
actions: [
|
|
169
|
+
{ ...bulkGroup, onActionsGroupToggled: onBulkToggled },
|
|
170
|
+
{ ...exportGroup, onActionsGroupToggled: onExportToggled },
|
|
171
|
+
],
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
await clickGroup('Bulk Actions');
|
|
175
|
+
await clickGroup('Export');
|
|
176
|
+
|
|
177
|
+
expect(barLabels()).toEqual(['Export as CSV']);
|
|
178
|
+
expect(groupAction('Bulk Actions')).toHaveAttribute(
|
|
179
|
+
'aria-pressed',
|
|
180
|
+
'false',
|
|
181
|
+
);
|
|
182
|
+
expect(groupAction('Export')).toHaveAttribute('aria-pressed', 'true');
|
|
183
|
+
expect(onBulkToggled.mock.calls).toEqual([[true], [false]]);
|
|
184
|
+
expect(onExportToggled.mock.calls).toEqual([[true]]);
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it(`doesn't raise onActionsGroupToggled of groups that are closed`, async () => {
|
|
188
|
+
const onExportToggled = vi.fn().mockResolvedValue(undefined);
|
|
189
|
+
renderHeader({
|
|
190
|
+
actions: [
|
|
191
|
+
bulkGroup,
|
|
192
|
+
{ ...exportGroup, onActionsGroupToggled: onExportToggled },
|
|
193
|
+
],
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
await clickGroup('Bulk Actions');
|
|
197
|
+
|
|
198
|
+
expect(onExportToggled).not.toHaveBeenCalled();
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it('stays closed when onActionsGroupToggled rejects the opening', async () => {
|
|
202
|
+
renderHeader({
|
|
203
|
+
actions: [
|
|
204
|
+
{
|
|
205
|
+
...bulkGroup,
|
|
206
|
+
onActionsGroupToggled: vi.fn().mockRejectedValue(new Error()),
|
|
207
|
+
},
|
|
208
|
+
],
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
await clickGroup('Bulk Actions');
|
|
212
|
+
|
|
213
|
+
expect(screen.queryByTestId('action-bar')).toBeNull();
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it('stays open when onActionsGroupToggled rejects the closing', async () => {
|
|
217
|
+
renderHeader({
|
|
218
|
+
actions: [
|
|
219
|
+
{
|
|
220
|
+
...bulkGroup,
|
|
221
|
+
onActionsGroupToggled: async (expanded) => {
|
|
222
|
+
if (!expanded) {
|
|
223
|
+
throw new Error();
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
exportGroup,
|
|
228
|
+
],
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
await clickGroup('Bulk Actions');
|
|
232
|
+
await clickGroup('Bulk Actions');
|
|
233
|
+
|
|
234
|
+
expect(barLabels()).toEqual(['Publish', 'Delete']);
|
|
235
|
+
|
|
236
|
+
// Opening another group has to close this one first, which it rejects.
|
|
237
|
+
await clickGroup('Export');
|
|
238
|
+
|
|
239
|
+
expect(barLabels()).toEqual(['Publish', 'Delete']);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it('closes the open group even if the group that was clicked rejects the opening', async () => {
|
|
243
|
+
renderHeader({
|
|
244
|
+
actions: [
|
|
245
|
+
bulkGroup,
|
|
246
|
+
{
|
|
247
|
+
...exportGroup,
|
|
248
|
+
onActionsGroupToggled: vi.fn().mockRejectedValue(new Error()),
|
|
249
|
+
},
|
|
250
|
+
],
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
await clickGroup('Bulk Actions');
|
|
254
|
+
await clickGroup('Export');
|
|
255
|
+
|
|
256
|
+
expect(screen.queryByTestId('action-bar')).toBeNull();
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
it('opens the group set to openActionsGroupOnStart without raising onActionsGroupToggled', () => {
|
|
260
|
+
const onActionsGroupToggled = vi.fn().mockResolvedValue(undefined);
|
|
261
|
+
renderHeader({
|
|
262
|
+
actions: [
|
|
263
|
+
bulkGroup,
|
|
264
|
+
{
|
|
265
|
+
...exportGroup,
|
|
266
|
+
openActionsGroupOnStart: true,
|
|
267
|
+
onActionsGroupToggled,
|
|
268
|
+
},
|
|
269
|
+
],
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
expect(barLabels()).toEqual(['Export as CSV']);
|
|
273
|
+
expect(onActionsGroupToggled).not.toHaveBeenCalled();
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
it('opens only the first of several groups set to openActionsGroupOnStart', () => {
|
|
277
|
+
renderHeader({
|
|
278
|
+
actions: [
|
|
279
|
+
{ ...bulkGroup, openActionsGroupOnStart: true },
|
|
280
|
+
{ ...exportGroup, openActionsGroupOnStart: true },
|
|
281
|
+
],
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
expect(barLabels()).toEqual(['Publish', 'Delete']);
|
|
285
|
+
expect(groupAction('Export')).toHaveAttribute('aria-pressed', 'false');
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
it('keeps the group open while actions are added in front of it', async () => {
|
|
289
|
+
const { rerender } = renderHeader({ actions: [bulkGroup] });
|
|
290
|
+
|
|
291
|
+
await clickGroup('Bulk Actions');
|
|
292
|
+
|
|
293
|
+
rerender(
|
|
294
|
+
<MemoryRouter>
|
|
295
|
+
<PageHeader
|
|
296
|
+
actions={[
|
|
297
|
+
{ label: 'Undo', kind: 'action', onClick: noop },
|
|
298
|
+
exportGroup,
|
|
299
|
+
bulkGroup,
|
|
300
|
+
]}
|
|
301
|
+
/>
|
|
302
|
+
</MemoryRouter>,
|
|
303
|
+
);
|
|
304
|
+
|
|
305
|
+
expect(barLabels()).toEqual(['Publish', 'Delete']);
|
|
306
|
+
expect(groupAction('Export')).toHaveAttribute('aria-pressed', 'false');
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
it('closes the action bar when the open group is removed', async () => {
|
|
310
|
+
const { rerender } = renderHeader({ actions: [bulkGroup] });
|
|
311
|
+
|
|
312
|
+
await clickGroup('Bulk Actions');
|
|
313
|
+
|
|
314
|
+
rerender(
|
|
315
|
+
<MemoryRouter>
|
|
316
|
+
<PageHeader actions={[exportGroup]} />
|
|
317
|
+
</MemoryRouter>,
|
|
318
|
+
);
|
|
319
|
+
|
|
320
|
+
expect(screen.queryByTestId('action-bar')).toBeNull();
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
it('renders the actionBarLabel on the action bar', async () => {
|
|
324
|
+
renderHeader({
|
|
325
|
+
actions: [{ ...bulkGroup, actionBarLabel: 'Selected 3' }],
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
await clickGroup('Bulk Actions');
|
|
329
|
+
|
|
330
|
+
expect(screen.getByTestId('action-bar-label')).toHaveTextContent(
|
|
331
|
+
'Selected 3',
|
|
332
|
+
);
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
it('renders no label on the action bar by default', async () => {
|
|
336
|
+
renderHeader({ actions: [bulkGroup] });
|
|
337
|
+
|
|
338
|
+
await clickGroup('Bulk Actions');
|
|
339
|
+
|
|
340
|
+
expect(screen.queryByTestId('action-bar-label')).toBeNull();
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
it('raises onClick of an action on the action bar', async () => {
|
|
344
|
+
const onClick = vi.fn();
|
|
345
|
+
renderHeader({
|
|
346
|
+
actions: [{ ...bulkGroup, actions: [{ label: 'Publish', onClick }] }],
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
await clickGroup('Bulk Actions');
|
|
350
|
+
fireEvent.click(
|
|
351
|
+
within(screen.getByTestId('action-bar')).getByTestId('action'),
|
|
352
|
+
);
|
|
353
|
+
|
|
354
|
+
expect(onClick).toHaveBeenCalledTimes(1);
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
it('disables every action of the group when groupActionsDisabled is set', async () => {
|
|
358
|
+
renderHeader({ actions: [{ ...bulkGroup, groupActionsDisabled: true }] });
|
|
359
|
+
|
|
360
|
+
await clickGroup('Bulk Actions');
|
|
361
|
+
|
|
362
|
+
within(screen.getByTestId('action-bar'))
|
|
363
|
+
.getAllByTestId('action')
|
|
364
|
+
.forEach((action) => expect(action).toBeDisabled());
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
it('keeps an action disabled on its own disabled', async () => {
|
|
368
|
+
renderHeader({
|
|
369
|
+
actions: [
|
|
370
|
+
{
|
|
371
|
+
...bulkGroup,
|
|
372
|
+
groupActionsDisabled: false,
|
|
373
|
+
actions: [
|
|
374
|
+
{ label: 'Publish', onClick: noop },
|
|
375
|
+
{ label: 'Delete', disabled: true, onClick: noop },
|
|
376
|
+
],
|
|
377
|
+
},
|
|
378
|
+
],
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
await clickGroup('Bulk Actions');
|
|
382
|
+
|
|
383
|
+
const [publish, remove] = within(
|
|
384
|
+
screen.getByTestId('action-bar'),
|
|
385
|
+
).getAllByTestId('action');
|
|
386
|
+
|
|
387
|
+
expect(publish).not.toBeDisabled();
|
|
388
|
+
expect(remove).toBeDisabled();
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
it('renders link actions of the group as links on the action bar', async () => {
|
|
392
|
+
renderHeader({
|
|
393
|
+
actions: [
|
|
394
|
+
{
|
|
395
|
+
...bulkGroup,
|
|
396
|
+
actions: [{ label: 'Open Export', path: '/export', tag: 'NEW' }],
|
|
397
|
+
},
|
|
398
|
+
],
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
await clickGroup('Bulk Actions');
|
|
402
|
+
|
|
403
|
+
const action = within(screen.getByTestId('action-bar')).getByTestId(
|
|
404
|
+
'action',
|
|
405
|
+
);
|
|
406
|
+
|
|
407
|
+
expect(action).toHaveAttribute('href', '/export');
|
|
408
|
+
expect(within(action).getByTestId('tag')).toHaveTextContent('NEW');
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
it('disables the action of a disabled group', async () => {
|
|
412
|
+
const onActionsGroupToggled = vi.fn().mockResolvedValue(undefined);
|
|
413
|
+
renderHeader({
|
|
414
|
+
actions: [{ ...bulkGroup, disabled: true, onActionsGroupToggled }],
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
expect(groupAction('Bulk Actions')).toBeDisabled();
|
|
418
|
+
|
|
419
|
+
await clickGroup('Bulk Actions');
|
|
420
|
+
|
|
421
|
+
expect(onActionsGroupToggled).not.toHaveBeenCalled();
|
|
422
|
+
expect(screen.queryByTestId('action-bar')).toBeNull();
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
it('does not carry a pending confirmation over to another group', async () => {
|
|
426
|
+
const onExportDelete = vi.fn();
|
|
427
|
+
renderHeader({
|
|
428
|
+
actions: [
|
|
429
|
+
{
|
|
430
|
+
...bulkGroup,
|
|
431
|
+
actions: [
|
|
432
|
+
{ label: 'Delete', confirmationMode: 'Simple', onClick: noop },
|
|
433
|
+
],
|
|
434
|
+
},
|
|
435
|
+
{
|
|
436
|
+
...exportGroup,
|
|
437
|
+
actions: [
|
|
438
|
+
{
|
|
439
|
+
label: 'Delete',
|
|
440
|
+
confirmationMode: 'Simple',
|
|
441
|
+
onClick: onExportDelete,
|
|
442
|
+
},
|
|
443
|
+
],
|
|
444
|
+
},
|
|
445
|
+
],
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
await clickGroup('Bulk Actions');
|
|
449
|
+
fireEvent.click(
|
|
450
|
+
within(screen.getByTestId('action-bar')).getByTestId('action'),
|
|
451
|
+
);
|
|
452
|
+
|
|
453
|
+
expect(screen.getByTestId('confirm')).toBeInTheDocument();
|
|
454
|
+
|
|
455
|
+
await clickGroup('Export');
|
|
456
|
+
|
|
457
|
+
expect(screen.queryByTestId('confirm')).toBeNull();
|
|
458
|
+
|
|
459
|
+
// The first click only asks for the confirmation.
|
|
460
|
+
fireEvent.click(
|
|
461
|
+
within(screen.getByTestId('action-bar')).getByTestId('action'),
|
|
462
|
+
);
|
|
463
|
+
|
|
464
|
+
expect(onExportDelete).not.toHaveBeenCalled();
|
|
465
|
+
});
|
|
466
|
+
});
|
|
78
467
|
});
|