@axinom/mosaic-ui 0.49.0-rc.5 → 0.49.0-rc.7

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.
Files changed (46) hide show
  1. package/dist/components/DynamicDataList/DynamicDataList.d.ts.map +1 -1
  2. package/dist/components/Explorer/Explorer.d.ts.map +1 -1
  3. package/dist/components/FormStation/FormStationHeader/FormStationHeader.d.ts.map +1 -1
  4. package/dist/components/PageHeader/PageHeader.d.ts +9 -2
  5. package/dist/components/PageHeader/PageHeader.d.ts.map +1 -1
  6. package/dist/components/PageHeader/PageHeader.model.d.ts +11 -12
  7. package/dist/components/PageHeader/PageHeader.model.d.ts.map +1 -1
  8. package/dist/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroup.d.ts +35 -0
  9. package/dist/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroup.d.ts.map +1 -0
  10. package/dist/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroupsContext.d.ts +7 -0
  11. package/dist/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroupsContext.d.ts.map +1 -0
  12. package/dist/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroupsContextProvider.d.ts +3 -0
  13. package/dist/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroupsContextProvider.d.ts.map +1 -0
  14. package/dist/components/PageHeader/index.d.ts +1 -1
  15. package/dist/components/PageHeader/index.d.ts.map +1 -1
  16. package/dist/index.es.js +4 -4
  17. package/dist/index.es.js.map +1 -1
  18. package/dist/index.js +4 -4
  19. package/dist/index.js.map +1 -1
  20. package/dist/{components/DynamicDataList/helpers/generateId.d.ts → utils/GenerateId.d.ts} +1 -1
  21. package/dist/utils/GenerateId.d.ts.map +1 -0
  22. package/package.json +3 -3
  23. package/src/components/DynamicDataList/DynamicDataList.spec.tsx +2 -1
  24. package/src/components/DynamicDataList/DynamicDataList.tsx +1 -1
  25. package/src/components/Explorer/Explorer.spec.tsx +26 -16
  26. package/src/components/Explorer/Explorer.tsx +47 -28
  27. package/src/components/Explorer/NavigationExplorer/NavigationExplorer.spec.tsx +2 -2
  28. package/src/components/Explorer/SelectionExplorer/SelectionExplorer.spec.tsx +8 -32
  29. package/src/components/FormStation/FormStationHeader/FormStationHeader.tsx +34 -30
  30. package/src/components/PageHeader/PageHeader.model.ts +10 -12
  31. package/src/components/PageHeader/PageHeader.scss +7 -3
  32. package/src/components/PageHeader/PageHeader.spec.tsx +28 -86
  33. package/src/components/PageHeader/PageHeader.stories.tsx +32 -7
  34. package/src/components/PageHeader/PageHeader.tsx +50 -77
  35. package/src/components/PageHeader/{PageHeaderBulkActions/PageHeaderBulkActions.scss → PageHeaderActionsGroup/PageHeaderActionsGroup.scss} +21 -21
  36. package/src/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroup.spec.tsx +105 -0
  37. package/src/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroup.tsx +224 -0
  38. package/src/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroupsContext.ts +13 -0
  39. package/src/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroupsContextProvider.tsx +30 -0
  40. package/src/components/PageHeader/index.ts +1 -1
  41. package/dist/components/DynamicDataList/helpers/generateId.d.ts.map +0 -1
  42. package/dist/components/PageHeader/PageHeaderBulkActions/PageHeaderBulkActions.d.ts +0 -22
  43. package/dist/components/PageHeader/PageHeaderBulkActions/PageHeaderBulkActions.d.ts.map +0 -1
  44. package/src/components/PageHeader/PageHeaderBulkActions/PageHeaderBulkActions.spec.tsx +0 -369
  45. package/src/components/PageHeader/PageHeaderBulkActions/PageHeaderBulkActions.tsx +0 -188
  46. /package/src/{components/DynamicDataList/helpers/generateId.ts → utils/GenerateId.ts} +0 -0
@@ -3,4 +3,4 @@
3
3
  * @returns UUID
4
4
  */
5
5
  export declare const uuid: () => string;
6
- //# sourceMappingURL=generateId.d.ts.map
6
+ //# sourceMappingURL=GenerateId.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GenerateId.d.ts","sourceRoot":"","sources":["../../src/utils/GenerateId.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,IAAI,QAAO,MAKvB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axinom/mosaic-ui",
3
- "version": "0.49.0-rc.5",
3
+ "version": "0.49.0-rc.7",
4
4
  "description": "UI components for building Axinom Mosaic applications",
5
5
  "author": "Axinom",
6
6
  "license": "PROPRIETARY",
@@ -32,7 +32,7 @@
32
32
  "build-storybook": "storybook build"
33
33
  },
34
34
  "dependencies": {
35
- "@axinom/mosaic-core": "^0.4.22-rc.5",
35
+ "@axinom/mosaic-core": "^0.4.22-rc.7",
36
36
  "@faker-js/faker": "^7.4.0",
37
37
  "@popperjs/core": "^2.11.8",
38
38
  "clsx": "^1.1.0",
@@ -105,5 +105,5 @@
105
105
  "publishConfig": {
106
106
  "access": "public"
107
107
  },
108
- "gitHead": "4f50c5ef83f997ed19fef76fb4786e4aa63679f5"
108
+ "gitHead": "9df1857d137a9f1556f33ad2ed8cef698f1006f8"
109
109
  }
@@ -9,7 +9,8 @@ import { DynamicListRow } from './DynamicListRow/DynamicListRow';
9
9
  import { useDataHandler } from './helpers/useDataHandler';
10
10
 
11
11
  jest.mock('./helpers/useDataHandler');
12
- jest.mock('./helpers/generateId', () => ({
12
+
13
+ jest.mock('../../utils/GenerateId', () => ({
13
14
  uuid: jest.fn().mockReturnValue('test-uuid'),
14
15
  }));
15
16
 
@@ -10,6 +10,7 @@ import {
10
10
  import { OptionalObjectSchema } from 'yup/lib/object';
11
11
  import { noop } from '../../helpers/utils';
12
12
  import { Data } from '../../types/data';
13
+ import { uuid } from '../../utils/GenerateId';
13
14
  import { ActionData } from '../Actions';
14
15
  import { ObjectSchemaDefinition } from '../FormStation';
15
16
  import { DynamicListColumn } from './DynamicDataList.model';
@@ -21,7 +22,6 @@ import {
21
22
  } from './DynamicListDataEntry/DynamicListDataEntry';
22
23
  import { DynamicListHeader } from './DynamicListHeader/DynamicListHeader';
23
24
  import { DynamicListRow } from './DynamicListRow/DynamicListRow';
24
- import { uuid } from './helpers/generateId';
25
25
  import { useColumnDefs } from './helpers/useColumnDefs';
26
26
  import { useDataHandler } from './helpers/useDataHandler';
27
27
  import { useRowAnimation } from './helpers/useRowAnimation';
@@ -24,7 +24,7 @@ import { MessageBar } from '../MessageBar';
24
24
  import { StationError } from '../models';
25
25
  import { PageHeaderAction } from '../PageHeader';
26
26
  import { PageHeader } from '../PageHeader/PageHeader';
27
- import { PageHeaderBulkActions } from '../PageHeader/PageHeaderBulkActions/PageHeaderBulkActions';
27
+ import { PageHeaderActionsGroup } from '../PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroup';
28
28
  import * as GS from '../Utils/State/GlobalState';
29
29
  import { Explorer, ExplorerProps } from './Explorer';
30
30
  import {
@@ -34,6 +34,10 @@ import {
34
34
  } from './Explorer.model';
35
35
  import { StationMessage } from './useStationMessage';
36
36
 
37
+ jest.mock('../../utils/GenerateId', () => ({
38
+ uuid: jest.fn().mockReturnValue('test-uuid'),
39
+ }));
40
+
37
41
  interface ExplorerTestData {
38
42
  id: number;
39
43
  title: string;
@@ -152,7 +156,6 @@ describe('Explorer', () => {
152
156
  columns={[{ propertyName: 'id' }]}
153
157
  dataProvider={provider}
154
158
  stationKey="mock-key"
155
- openBulkActionsOnStart={true}
156
159
  bulkActions={[{ label: 'Something', onClick: jest.fn() }]}
157
160
  />,
158
161
  );
@@ -166,8 +169,9 @@ describe('Explorer', () => {
166
169
  await wrapper.update();
167
170
  });
168
171
 
169
- wrapper.update();
170
- expect(wrapper.find(PageHeader).prop('bulkActionsDisabled')).toBe(true);
172
+ expect(
173
+ wrapper.find(PageHeaderActionsGroup).prop('groupActionsDisabled'),
174
+ ).toBe(true);
171
175
  });
172
176
 
173
177
  it('enables bulk actions if filtered results are returned', async () => {
@@ -203,7 +207,10 @@ describe('Explorer', () => {
203
207
  });
204
208
 
205
209
  wrapper.update();
206
- expect(wrapper.find(PageHeader).prop('bulkActionsDisabled')).toBe(false);
210
+
211
+ expect(
212
+ wrapper.find(PageHeaderActionsGroup).prop('groupActionsDisabled'),
213
+ ).toBe(false);
207
214
  });
208
215
 
209
216
  it('disables bulk actions if no filtered results are returned', async () => {
@@ -239,7 +246,9 @@ describe('Explorer', () => {
239
246
  });
240
247
 
241
248
  wrapper.update();
242
- expect(wrapper.find(PageHeader).prop('bulkActionsDisabled')).toBe(true);
249
+ expect(
250
+ wrapper.find(PageHeaderActionsGroup).prop('groupActionsDisabled'),
251
+ ).toBe(true);
243
252
  });
244
253
 
245
254
  it('Reloads data when a bulk action with reloadData is triggered', async () => {
@@ -267,10 +276,10 @@ describe('Explorer', () => {
267
276
  // Initial Data Loading
268
277
  expect(spy).toHaveBeenCalledTimes(1);
269
278
 
270
- const header = wrapper.find(PageHeader);
279
+ const bulkActions = wrapper.find(PageHeaderActionsGroup);
271
280
 
272
281
  await act(async () => {
273
- header.prop('bulkActions')?.[0].onClick?.();
282
+ bulkActions.prop('actions')?.[0].onClick?.();
274
283
 
275
284
  await wrapper.update();
276
285
  });
@@ -301,9 +310,9 @@ describe('Explorer', () => {
301
310
  return wrapper;
302
311
  });
303
312
 
304
- const header = wrapper.find(PageHeader);
313
+ const bulkActions = wrapper.find(PageHeaderActionsGroup);
305
314
  await act(async () => {
306
- header.prop('bulkActions')?.[0].onClick?.();
315
+ bulkActions.prop('actions')?.[0].onClick?.();
307
316
  await wrapper.update();
308
317
  });
309
318
 
@@ -336,9 +345,9 @@ describe('Explorer', () => {
336
345
  return wrapper;
337
346
  });
338
347
 
339
- const header = wrapper.find(PageHeader);
348
+ const bulkActions = wrapper.find(PageHeaderActionsGroup);
340
349
  await act(async () => {
341
- header.prop('bulkActions')?.[0].onClick?.();
350
+ bulkActions.prop('actions')?.[0].onClick?.();
342
351
  await wrapper.update();
343
352
  });
344
353
 
@@ -401,7 +410,7 @@ describe('Explorer', () => {
401
410
  expectComponentReceivesValue(header, 'title');
402
411
  // expectComponentReceivesValue(header, 'actions');
403
412
  // expectComponentReceivesValue(header, 'bulkActions');
404
- expectComponentReceivesValue(header, 'openBulkActionsOnStart');
413
+ // expectComponentReceivesValue(header, 'openBulkActionsOnStart');
405
414
 
406
415
  const filters = wrapper.find(Filters);
407
416
  expectComponentReceivesValue(filters, 'filters');
@@ -2025,9 +2034,10 @@ describe('Explorer', () => {
2025
2034
  });
2026
2035
 
2027
2036
  await act(async () => {
2028
- wrapper.find(PageHeaderBulkActions).prop('onBulkActionsToggled')!(true);
2029
-
2030
- wrapper.find(PageHeaderBulkActions).prop('onBulkActionsToggled')!(false);
2037
+ wrapper.find(PageHeaderActionsGroup).prop('onActionsGroupToggled')!(true);
2038
+ wrapper.find(PageHeaderActionsGroup).prop('onActionsGroupToggled')!(
2039
+ false,
2040
+ );
2031
2041
  });
2032
2042
 
2033
2043
  expect(spy).toHaveBeenCalledTimes(2);
@@ -7,7 +7,7 @@ import {
7
7
  useEffect,
8
8
  useState,
9
9
  } from 'react';
10
- import { ActionData } from '..';
10
+ import { ActionData, IconName } from '..';
11
11
  import { noop } from '../../helpers/utils';
12
12
  import { showNotification } from '../../initialize';
13
13
  import { Data } from '../../types/data';
@@ -23,7 +23,11 @@ import {
23
23
  ListSelectMode,
24
24
  SortData,
25
25
  } from '../List';
26
- import { PageHeader, PageHeaderActionProps } from '../PageHeader';
26
+ import {
27
+ PageHeader,
28
+ PageHeaderActionItemProps,
29
+ PageHeaderActionProps,
30
+ } from '../PageHeader';
27
31
  import { isPageHeaderNavigationAction } from '../PageHeader/PageHeaderAction/PageHeaderAction';
28
32
  import { PageHeaderJsActionProps } from '../PageHeader/PageHeaderAction/PageHeaderAction.model';
29
33
  import { getState, storeState } from '../Utils/State/GlobalState';
@@ -348,24 +352,48 @@ export const Explorer = React.forwardRef(function Explorer<T extends Data>(
348
352
  });
349
353
  };
350
354
 
351
- const pageHeaderActionsHandler = (): PageHeaderActionProps[] => {
352
- return (actions ?? []).map((action) => {
353
- return isPageHeaderNavigationAction(action)
354
- ? action
355
- : {
356
- ...action,
357
- onClick: async () => {
358
- try {
359
- const result = await action.onClick();
360
- if (result) {
361
- setStationMessage(errMsg(result));
355
+ const pageHeaderActionsHandler = (): PageHeaderActionItemProps[] => {
356
+ const headerActions: PageHeaderActionItemProps[] = [];
357
+
358
+ if (bulkActions && bulkActions.length > 0) {
359
+ headerActions.push({
360
+ label: 'Bulk Actions',
361
+ icon: IconName.Bulk,
362
+ kind: 'group',
363
+ actions: bulkActionsHandler(),
364
+ openActionsGroupOnStart: openBulkActionsOnStart,
365
+ onActionsGroupToggled: (isOpen) => {
366
+ setIsBulkOpen(isOpen);
367
+ onBulkActionsToggled(isOpen);
368
+ },
369
+ groupActionsDisabled:
370
+ itemSelection.items?.length === 0 || resultCount?.filtered === 0,
371
+ });
372
+ headerActions.push({ kind: 'spacer' });
373
+ }
374
+
375
+ actions?.forEach((action) => {
376
+ headerActions.push({
377
+ ...(isPageHeaderNavigationAction(action)
378
+ ? action
379
+ : {
380
+ ...action,
381
+ onClick: async () => {
382
+ try {
383
+ const result = await action.onClick();
384
+ if (result) {
385
+ setStationMessage(errMsg(result));
386
+ }
387
+ } catch (error) {
388
+ setStationMessage(errMsg(error, errAction));
362
389
  }
363
- } catch (error) {
364
- setStationMessage(errMsg(error, errAction));
365
- }
366
- },
367
- };
390
+ },
391
+ }),
392
+ kind: 'action',
393
+ });
368
394
  });
395
+
396
+ return headerActions;
369
397
  };
370
398
 
371
399
  const bulkActionsHandler = (): PageHeaderJsActionProps[] => {
@@ -421,16 +449,7 @@ export const Explorer = React.forwardRef(function Explorer<T extends Data>(
421
449
  <PageHeader
422
450
  title={title}
423
451
  subtitle={resultsTitle}
424
- actions={actions && pageHeaderActionsHandler()}
425
- bulkActions={bulkActions && bulkActionsHandler()}
426
- openBulkActionsOnStart={openBulkActionsOnStart}
427
- bulkActionsDisabled={
428
- itemSelection.items?.length === 0 || resultCount?.filtered === 0
429
- }
430
- onBulkActionsToggled={(isOpen) => {
431
- setIsBulkOpen(isOpen);
432
- onBulkActionsToggled(isOpen);
433
- }}
452
+ actions={pageHeaderActionsHandler()}
434
453
  setTabTitle={setTabTitle}
435
454
  />
436
455
  {StationMessage}
@@ -117,7 +117,7 @@ describe('NavigationExplorer', () => {
117
117
  return wrapper;
118
118
  });
119
119
 
120
- const action = wrapper.find(PageHeaderAction);
120
+ const action = wrapper.find(PageHeaderAction).last();
121
121
  expect(action.props().label).toBe('test');
122
122
  });
123
123
 
@@ -219,7 +219,7 @@ describe('NavigationExplorer', () => {
219
219
  return wrapper;
220
220
  });
221
221
 
222
- const createAction = wrapper.find(PageHeaderAction);
222
+ const createAction = wrapper.find(PageHeaderAction).last();
223
223
 
224
224
  createAction.simulate('click');
225
225
 
@@ -3,14 +3,16 @@ import { noop } from 'lodash';
3
3
  import React from 'react';
4
4
  import { act } from 'react-dom/test-utils';
5
5
  import { actWithReturn } from '../../../helpers/testing';
6
- import * as app from '../../../initialize';
7
6
  import { Column } from '../../List';
8
- import { PageHeader } from '../../PageHeader';
9
- import { PageHeaderBulkActions } from '../../PageHeader/PageHeaderBulkActions/PageHeaderBulkActions';
7
+ import { PageHeaderActionsGroup } from '../../PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroup';
10
8
  import { Explorer } from '../Explorer';
11
9
  import { ExplorerDataProvider } from '../Explorer.model';
12
10
  import { SelectionExplorer } from './SelectionExplorer';
13
11
 
12
+ jest.mock('../../../utils/GenerateId', () => ({
13
+ uuid: jest.fn().mockReturnValue('test-uuid'),
14
+ }));
15
+
14
16
  interface SelectExplorerTestData {
15
17
  id: string;
16
18
  desc: string;
@@ -78,7 +80,7 @@ describe('SelectionExplorer', () => {
78
80
  return wrapper;
79
81
  });
80
82
 
81
- const bulkActions = wrapper.find(PageHeaderBulkActions);
83
+ const bulkActions = wrapper.find(PageHeaderActionsGroup);
82
84
 
83
85
  expect(bulkActions.exists()).toBe(true);
84
86
  });
@@ -101,38 +103,12 @@ describe('SelectionExplorer', () => {
101
103
  return wrapper;
102
104
  });
103
105
 
104
- const bulkActions = wrapper.find(PageHeaderBulkActions);
106
+ const bulkActions = wrapper.find(PageHeaderActionsGroup);
105
107
 
106
108
  expect(bulkActions.exists()).toBe(false);
107
109
  });
108
110
 
109
- it('Does not call "showNotification" when "Apply Selection" is clicked', async () => {
110
- const [provider] = getDataProvider();
111
- const showNotificationSpy: jest.SpyInstance = jest.spyOn(
112
- app,
113
- 'showNotification',
114
- );
115
-
116
- const wrapper = await actWithReturn(async () => {
117
- const wrapper = mount(
118
- <SelectionExplorer
119
- columns={mockListColumns}
120
- dataProvider={provider}
121
- stationKey="mock-key"
122
- allowBulkSelect={true}
123
- />,
124
- );
125
- return wrapper;
126
- });
127
-
128
- const header = wrapper.find(PageHeader);
129
- await act(async () => {
130
- header.prop('bulkActions')?.[0].onClick?.();
131
- await wrapper.update();
132
- });
133
-
134
- expect(showNotificationSpy).toHaveBeenCalledTimes(0);
135
- });
111
+ it.todo('Does not call "showNotification" when "Apply Selection" is clicked');
136
112
 
137
113
  it('sends onSelection callback when the selection of a single item is triggered', async () => {
138
114
  const [provider] = getDataProvider();
@@ -1,10 +1,11 @@
1
1
  import { FormikValues, useFormikContext } from 'formik';
2
- import React, { useEffect } from 'react';
2
+ import React, { useEffect, useMemo } from 'react';
3
3
  import { useHistory } from 'react-router-dom';
4
4
  import { SaveIndicatorType, setSaveIndicator } from '../../../initialize';
5
5
  import { IconName } from '../../Icons';
6
6
  import {
7
7
  PageHeader,
8
+ PageHeaderActionItemProps,
8
9
  PageHeaderActionType,
9
10
  PageHeaderProps,
10
11
  } from '../../PageHeader';
@@ -49,41 +50,44 @@ export const FormStationHeader: React.FC<
49
50
 
50
51
  const title = useTitle(titleProperty, defaultTitle);
51
52
 
53
+ const actions: PageHeaderActionItemProps[] = useMemo(() => {
54
+ const actionItems: PageHeaderActionItemProps[] = [];
55
+
56
+ if (dirty) {
57
+ actionItems.push({
58
+ label: 'Undo Changes',
59
+ icon: IconName.Undo,
60
+ kind: 'action',
61
+ actionType: PageHeaderActionType.Context,
62
+ onClick: () => {
63
+ resetForm();
64
+ },
65
+ });
66
+ }
67
+
68
+ if (cancelNavigationUrl) {
69
+ actionItems.push({
70
+ label: 'Cancel',
71
+ icon: IconName.X,
72
+ kind: 'action',
73
+ onClick: () => {
74
+ resetForm();
75
+ // If the form has errors, Navigation needs to be wrapped in a promise or timeout.
76
+ Promise.resolve().then(() => history.push(cancelNavigationUrl));
77
+ },
78
+ });
79
+ }
80
+
81
+ return actionItems;
82
+ }, [cancelNavigationUrl, dirty, history, resetForm]);
83
+
52
84
  return (
53
85
  <PageHeader
54
86
  title={title}
55
87
  subtitle={subtitle}
56
88
  className={className}
57
89
  setTabTitle={setTabTitle}
58
- actions={[
59
- ...(dirty === true // add undo action if form as been altered
60
- ? [
61
- {
62
- label: 'Undo Changes',
63
- icon: IconName.Undo,
64
- actionType: PageHeaderActionType.Context,
65
- onClick: () => {
66
- resetForm();
67
- },
68
- },
69
- ]
70
- : []),
71
- ...(cancelNavigationUrl // add cancel action if applicable
72
- ? [
73
- {
74
- label: 'Cancel',
75
- icon: IconName.X,
76
- onClick: () => {
77
- resetForm();
78
- // If the form has errors, Navigation needs to be wrapped in a promise or timeout.
79
- Promise.resolve().then(() =>
80
- history.push(cancelNavigationUrl),
81
- );
82
- },
83
- },
84
- ]
85
- : []),
86
- ]}
90
+ actions={actions}
87
91
  />
88
92
  );
89
93
  };
@@ -1,4 +1,5 @@
1
1
  import { PageHeaderActionProps } from './PageHeaderAction/PageHeaderAction.model';
2
+ import { PageHeaderActionsGroupProps } from './PageHeaderActionsGroup/PageHeaderActionsGroup';
2
3
 
3
4
  export interface PageHeaderProps {
4
5
  /** Title shown in page header */
@@ -6,20 +7,17 @@ export interface PageHeaderProps {
6
7
  /** Subtitle shown in page header */
7
8
  subtitle?: string;
8
9
  /** Array of actions to be rendered. (default: []) */
9
- actions?: PageHeaderActionProps[];
10
- /** Array of Bulk Actions to be rendered. If populated, Bulk Actions will become available. (default: []) */
11
- bulkActions?: PageHeaderActionProps[];
12
- /** Whether or bulk actions are shown by default. (default: false) */
13
- openBulkActionsOnStart?: boolean;
14
- /** Whether or not bulk actions are disabled (default: false)*/
15
- bulkActionsDisabled?: boolean;
16
- /**
17
- * Callback to emit when Bulk Actions is toggled
18
- * The expanded state is supplied as an argument
19
- */
20
- onBulkActionsToggled?: (expanded: boolean) => void;
10
+ actions?: PageHeaderActionItemProps[];
21
11
  /** CSS Class name for additional styles */
22
12
  className?: string;
23
13
  /** Update the tab title using the 'title' field. (default: true) */
24
14
  setTabTitle?: boolean;
25
15
  }
16
+
17
+ // eslint-disable-next-line @typescript-eslint/no-empty-interface
18
+ export interface PageHeaderSpacerProps {}
19
+
20
+ export type PageHeaderActionItemProps =
21
+ | (PageHeaderSpacerProps & { kind: 'spacer' })
22
+ | (PageHeaderActionProps & { kind: 'action' })
23
+ | (PageHeaderActionsGroupProps & { kind: 'group' });
@@ -5,7 +5,7 @@
5
5
 
6
6
  height: $page-header-height;
7
7
  display: grid;
8
- grid-template-columns: minmax(min-content, 1fr) max-content max-content;
8
+ grid-template-columns: minmax(30%, 1fr) auto;
9
9
  grid-template-rows: 1fr;
10
10
 
11
11
  @media only screen and (min-width: $XL-min-size) {
@@ -52,9 +52,13 @@
52
52
 
53
53
  .actions {
54
54
  display: grid;
55
- grid-template-rows: 1fr;
56
55
  grid-auto-flow: column;
56
+ grid-auto-columns: minmax(0, min-content);
57
57
  grid-gap: 1px;
58
- justify-items: end;
58
+ }
59
+
60
+ .spacer {
61
+ display: grid;
62
+ width: 8px;
59
63
  }
60
64
  }
@@ -1,10 +1,11 @@
1
- import { mount, shallow } from 'enzyme';
1
+ import { shallow } from 'enzyme';
2
2
  import React from 'react';
3
3
  import { noop } from '../../helpers/utils';
4
4
  import { PageHeader } from './PageHeader';
5
+ import { PageHeaderActionItemProps } from './PageHeader.model';
6
+ import { PageHeaderActionProps } from './PageHeaderAction';
5
7
  import { PageHeaderAction } from './PageHeaderAction/PageHeaderAction';
6
- import { PageHeaderActionProps } from './PageHeaderAction/PageHeaderAction.model';
7
- import { PageHeaderBulkActions } from './PageHeaderBulkActions/PageHeaderBulkActions';
8
+ import { PageHeaderActionsGroup } from './PageHeaderActionsGroup/PageHeaderActionsGroup';
8
9
 
9
10
  jest.mock('../../hooks/useTabTitle/useTabTitle');
10
11
 
@@ -40,96 +41,37 @@ describe('PageHeader', () => {
40
41
  });
41
42
 
42
43
  it(`renders actions`, () => {
43
- const wrapper = shallow(<PageHeader actions={defaultbulkActions} />);
44
+ const wrapper = shallow(
45
+ <PageHeader actions={[{ ...defaultbulkActions[0], kind: 'action' }]} />,
46
+ );
44
47
 
45
48
  const action = wrapper.find(PageHeaderAction);
46
49
  expect(action.exists()).toBe(true);
47
50
  });
48
51
 
49
- it(`adds a 10px left margin to the actions container as a spacer when actions are present`, () => {
50
- const wrapper = shallow(<PageHeader actions={defaultbulkActions} />);
51
-
52
- const actionsContainer = wrapper
53
- .find('.actions')
54
- .prop('style') as React.CSSProperties;
55
-
56
- expect(actionsContainer.marginLeft).toBe('10px');
57
- });
58
-
59
- it(`does not add a 10px left margin to the actions container when no actions are present`, () => {
60
- const wrapper = shallow(<PageHeader />);
61
-
62
- const actionsContainer = wrapper
63
- .find('.actions')
64
- .prop('style') as React.CSSProperties;
65
-
66
- expect(actionsContainer.marginLeft).toBeUndefined();
67
- });
68
-
69
- it(`does not render 'PageHeaderBulkActions' if bulkActions prop is empty`, () => {
70
- const wrapper = mount(<PageHeader />);
71
-
72
- const bulkActions = wrapper.find(PageHeaderBulkActions);
73
-
74
- expect(bulkActions.exists()).toBe(false);
75
- });
76
-
77
- it(`renders 'PageHeaderBulkActions' if bulkActions prop is populated`, () => {
78
- const wrapper = mount(<PageHeader bulkActions={defaultbulkActions} />);
79
-
80
- const bulkActions = wrapper.find(PageHeaderBulkActions);
81
-
82
- expect(bulkActions.exists()).toBe(true);
83
- });
84
-
85
- it('raises onBulkActionsToggled', () => {
86
- const spy = jest.fn();
87
-
88
- const wrapper = mount(
89
- <PageHeader
90
- bulkActions={defaultbulkActions}
91
- onBulkActionsToggled={spy}
92
- />,
93
- );
94
-
95
- const bulkActionsToggle = wrapper.find(PageHeaderAction).first();
96
- bulkActionsToggle.simulate('click');
97
- expect(spy).toHaveBeenCalledTimes(1);
98
- expect(spy).toHaveBeenCalledWith(true);
99
- });
100
-
101
- it(`bulk actions should not be disabled by default`, () => {
102
- const spy = jest.fn();
103
-
104
- const wrapper = shallow(
105
- <PageHeader
106
- bulkActions={defaultbulkActions}
107
- onBulkActionsToggled={spy}
108
- />,
109
- );
110
-
111
- const bulkActions = wrapper.find(PageHeaderBulkActions);
112
-
113
- expect(bulkActions.prop('bulkActionsDisabled')).toBe(false);
52
+ it(`renders actions groups`, () => {
53
+ const actions: PageHeaderActionItemProps[] = [
54
+ {
55
+ label: 'Bulk Actions',
56
+ kind: 'group',
57
+ actions: defaultbulkActions,
58
+ },
59
+ ];
60
+ const wrapper = shallow(<PageHeader actions={actions} />);
61
+
62
+ const action = wrapper.find(PageHeaderActionsGroup);
63
+ expect(action.exists()).toBe(true);
114
64
  });
115
65
 
116
- it(`disables bulk actions if 'bulkActionsDisabled' prop is set to true`, () => {
117
- const spy = jest.fn();
66
+ it('renders spacers', () => {
67
+ const actions: PageHeaderActionItemProps[] = [
68
+ {
69
+ kind: 'spacer',
70
+ },
71
+ ];
72
+ const wrapper = shallow(<PageHeader actions={actions} />);
118
73
 
119
- const wrapper = shallow(
120
- <PageHeader
121
- bulkActions={defaultbulkActions}
122
- onBulkActionsToggled={spy}
123
- bulkActionsDisabled={true}
124
- />,
125
- );
126
-
127
- const bulkActions = wrapper.find(PageHeaderBulkActions);
128
-
129
- expect(bulkActions.prop('bulkActionsDisabled')).toBe(true);
74
+ const spacer = wrapper.find('.spacer');
75
+ expect(spacer.exists()).toBe(true);
130
76
  });
131
-
132
- it.todo('calculates the available space needed for bulk actions');
133
-
134
- it.todo('should not calcuate if there are no bulk actions');
135
77
  });