@axinom/mosaic-ui 0.49.0-rc.0 → 0.49.0-rc.10

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 (60) hide show
  1. package/dist/components/DynamicDataList/DynamicDataList.d.ts.map +1 -1
  2. package/dist/components/DynamicDataList/DynamicListRow/DynamicListRow.d.ts.map +1 -1
  3. package/dist/components/Explorer/Explorer.d.ts.map +1 -1
  4. package/dist/components/Filters/Filter/Filter.d.ts +2 -1
  5. package/dist/components/Filters/Filter/Filter.d.ts.map +1 -1
  6. package/dist/components/Filters/SelectionTypes/FreeTextFilter/FreeTextFilter.d.ts +2 -0
  7. package/dist/components/Filters/SelectionTypes/FreeTextFilter/FreeTextFilter.d.ts.map +1 -1
  8. package/dist/components/FormStation/FormStationHeader/FormStationHeader.d.ts.map +1 -1
  9. package/dist/components/List/ListRow/ListRow.d.ts.map +1 -1
  10. package/dist/components/PageHeader/PageHeader.d.ts +9 -2
  11. package/dist/components/PageHeader/PageHeader.d.ts.map +1 -1
  12. package/dist/components/PageHeader/PageHeader.model.d.ts +11 -12
  13. package/dist/components/PageHeader/PageHeader.model.d.ts.map +1 -1
  14. package/dist/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroup.d.ts +35 -0
  15. package/dist/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroup.d.ts.map +1 -0
  16. package/dist/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroupsContext.d.ts +7 -0
  17. package/dist/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroupsContext.d.ts.map +1 -0
  18. package/dist/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroupsContextProvider.d.ts +3 -0
  19. package/dist/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroupsContextProvider.d.ts.map +1 -0
  20. package/dist/components/PageHeader/index.d.ts +1 -1
  21. package/dist/components/PageHeader/index.d.ts.map +1 -1
  22. package/dist/index.es.js +4 -4
  23. package/dist/index.es.js.map +1 -1
  24. package/dist/index.js +4 -4
  25. package/dist/index.js.map +1 -1
  26. package/dist/{components/DynamicDataList/helpers/generateId.d.ts → utils/GenerateId.d.ts} +1 -1
  27. package/dist/utils/GenerateId.d.ts.map +1 -0
  28. package/package.json +4 -4
  29. package/src/components/DynamicDataList/DynamicDataList.spec.tsx +2 -1
  30. package/src/components/DynamicDataList/DynamicDataList.tsx +1 -1
  31. package/src/components/DynamicDataList/DynamicListRow/DynamicListRow.spec.tsx +37 -0
  32. package/src/components/DynamicDataList/DynamicListRow/DynamicListRow.tsx +4 -0
  33. package/src/components/Explorer/Explorer.spec.tsx +26 -16
  34. package/src/components/Explorer/Explorer.tsx +47 -28
  35. package/src/components/Explorer/NavigationExplorer/NavigationExplorer.spec.tsx +2 -2
  36. package/src/components/Explorer/SelectionExplorer/SelectionExplorer.spec.tsx +8 -32
  37. package/src/components/Filters/Filter/Filter.tsx +3 -0
  38. package/src/components/Filters/SelectionTypes/FreeTextFilter/FreeTextFilter.spec.tsx +16 -1
  39. package/src/components/Filters/SelectionTypes/FreeTextFilter/FreeTextFilter.tsx +13 -1
  40. package/src/components/FormStation/FormStationHeader/FormStationHeader.tsx +34 -30
  41. package/src/components/List/ListRow/ListRow.scss +0 -1
  42. package/src/components/List/ListRow/ListRow.spec.tsx +35 -0
  43. package/src/components/List/ListRow/ListRow.tsx +5 -1
  44. package/src/components/PageHeader/PageHeader.model.ts +10 -12
  45. package/src/components/PageHeader/PageHeader.scss +7 -3
  46. package/src/components/PageHeader/PageHeader.spec.tsx +28 -86
  47. package/src/components/PageHeader/PageHeader.stories.tsx +32 -7
  48. package/src/components/PageHeader/PageHeader.tsx +50 -77
  49. package/src/components/PageHeader/{PageHeaderBulkActions/PageHeaderBulkActions.scss → PageHeaderActionsGroup/PageHeaderActionsGroup.scss} +21 -21
  50. package/src/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroup.spec.tsx +105 -0
  51. package/src/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroup.tsx +224 -0
  52. package/src/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroupsContext.ts +13 -0
  53. package/src/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroupsContextProvider.tsx +30 -0
  54. package/src/components/PageHeader/index.ts +1 -1
  55. package/dist/components/DynamicDataList/helpers/generateId.d.ts.map +0 -1
  56. package/dist/components/PageHeader/PageHeaderBulkActions/PageHeaderBulkActions.d.ts +0 -22
  57. package/dist/components/PageHeader/PageHeaderBulkActions/PageHeaderBulkActions.d.ts.map +0 -1
  58. package/src/components/PageHeader/PageHeaderBulkActions/PageHeaderBulkActions.spec.tsx +0 -369
  59. package/src/components/PageHeader/PageHeaderBulkActions/PageHeaderBulkActions.tsx +0 -188
  60. /package/src/{components/DynamicDataList/helpers/generateId.ts → utils/GenerateId.ts} +0 -0
@@ -212,7 +212,11 @@ export const ListRow = <T extends Data>({
212
212
  column.tooltip !== false ? getTooltipText(columnData) : undefined
213
213
  }
214
214
  data-test-id={`list-entry-property:${column.propertyName as string}`}
215
- style={{ justifySelf: column.horizontalColumnAlign }}
215
+ style={{
216
+ justifySelf: column.horizontalColumnAlign, // Horizontal alignment based on column config
217
+ alignSelf: verticalTextAlign, // Vertical alignment based on props
218
+ textAlign: horizontalTextAlign, // Additional text alignment inside the cell
219
+ }}
216
220
  >
217
221
  {columnData}
218
222
  </div>
@@ -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
  });
@@ -2,21 +2,24 @@ import { action } from '@storybook/addon-actions';
2
2
  import { Meta, StoryObj } from '@storybook/react';
3
3
  import { IconName } from '../Icons';
4
4
  import { PageHeader } from './PageHeader';
5
+ import { PageHeaderActionItemProps } from './PageHeader.model';
5
6
  import {
6
7
  PageHeaderActionProps,
7
8
  PageHeaderActionType,
8
9
  } from './PageHeaderAction';
9
10
  import {} from './PageHeaderAction/PageHeaderAction';
10
11
 
11
- const headerActions: PageHeaderActionProps[] = [
12
+ const headerActions: PageHeaderActionItemProps[] = [
12
13
  {
13
14
  label: 'Undo',
14
15
  icon: IconName.Undo,
16
+ kind: 'action',
15
17
  onClick: action('onActionSelected'),
16
18
  },
17
19
  {
18
20
  label: 'Cancel',
19
21
  icon: IconName.X,
22
+ kind: 'action',
20
23
  onClick: action('onActionSelected'),
21
24
  },
22
25
  ];
@@ -101,7 +104,7 @@ export const Actions: StoryObj<typeof PageHeader> = {
101
104
  },
102
105
  };
103
106
 
104
- export const BulkActions: StoryObj<typeof PageHeader> = {
107
+ export const ActionsGroup: StoryObj<typeof PageHeader> = {
105
108
  parameters: {
106
109
  docs: {
107
110
  description: {
@@ -113,13 +116,19 @@ export const BulkActions: StoryObj<typeof PageHeader> = {
113
116
  args: {
114
117
  title: 'Title',
115
118
  subtitle: 'Subtitle',
116
- bulkActions: bulkHeaderActions,
117
- openBulkActionsOnStart: false,
119
+ actions: [
120
+ {
121
+ label: 'Bulk Actions',
122
+ icon: IconName.Bulk,
123
+ kind: 'group',
124
+ actions: bulkHeaderActions,
125
+ },
126
+ ],
118
127
  },
119
128
  };
120
129
 
121
130
  export const All: StoryObj<typeof PageHeader> = {
122
- name: 'Titles, Bulk Actions, & Actions',
131
+ name: 'Titles, Actions, & Actions Groups',
123
132
  parameters: {
124
133
  docs: {
125
134
  description: {
@@ -131,7 +140,23 @@ export const All: StoryObj<typeof PageHeader> = {
131
140
  args: {
132
141
  title: 'Title',
133
142
  subtitle: 'Subtitle',
134
- actions: headerActions,
135
- bulkActions: bulkHeaderActions,
143
+ actions: [
144
+ ...headerActions,
145
+ { kind: 'spacer' },
146
+ {
147
+ label: 'Bulk Actions',
148
+ icon: IconName.Bulk,
149
+ kind: 'group',
150
+ actions: bulkHeaderActions,
151
+ onActionsGroupToggled: action('onBulkActions1Toggled'),
152
+ },
153
+ {
154
+ label: 'Bulk Actions 2',
155
+ icon: IconName.Bulk,
156
+ kind: 'group',
157
+ actions: [bulkHeaderActions[0]],
158
+ onActionsGroupToggled: action('onBulkActions2Toggled'),
159
+ },
160
+ ],
136
161
  },
137
162
  };
@@ -1,90 +1,57 @@
1
1
  import clsx from 'clsx';
2
- import React, { useEffect, useState } from 'react';
3
- import { noop } from '../../helpers/utils';
2
+ import React from 'react';
4
3
  import { useTabTitle } from '../../hooks/useTabTitle/useTabTitle';
5
4
  import { useWindowSize } from '../../hooks/useWindowSize/useWindowSize';
6
5
  import { PageHeaderProps } from './PageHeader.model';
7
6
  import classes from './PageHeader.scss';
7
+ import { PageHeaderActionProps } from './PageHeaderAction';
8
8
  import { PageHeaderAction } from './PageHeaderAction/PageHeaderAction';
9
- import { PageHeaderBulkActions } from './PageHeaderBulkActions/PageHeaderBulkActions';
9
+ import { PageHeaderActionsGroup } from './PageHeaderActionsGroup/PageHeaderActionsGroup';
10
+ import { PageHeaderActionsGroupContextProvider } from './PageHeaderActionsGroup/PageHeaderActionsGroupsContextProvider';
10
11
 
11
12
  /**
12
- * Primary header for stations. Accepts a title, subtitle, actions, and bulk actions.
13
+ * Primary header for stations. Accepts a title, subtitle, actions, and actions groups.
13
14
  * @example
14
- * <PageHeader title="title" subtitle="subtitle" />
15
+ * <PageHeader title="title" subtitle="subtitle" actions={[
16
+ * { label: 'Undo', icon: IconName.Undo, kind: 'action', onClick: onActionSelected },
17
+ * { label: 'Cancel', icon: IconName.X, kind: 'action' onClick: onActionSelected },
18
+ * { kind: 'spacer' },
19
+ * { label: 'Actions Group', kind: 'group', actions: [
20
+ * { label: 'Action 1', actionType: PageHeaderActionType.Context, icon: IconName.Delete, confirmationMode: 'Advanced', onClick: onActionSelected },
21
+ * ]}
22
+ * ]} />
15
23
  */
16
24
  export const PageHeader: React.FC<PageHeaderProps> = ({
17
25
  title = '',
18
26
  subtitle = '',
19
27
  actions = [],
20
- bulkActions = [],
21
- bulkActionsDisabled = false,
22
- openBulkActionsOnStart = false,
23
- onBulkActionsToggled = noop,
24
28
  className = '',
25
29
  setTabTitle = true,
26
30
  }) => {
27
- const [containerScrollWidth, setContainerScrollWidth] = useState<number>(0);
28
- const [childrenScrollWidth, setChildrenScrollWidth] = useState<number>(0);
29
- const [availableActionSpace, setAvailableActionSpace] = useState<number>(0);
30
- const ActionsWidth = 120;
31
- const { width } = useWindowSize();
32
-
33
- // Order of this useEffect hook is important
34
- useEffect(() => {
35
- setContainerScrollWidth(width);
36
- }, [width]);
37
-
38
- const actionsRef = (node: HTMLDivElement): void => {
39
- if (node !== null) {
40
- setChildrenScrollWidth(node.scrollWidth);
41
- }
42
- };
43
-
44
31
  useTabTitle(title, setTabTitle);
32
+ const { width } = useWindowSize();
33
+ const containerRef = React.useRef<HTMLDivElement>(null);
45
34
 
46
- useEffect(() => {
47
- // only perform calculation if there are bulkActions
48
- if (bulkActions.length > 0) {
49
- const minimumTitleWidth = width >= 1920 ? 510 : 120;
50
- const availableWidth: number =
51
- containerScrollWidth - (minimumTitleWidth + childrenScrollWidth);
35
+ const [availableActionSpace, setAvailableActionSpace] =
36
+ React.useState<number>(0);
52
37
 
53
- const bulkActionSpace = 1;
54
- const moreActionSpace = 1;
38
+ React.useEffect(() => {
39
+ if (containerRef.current) {
40
+ // Use up to 75% of the container width for actions
41
+ const maxActionsWidth = containerRef.current.clientWidth * 0.75;
55
42
 
56
- // calculates the number of bulk action spaces available
57
- let currentAvailableActionSpace: number = Math.floor(
58
- availableWidth / ActionsWidth - bulkActionSpace,
43
+ // Each action is 120px wide
44
+ setAvailableActionSpace(
45
+ Math.floor(maxActionsWidth / 120 - actions.length),
59
46
  );
60
-
61
- // determines if the 'more' action will take up an action slot
62
- if (bulkActions.length > currentAvailableActionSpace) {
63
- currentAvailableActionSpace -= moreActionSpace;
64
- }
65
-
66
- // prevents current available space from going negative
67
- if (currentAvailableActionSpace < 0) {
68
- currentAvailableActionSpace = 0;
69
- }
70
-
71
- // update available action space if the currentAvailableActionSpace has changed
72
- if (currentAvailableActionSpace !== availableActionSpace) {
73
- setAvailableActionSpace(currentAvailableActionSpace);
74
- }
75
47
  }
76
- }, [
77
- bulkActions,
78
- availableActionSpace,
79
- childrenScrollWidth,
80
- containerScrollWidth,
81
- width,
82
- ]);
48
+ }, [width, actions.length]);
83
49
 
84
50
  return (
85
51
  <div
86
52
  className={clsx(classes.container, 'page-header-container', className)}
87
53
  data-test-id="page-header"
54
+ ref={containerRef}
88
55
  >
89
56
  <div className={clsx(classes.titles)}>
90
57
  <div className={clsx(classes.title)} data-test-id="page-header-title">
@@ -98,24 +65,30 @@ export const PageHeader: React.FC<PageHeaderProps> = ({
98
65
  {subtitle}
99
66
  </div>
100
67
  </div>
101
- {bulkActions.length > 0 && (
102
- <PageHeaderBulkActions
103
- availableActionSpace={availableActionSpace}
104
- actions={bulkActions}
105
- openBulkActionsOnStart={openBulkActionsOnStart}
106
- onBulkActionsToggled={onBulkActionsToggled}
107
- bulkActionsDisabled={bulkActionsDisabled}
108
- />
109
- )}
110
- <div
111
- className={clsx(classes.actions)}
112
- style={{ marginLeft: actions.length > 0 ? '10px' : undefined }}
113
- ref={actionsRef}
114
- data-test-id="page-header-actions"
115
- >
116
- {actions.map((action, index) => {
117
- return <PageHeaderAction key={index} {...action} />;
118
- })}
68
+ <div className={classes.actions} data-test-id="page-header-actions">
69
+ <PageHeaderActionsGroupContextProvider>
70
+ {actions.map((action, index) => {
71
+ switch (action.kind) {
72
+ case 'group':
73
+ return (
74
+ <PageHeaderActionsGroup
75
+ key={index}
76
+ {...action}
77
+ availableActionSpace={availableActionSpace}
78
+ />
79
+ );
80
+ case 'spacer':
81
+ return <div key={index} className={classes.spacer} />;
82
+ case 'action':
83
+ return (
84
+ <PageHeaderAction
85
+ key={index}
86
+ {...(action as PageHeaderActionProps)}
87
+ />
88
+ );
89
+ }
90
+ })}
91
+ </PageHeaderActionsGroupContextProvider>
119
92
  </div>
120
93
  </div>
121
94
  );
@@ -2,36 +2,36 @@
2
2
 
3
3
  .container {
4
4
  display: grid;
5
- grid-template-rows: 1fr;
6
- grid-auto-flow: column;
5
+ grid-template-rows: $page-header-height 1fr;
6
+ grid-template-columns: max-content 1fr;
7
7
  grid-gap: 1px;
8
8
  justify-content: end;
9
+ width: max-content;
9
10
 
10
- .hasMore {
11
- width: 120px;
11
+ .actions {
12
12
  display: grid;
13
- grid-template-columns: 1fr;
14
- grid-template-rows: 1fr;
15
-
16
- position: relative;
13
+ grid-auto-flow: column;
14
+ grid-gap: 1px;
15
+ transition: max-width 200ms linear, opacity 150ms linear;
16
+ overflow: hidden;
17
+ }
17
18
 
18
- .dropDownList {
19
- width: 360px;
20
- display: grid;
21
- grid-template-columns: 1fr;
22
- grid-auto-rows: 60px;
23
- grid-gap: 1px;
19
+ .dropDownList {
20
+ width: 100%;
21
+ max-width: 360px;
22
+ display: grid;
23
+ grid-template-columns: 1fr;
24
+ grid-auto-rows: 60px;
25
+ grid-gap: 1px;
24
26
 
25
- border-top: 2px solid white;
27
+ border-top: 2px solid white;
26
28
 
27
- position: absolute;
28
- top: $page-header-height;
29
- right: 0px;
29
+ grid-column: 1 / span 2;
30
+ place-self: end;
30
31
 
31
- background-color: white;
32
+ background-color: white;
32
33
 
33
- z-index: 2;
34
- }
34
+ z-index: 2;
35
35
  }
36
36
  }
37
37
 
@@ -0,0 +1,105 @@
1
+ import { mount, shallow } from 'enzyme';
2
+ import React from 'react';
3
+ import { noop } from '../../../helpers/utils';
4
+ import { PageHeaderAction } from '../PageHeaderAction/PageHeaderAction';
5
+ import {
6
+ PageHeaderActionProps,
7
+ PageHeaderActionType,
8
+ } from '../PageHeaderAction/PageHeaderAction.model';
9
+ import {
10
+ PageHeaderActionsGroup,
11
+ PageHeaderActionsGroupProps,
12
+ } from './PageHeaderActionsGroup';
13
+
14
+ jest.mock('../../../utils/GenerateId', () => ({
15
+ uuid: jest.fn().mockReturnValue('test-uuid'),
16
+ }));
17
+
18
+ const defaultActions: PageHeaderActionProps[] = [
19
+ {
20
+ label: 'Group Action 1',
21
+ onClick: noop,
22
+ },
23
+ {
24
+ label: 'Group Action 2',
25
+ onClick: noop,
26
+ },
27
+ {
28
+ label: 'Group Action 3',
29
+ onClick: noop,
30
+ },
31
+ {
32
+ label: 'Group Action 4',
33
+ onClick: noop,
34
+ },
35
+ ];
36
+
37
+ const defaultProps: PageHeaderActionsGroupProps = {
38
+ label: 'Group Actions',
39
+ actions: defaultActions,
40
+ };
41
+
42
+ describe('PageHeaderActionsGroup', () => {
43
+ it('renders the component without crashing', () => {
44
+ const wrapper = shallow(<PageHeaderActionsGroup {...defaultProps} />);
45
+ expect(wrapper).toBeTruthy();
46
+ });
47
+
48
+ it(`'Group Actions' has the 'Context' actionType when closed and 'Active' actionType when open`, () => {
49
+ const wrapper = mount(<PageHeaderActionsGroup {...defaultProps} />);
50
+ let groupActionsToggle = wrapper.find(PageHeaderAction).first();
51
+ // let action = wrapper.find(PageHeaderAction);
52
+
53
+ expect(groupActionsToggle.prop('actionType')).toBe(
54
+ PageHeaderActionType.Context,
55
+ );
56
+
57
+ groupActionsToggle.simulate('click');
58
+
59
+ groupActionsToggle = wrapper.find(PageHeaderAction).first();
60
+
61
+ expect(groupActionsToggle.prop('actionType')).toBe(
62
+ PageHeaderActionType.Active,
63
+ );
64
+ });
65
+
66
+ it(`renders all actions when 'Group Actions' is selected and there is enough available action slots`, () => {
67
+ const wrapper = mount(
68
+ <PageHeaderActionsGroup {...defaultProps} availableActionSpace={5} />,
69
+ );
70
+ const groupActionsToggle = wrapper.find(PageHeaderAction).first();
71
+ let actions = wrapper.find(PageHeaderAction);
72
+
73
+ groupActionsToggle.simulate('click');
74
+ actions = wrapper.find(PageHeaderAction);
75
+ expect(actions).toHaveLength(5);
76
+ });
77
+
78
+ it(`raises onActionsGroupToggled`, () => {
79
+ const groupActionSpy = jest.fn();
80
+ const wrapper = mount(
81
+ <PageHeaderActionsGroup
82
+ {...defaultProps}
83
+ onActionsGroupToggled={groupActionSpy}
84
+ />,
85
+ );
86
+ const groupActionsToggle = wrapper.find(PageHeaderAction).first();
87
+ groupActionsToggle.simulate('click');
88
+ expect(groupActionSpy).toHaveBeenCalledTimes(1);
89
+ expect(groupActionSpy).toHaveBeenCalledWith(true);
90
+ });
91
+
92
+ it(`renders 'Group Actions' and 'More Actions' if openActionsGroupOnStart is set to true and there isn't enough available space`, () => {
93
+ const wrapper = mount(
94
+ <PageHeaderActionsGroup
95
+ {...defaultProps}
96
+ openActionsGroupOnStart={true}
97
+ availableActionSpace={3}
98
+ />,
99
+ );
100
+
101
+ const actions = wrapper.find(PageHeaderAction);
102
+
103
+ expect(actions).toHaveLength(4);
104
+ });
105
+ });