@axinom/mosaic-ui 0.32.0-rc.1 → 0.32.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.
- package/dist/components/Actions/Action/Action.d.ts.map +1 -1
- package/dist/components/Actions/Actions.models.d.ts +4 -16
- package/dist/components/Actions/Actions.models.d.ts.map +1 -1
- package/dist/components/Buttons/Button/Button.d.ts +9 -10
- package/dist/components/Buttons/Button/Button.d.ts.map +1 -1
- package/dist/components/Buttons/Button/Button.model.d.ts +21 -0
- package/dist/components/Buttons/Button/Button.model.d.ts.map +1 -0
- package/dist/components/Buttons/Button/index.d.ts +3 -0
- package/dist/components/Buttons/Button/index.d.ts.map +1 -0
- package/dist/components/Buttons/Button.model.d.ts +69 -7
- package/dist/components/Buttons/Button.model.d.ts.map +1 -1
- package/dist/components/Buttons/CompositeButton/CompositeButton.d.ts +5 -14
- package/dist/components/Buttons/CompositeButton/CompositeButton.d.ts.map +1 -1
- package/dist/components/Buttons/CompositeButton/CompositeButton.model.d.ts +20 -0
- package/dist/components/Buttons/CompositeButton/CompositeButton.model.d.ts.map +1 -0
- package/dist/components/Buttons/CompositeButton/index.d.ts +3 -0
- package/dist/components/Buttons/CompositeButton/index.d.ts.map +1 -0
- package/dist/components/Buttons/TextButton/TextButton.d.ts +5 -9
- package/dist/components/Buttons/TextButton/TextButton.d.ts.map +1 -1
- package/dist/components/Buttons/TextButton/TextButton.model.d.ts +18 -0
- package/dist/components/Buttons/TextButton/TextButton.model.d.ts.map +1 -0
- package/dist/components/Buttons/TextButton/index.d.ts +3 -0
- package/dist/components/Buttons/TextButton/index.d.ts.map +1 -0
- package/dist/components/Buttons/index.d.ts +3 -3
- package/dist/components/Buttons/index.d.ts.map +1 -1
- package/dist/components/Explorer/Explorer.d.ts.map +1 -1
- package/dist/components/Explorer/Explorer.model.d.ts +2 -2
- package/dist/components/Explorer/Explorer.model.d.ts.map +1 -1
- package/dist/components/Explorer/NavigationExplorer/NavigationExplorer.d.ts +13 -3
- package/dist/components/Explorer/NavigationExplorer/NavigationExplorer.d.ts.map +1 -1
- package/dist/components/FormElements/ToggleButton/ToggleButton.d.ts +2 -2
- package/dist/components/FormElements/ToggleButton/ToggleButton.d.ts.map +1 -1
- package/dist/components/List/List.d.ts +1 -1
- package/dist/components/List/List.d.ts.map +1 -1
- package/dist/components/List/ListRow/ListRow.d.ts.map +1 -1
- package/dist/components/PageHeader/PageHeader.d.ts +1 -22
- package/dist/components/PageHeader/PageHeader.d.ts.map +1 -1
- package/dist/components/PageHeader/PageHeader.model.d.ts +23 -0
- package/dist/components/PageHeader/PageHeader.model.d.ts.map +1 -0
- package/dist/components/PageHeader/PageHeaderAction/PageHeaderAction.d.ts +20 -33
- package/dist/components/PageHeader/PageHeaderAction/PageHeaderAction.d.ts.map +1 -1
- package/dist/components/PageHeader/PageHeaderAction/PageHeaderAction.model.d.ts +47 -0
- package/dist/components/PageHeader/PageHeaderAction/PageHeaderAction.model.d.ts.map +1 -0
- package/dist/components/PageHeader/PageHeaderAction/index.d.ts +3 -0
- package/dist/components/PageHeader/PageHeaderAction/index.d.ts.map +1 -0
- package/dist/components/PageHeader/PageHeaderBulkActions/PageHeaderBulkActions.d.ts +2 -2
- package/dist/components/PageHeader/PageHeaderBulkActions/PageHeaderBulkActions.d.ts.map +1 -1
- package/dist/components/PageHeader/index.d.ts +3 -2
- package/dist/components/PageHeader/index.d.ts.map +1 -1
- package/dist/components/models.d.ts +22 -0
- package/dist/components/models.d.ts.map +1 -1
- package/dist/index.es.js +3 -3
- package/dist/index.es.js.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/components/Actions/Action/Action.spec.tsx +14 -0
- package/src/components/Actions/Action/Action.tsx +5 -2
- package/src/components/Actions/Actions.models.ts +4 -23
- package/src/components/Buttons/Button/Button.model.ts +30 -0
- package/src/components/Buttons/Button/Button.scss +3 -1
- package/src/components/Buttons/Button/Button.spec.tsx +254 -83
- package/src/components/Buttons/Button/Button.stories.tsx +20 -0
- package/src/components/Buttons/Button/Button.tsx +103 -32
- package/src/components/Buttons/Button/index.ts +2 -0
- package/src/components/Buttons/Button.model.ts +84 -9
- package/src/components/Buttons/CompositeButton/CompositeButton.model.ts +32 -0
- package/src/components/Buttons/CompositeButton/CompositeButton.scss +6 -1
- package/src/components/Buttons/CompositeButton/CompositeButton.spec.tsx +277 -89
- package/src/components/Buttons/CompositeButton/CompositeButton.stories.tsx +20 -0
- package/src/components/Buttons/CompositeButton/CompositeButton.tsx +94 -30
- package/src/components/Buttons/CompositeButton/index.ts +2 -0
- package/src/components/Buttons/TextButton/TextButton.model.ts +27 -0
- package/src/components/Buttons/TextButton/TextButton.scss +3 -1
- package/src/components/Buttons/TextButton/TextButton.spec.tsx +198 -87
- package/src/components/Buttons/TextButton/TextButton.stories.tsx +20 -0
- package/src/components/Buttons/TextButton/TextButton.tsx +74 -20
- package/src/components/Buttons/TextButton/index.ts +2 -0
- package/src/components/Buttons/index.ts +3 -6
- package/src/components/Explorer/Explorer.model.ts +2 -2
- package/src/components/Explorer/Explorer.tsx +21 -16
- package/src/components/Explorer/NavigationExplorer/NavigationExplorer.tsx +32 -11
- package/src/components/FormElements/CustomTags/CustomTags.spec.tsx +26 -16
- package/src/components/FormElements/ToggleButton/ToggleButton.tsx +2 -2
- package/src/components/List/List.spec.tsx +23 -0
- package/src/components/List/List.stories.tsx +8 -0
- package/src/components/List/List.tsx +15 -3
- package/src/components/List/ListRow/ListRow.tsx +18 -13
- package/src/components/PageHeader/PageHeader.model.ts +23 -0
- package/src/components/PageHeader/PageHeader.stories.tsx +2 -1
- package/src/components/PageHeader/PageHeader.tsx +2 -26
- package/src/components/PageHeader/PageHeaderAction/PageHeaderAction.model.ts +60 -0
- package/src/components/PageHeader/PageHeaderAction/PageHeaderAction.spec.tsx +549 -382
- package/src/components/PageHeader/PageHeaderAction/PageHeaderAction.stories.tsx +12 -1
- package/src/components/PageHeader/PageHeaderAction/PageHeaderAction.tsx +94 -44
- package/src/components/PageHeader/PageHeaderAction/index.ts +2 -0
- package/src/components/PageHeader/PageHeaderBulkActions/PageHeaderBulkActions.spec.tsx +2 -2
- package/src/components/PageHeader/PageHeaderBulkActions/PageHeaderBulkActions.tsx +56 -43
- package/src/components/PageHeader/index.ts +3 -2
- package/src/components/models.ts +30 -0
|
@@ -1,135 +1,246 @@
|
|
|
1
1
|
import { mount, shallow } from 'enzyme';
|
|
2
2
|
import React from 'react';
|
|
3
|
+
import { Link, BrowserRouter as Router } from 'react-router-dom';
|
|
3
4
|
import { ButtonContext } from '../Button.model';
|
|
4
5
|
import { TextButton } from './TextButton';
|
|
5
6
|
|
|
6
|
-
describe('
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
describe('TextButton', () => {
|
|
8
|
+
describe('TextContextButton', () => {
|
|
9
|
+
it('renders the component without crashing', () => {
|
|
10
|
+
const wrapper = shallow(<TextButton />);
|
|
9
11
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
+
expect(wrapper).toBeTruthy();
|
|
13
|
+
});
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
it('raises the onButtonClicked event', () => {
|
|
16
|
+
const spy = jest.fn();
|
|
17
|
+
const wrapper = mount(<TextButton onButtonClicked={spy} />);
|
|
16
18
|
|
|
17
|
-
|
|
19
|
+
wrapper.simulate('click');
|
|
18
20
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
+
expect(spy).toHaveBeenCalledTimes(1);
|
|
22
|
+
});
|
|
21
23
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
it('creates a class based off of the className prop', () => {
|
|
25
|
+
const mockClassName = 'test-class';
|
|
26
|
+
const wrapper = mount(<TextButton className={mockClassName} />);
|
|
25
27
|
|
|
26
|
-
|
|
28
|
+
const button = wrapper.find('button');
|
|
27
29
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
expect(button.hasClass(mockClassName)).toBe(true);
|
|
31
|
+
});
|
|
30
32
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
+
it(`button 'type' must be 'button' by default`, () => {
|
|
34
|
+
const wrapper = mount(<TextButton />);
|
|
33
35
|
|
|
34
|
-
|
|
36
|
+
const buttonType = wrapper.find('button').prop('type');
|
|
35
37
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
+
expect(buttonType).toBe('button');
|
|
39
|
+
});
|
|
38
40
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
it('accepts type html attribute and width/height styles', () => {
|
|
42
|
+
const mockType = 'submit';
|
|
43
|
+
const mockHeight = '75px';
|
|
44
|
+
const mockWidth = '80px';
|
|
43
45
|
|
|
44
|
-
|
|
46
|
+
const wrapper = mount(<TextButton />);
|
|
45
47
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
let buttonType = wrapper.find('button').prop('type');
|
|
49
|
+
let buttonStyles = wrapper
|
|
50
|
+
.find('button')
|
|
51
|
+
.prop('style') as React.CSSProperties;
|
|
50
52
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
expect(buttonType).toBe('button');
|
|
54
|
+
expect(buttonStyles.height).toBeUndefined();
|
|
55
|
+
expect(buttonStyles.width).toBeUndefined();
|
|
54
56
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
+
wrapper.setProps({
|
|
58
|
+
type: mockType,
|
|
59
|
+
height: mockHeight,
|
|
60
|
+
width: mockWidth,
|
|
61
|
+
});
|
|
62
|
+
wrapper.update();
|
|
57
63
|
|
|
58
|
-
|
|
59
|
-
|
|
64
|
+
buttonType = wrapper.find('button').prop('type');
|
|
65
|
+
buttonStyles = wrapper
|
|
66
|
+
.find('button')
|
|
67
|
+
.prop('style') as React.CSSProperties;
|
|
60
68
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
69
|
+
expect(buttonType).toBe(mockType);
|
|
70
|
+
expect(buttonStyles.height).toBe(mockHeight);
|
|
71
|
+
expect(buttonStyles.width).toBe(mockWidth);
|
|
72
|
+
});
|
|
65
73
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
74
|
+
it('allows the button to be enabled by default', () => {
|
|
75
|
+
const spy = jest.fn();
|
|
76
|
+
const wrapper = mount(<TextButton onButtonClicked={spy} />);
|
|
69
77
|
|
|
70
|
-
|
|
78
|
+
const button = wrapper.find('button');
|
|
71
79
|
|
|
72
|
-
|
|
80
|
+
wrapper.simulate('click');
|
|
73
81
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
82
|
+
expect(button.prop('disabled')).toBe(false);
|
|
83
|
+
expect(spy).toHaveBeenCalledTimes(1);
|
|
84
|
+
});
|
|
77
85
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
86
|
+
it('allows button to be disabled', () => {
|
|
87
|
+
const spy = jest.fn();
|
|
88
|
+
const wrapper = mount(
|
|
89
|
+
<TextButton disabled={true} onButtonClicked={spy} />,
|
|
90
|
+
);
|
|
81
91
|
|
|
82
|
-
|
|
92
|
+
const button = wrapper.find('button');
|
|
83
93
|
|
|
84
|
-
|
|
94
|
+
wrapper.simulate('click');
|
|
85
95
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
96
|
+
expect(button.prop('disabled')).toBe(true);
|
|
97
|
+
expect(spy).not.toHaveBeenCalled();
|
|
98
|
+
});
|
|
89
99
|
|
|
90
|
-
|
|
91
|
-
|
|
100
|
+
it('default should have a context class', () => {
|
|
101
|
+
const wrapper = mount(<TextButton />);
|
|
92
102
|
|
|
93
|
-
|
|
103
|
+
const button = wrapper.find('button');
|
|
94
104
|
|
|
95
|
-
|
|
96
|
-
|
|
105
|
+
expect(button.hasClass('context')).toBe(true);
|
|
106
|
+
});
|
|
97
107
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
108
|
+
it('context button type should have a context class', () => {
|
|
109
|
+
const wrapper = mount(
|
|
110
|
+
<TextButton buttonContext={ButtonContext.Context} />,
|
|
111
|
+
);
|
|
102
112
|
|
|
103
|
-
|
|
113
|
+
const button = wrapper.find('button');
|
|
104
114
|
|
|
105
|
-
|
|
106
|
-
|
|
115
|
+
expect(button.hasClass('context')).toBe(true);
|
|
116
|
+
});
|
|
107
117
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
118
|
+
it('active button type should have a active class', () => {
|
|
119
|
+
const wrapper = mount(
|
|
120
|
+
<TextButton buttonContext={ButtonContext.Active} />,
|
|
121
|
+
);
|
|
112
122
|
|
|
113
|
-
|
|
123
|
+
const button = wrapper.find('button');
|
|
114
124
|
|
|
115
|
-
|
|
116
|
-
|
|
125
|
+
expect(button.hasClass('active')).toBe(true);
|
|
126
|
+
});
|
|
117
127
|
|
|
118
|
-
|
|
119
|
-
|
|
128
|
+
it(`renders value from 'text' prop`, () => {
|
|
129
|
+
const mockText = 'mock-text';
|
|
120
130
|
|
|
121
|
-
|
|
131
|
+
const wrapper = mount(<TextButton text={mockText} />);
|
|
122
132
|
|
|
123
|
-
|
|
133
|
+
const button = wrapper.find('button');
|
|
124
134
|
|
|
125
|
-
|
|
126
|
-
|
|
135
|
+
expect(button.text()).toBe(mockText);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it(`defaults to an empty string is 'text' prop is not set`, () => {
|
|
139
|
+
const wrapper = mount(<TextButton />);
|
|
127
140
|
|
|
128
|
-
|
|
129
|
-
const wrapper = shallow(<TextButton />);
|
|
141
|
+
const button = wrapper.find('button');
|
|
130
142
|
|
|
131
|
-
|
|
143
|
+
expect(button.text()).toBe('');
|
|
144
|
+
});
|
|
145
|
+
});
|
|
132
146
|
|
|
133
|
-
|
|
147
|
+
describe('TextNavigationButton', () => {
|
|
148
|
+
it('renders the component without crashing', () => {
|
|
149
|
+
const wrapper = shallow(<TextButton path={'/'} />);
|
|
150
|
+
expect(wrapper).toBeTruthy();
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it('renders as a navigation button when path prop is defined', () => {
|
|
154
|
+
const mockPath = '/home';
|
|
155
|
+
const wrapper = mount(
|
|
156
|
+
<Router>
|
|
157
|
+
<TextButton path={mockPath} />
|
|
158
|
+
</Router>,
|
|
159
|
+
);
|
|
160
|
+
const link = wrapper.find(Link);
|
|
161
|
+
expect(link).toHaveLength(1);
|
|
162
|
+
expect(link.prop('to')).toBe(mockPath);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it('does not open link in new tab by default', () => {
|
|
166
|
+
const mockPath = '/home';
|
|
167
|
+
const wrapper = mount(
|
|
168
|
+
<Router>
|
|
169
|
+
<TextButton path={mockPath} />
|
|
170
|
+
</Router>,
|
|
171
|
+
);
|
|
172
|
+
const link = wrapper.find(Link);
|
|
173
|
+
expect(link.prop('target')).toBeUndefined();
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it('opens link in new tab when openInNewTab prop set to true', () => {
|
|
177
|
+
const mockPath = '/home';
|
|
178
|
+
const wrapper = mount(
|
|
179
|
+
<Router>
|
|
180
|
+
<TextButton path={mockPath} openInNewTab={true} />
|
|
181
|
+
</Router>,
|
|
182
|
+
);
|
|
183
|
+
const link = wrapper.find(Link);
|
|
184
|
+
expect(link.prop('target')).toBe('_blank');
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it('creates a class based on the className prop', () => {
|
|
188
|
+
const mockClassName = 'test-class';
|
|
189
|
+
const wrapper = mount(
|
|
190
|
+
<Router>
|
|
191
|
+
<TextButton path={'/test'} className={mockClassName} />,
|
|
192
|
+
</Router>,
|
|
193
|
+
);
|
|
194
|
+
const link = wrapper.find(Link);
|
|
195
|
+
expect(link.hasClass(mockClassName)).toBe(true);
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it('accepts width and height styles', () => {
|
|
199
|
+
const mockHeight = '75px';
|
|
200
|
+
const mockWidth = '80px';
|
|
201
|
+
const wrapper = mount(
|
|
202
|
+
<Router>
|
|
203
|
+
<TextButton path={'/test'} width={mockWidth} height={mockHeight} />
|
|
204
|
+
</Router>,
|
|
205
|
+
);
|
|
206
|
+
const linkStyles = wrapper
|
|
207
|
+
.find('Link')
|
|
208
|
+
.prop('style') as React.CSSProperties;
|
|
209
|
+
|
|
210
|
+
expect(linkStyles.height).toBe(mockHeight);
|
|
211
|
+
expect(linkStyles.width).toBe(mockWidth);
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it('allows the link to be enabled by default', () => {
|
|
215
|
+
const wrapper = mount(
|
|
216
|
+
<Router>
|
|
217
|
+
<TextButton path={'/test'} />
|
|
218
|
+
</Router>,
|
|
219
|
+
);
|
|
220
|
+
|
|
221
|
+
const link = wrapper.find('Link');
|
|
222
|
+
|
|
223
|
+
expect(link.hasClass('disabled')).toBe(false);
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
it('allows the button to be disabled', () => {
|
|
227
|
+
const wrapper = mount(
|
|
228
|
+
<Router>
|
|
229
|
+
<TextButton path={'/test'} disabled={true} />
|
|
230
|
+
</Router>,
|
|
231
|
+
);
|
|
232
|
+
const link = wrapper.find('Link');
|
|
233
|
+
expect(link.hasClass('disabled')).toBe(true);
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
it('adds `navigation` class for link buttons', () => {
|
|
237
|
+
const wrapper = mount(
|
|
238
|
+
<Router>
|
|
239
|
+
<TextButton path={'/test'} />
|
|
240
|
+
</Router>,
|
|
241
|
+
);
|
|
242
|
+
const link = wrapper.find(Link);
|
|
243
|
+
expect(link.hasClass('navigation')).toBe(true);
|
|
244
|
+
});
|
|
134
245
|
});
|
|
135
246
|
});
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { MemoryRouter } from 'react-router';
|
|
2
4
|
import { enumToObj } from '../../../helpers/storybook';
|
|
3
5
|
import { ButtonContext } from '../Button.model';
|
|
4
6
|
import { TextButton } from './TextButton';
|
|
@@ -21,7 +23,25 @@ const meta: Meta<typeof TextButton> = {
|
|
|
21
23
|
onBlur: {
|
|
22
24
|
control: false,
|
|
23
25
|
},
|
|
26
|
+
width: {
|
|
27
|
+
control: {
|
|
28
|
+
type: 'number',
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
height: {
|
|
32
|
+
control: {
|
|
33
|
+
type: 'number',
|
|
34
|
+
},
|
|
35
|
+
},
|
|
24
36
|
},
|
|
37
|
+
decorators: [
|
|
38
|
+
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
39
|
+
(Story) => (
|
|
40
|
+
<MemoryRouter>
|
|
41
|
+
<Story />
|
|
42
|
+
</MemoryRouter>
|
|
43
|
+
),
|
|
44
|
+
],
|
|
25
45
|
};
|
|
26
46
|
|
|
27
47
|
export default meta;
|
|
@@ -1,24 +1,49 @@
|
|
|
1
1
|
import clsx from 'clsx';
|
|
2
2
|
import React from 'react';
|
|
3
|
+
import { Link } from 'react-router-dom';
|
|
3
4
|
import { noop } from '../../../helpers/utils';
|
|
4
|
-
import {
|
|
5
|
+
import { ButtonContext } from '../Button.model';
|
|
6
|
+
import {
|
|
7
|
+
TextButtonProps,
|
|
8
|
+
TextContextButtonProps,
|
|
9
|
+
TextNavigationButtonProps,
|
|
10
|
+
} from './TextButton.model';
|
|
5
11
|
import classes from './TextButton.scss';
|
|
6
12
|
|
|
7
|
-
export interface TextButtonProps extends BaseButtonOptions {
|
|
8
|
-
/** Button's height (default: '30px') */
|
|
9
|
-
height?: string | number;
|
|
10
|
-
/** Button's width (default: undefined) */
|
|
11
|
-
width?: string | number;
|
|
12
|
-
/** Button text */
|
|
13
|
-
text?: string;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
13
|
/**
|
|
17
14
|
* Button which can render a text string.
|
|
18
15
|
* @example
|
|
16
|
+
* // Rendered as button
|
|
19
17
|
* <TextButton type="button" text="Click me!" />
|
|
18
|
+
*
|
|
19
|
+
* // Rendered as link
|
|
20
|
+
* <TextButton path="/home" text="Click me!" />
|
|
20
21
|
*/
|
|
21
22
|
export const TextButton: React.FC<TextButtonProps> = ({
|
|
23
|
+
className,
|
|
24
|
+
dataTestId = undefined,
|
|
25
|
+
disabled = false,
|
|
26
|
+
height,
|
|
27
|
+
path,
|
|
28
|
+
text = '',
|
|
29
|
+
width,
|
|
30
|
+
openInNewTab,
|
|
31
|
+
...rest
|
|
32
|
+
}) => {
|
|
33
|
+
const commonProps = { className, dataTestId, height, text, width, disabled };
|
|
34
|
+
|
|
35
|
+
return path ? (
|
|
36
|
+
<TextNavigationButton
|
|
37
|
+
{...commonProps}
|
|
38
|
+
path={path}
|
|
39
|
+
openInNewTab={openInNewTab}
|
|
40
|
+
/>
|
|
41
|
+
) : (
|
|
42
|
+
<TextContextButton {...commonProps} {...rest} />
|
|
43
|
+
);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const TextContextButton: React.FC<TextContextButtonProps> = ({
|
|
22
47
|
type = 'button',
|
|
23
48
|
height,
|
|
24
49
|
width,
|
|
@@ -28,28 +53,23 @@ export const TextButton: React.FC<TextButtonProps> = ({
|
|
|
28
53
|
className,
|
|
29
54
|
dataTestId = undefined,
|
|
30
55
|
onButtonClicked = noop,
|
|
31
|
-
}
|
|
32
|
-
const customStyles = {
|
|
33
|
-
height: height,
|
|
34
|
-
width: width,
|
|
35
|
-
} as React.CSSProperties;
|
|
36
|
-
|
|
56
|
+
}) => {
|
|
37
57
|
return (
|
|
38
58
|
<button
|
|
39
59
|
className={clsx(
|
|
40
60
|
classes.container,
|
|
41
|
-
{ [classes.navigation]: buttonContext === ButtonContext.Navigation },
|
|
42
61
|
{
|
|
43
62
|
[classes.context]: buttonContext === ButtonContext.Context,
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
63
|
[classes.active]: buttonContext === ButtonContext.Active,
|
|
47
64
|
},
|
|
48
65
|
'text-button-container',
|
|
49
66
|
className,
|
|
50
67
|
)}
|
|
51
68
|
type={type}
|
|
52
|
-
style={
|
|
69
|
+
style={{
|
|
70
|
+
height,
|
|
71
|
+
width,
|
|
72
|
+
}}
|
|
53
73
|
onClick={onButtonClicked}
|
|
54
74
|
disabled={disabled}
|
|
55
75
|
data-test-id={dataTestId ?? 'text-button'}
|
|
@@ -58,3 +78,37 @@ export const TextButton: React.FC<TextButtonProps> = ({
|
|
|
58
78
|
</button>
|
|
59
79
|
);
|
|
60
80
|
};
|
|
81
|
+
|
|
82
|
+
const TextNavigationButton: React.FC<TextNavigationButtonProps> = ({
|
|
83
|
+
height,
|
|
84
|
+
width,
|
|
85
|
+
disabled = false,
|
|
86
|
+
text = '',
|
|
87
|
+
className,
|
|
88
|
+
dataTestId = undefined,
|
|
89
|
+
path,
|
|
90
|
+
openInNewTab = false,
|
|
91
|
+
}) => {
|
|
92
|
+
return (
|
|
93
|
+
<Link
|
|
94
|
+
to={path}
|
|
95
|
+
className={clsx(
|
|
96
|
+
classes.container,
|
|
97
|
+
classes.navigation,
|
|
98
|
+
{
|
|
99
|
+
[classes.disabled]: disabled,
|
|
100
|
+
},
|
|
101
|
+
'text-button-container',
|
|
102
|
+
className,
|
|
103
|
+
)}
|
|
104
|
+
style={{
|
|
105
|
+
height,
|
|
106
|
+
width,
|
|
107
|
+
}}
|
|
108
|
+
data-test-id={dataTestId ?? 'text-button'}
|
|
109
|
+
target={openInNewTab ? '_blank' : undefined}
|
|
110
|
+
>
|
|
111
|
+
{text}
|
|
112
|
+
</Link>
|
|
113
|
+
);
|
|
114
|
+
};
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
+
export * from './Button';
|
|
1
2
|
export { ButtonContext } from './Button.model';
|
|
2
|
-
export
|
|
3
|
-
export
|
|
4
|
-
CompositeButton,
|
|
5
|
-
CompositeButtonProps,
|
|
6
|
-
} from './CompositeButton/CompositeButton';
|
|
7
|
-
export { TextButton, TextButtonProps } from './TextButton/TextButton';
|
|
3
|
+
export * from './CompositeButton';
|
|
4
|
+
export * from './TextButton';
|
|
@@ -2,7 +2,7 @@ import { Data } from '../../types/data';
|
|
|
2
2
|
import { FilterValues } from '../Filters';
|
|
3
3
|
import { SortData } from '../List';
|
|
4
4
|
import { ErrorType } from '../models';
|
|
5
|
-
import {
|
|
5
|
+
import { PageHeaderJsActionProps } from '../PageHeader/PageHeaderAction/PageHeaderAction.model';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Item selection can have two modes:
|
|
@@ -24,7 +24,7 @@ interface SelectAllSelection<T extends Data> {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
export interface ExplorerBulkAction<T extends Data>
|
|
27
|
-
extends Omit<
|
|
27
|
+
extends Omit<PageHeaderJsActionProps, 'onClick'> {
|
|
28
28
|
/**
|
|
29
29
|
* Callback to emit when a user clicks on the component
|
|
30
30
|
* @param arg ItemSelection details of the bulk action
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import clsx from 'clsx';
|
|
2
2
|
import { LocationDescriptor } from 'history';
|
|
3
3
|
import {
|
|
4
|
-
default as React,
|
|
5
4
|
ForwardedRef,
|
|
5
|
+
default as React,
|
|
6
6
|
useCallback,
|
|
7
7
|
useEffect,
|
|
8
8
|
useState,
|
|
@@ -22,9 +22,11 @@ import {
|
|
|
22
22
|
ListSelectMode,
|
|
23
23
|
SortData,
|
|
24
24
|
} from '../List';
|
|
25
|
-
import { ErrorType } from '../models';
|
|
26
25
|
import { PageHeader, PageHeaderActionProps } from '../PageHeader';
|
|
26
|
+
import { isPageHeaderNavigationAction } from '../PageHeader/PageHeaderAction/PageHeaderAction';
|
|
27
|
+
import { PageHeaderJsActionProps } from '../PageHeader/PageHeaderAction/PageHeaderAction.model';
|
|
27
28
|
import { getState, storeState } from '../Utils/State/GlobalState';
|
|
29
|
+
import { ErrorType } from '../models';
|
|
28
30
|
import {
|
|
29
31
|
ExplorerBulkAction,
|
|
30
32
|
ExplorerDataProvider,
|
|
@@ -141,6 +143,7 @@ export interface ExplorerProps<T extends Data> {
|
|
|
141
143
|
* The expanded state is supplied as an argument
|
|
142
144
|
*/
|
|
143
145
|
onBulkActionsToggled?: (expanded: boolean) => void;
|
|
146
|
+
|
|
144
147
|
/** Provide inline actions which are available through '...' context menu */
|
|
145
148
|
inlineMenuActions?: (data: T) => ActionData[];
|
|
146
149
|
}
|
|
@@ -339,23 +342,25 @@ export const Explorer = React.forwardRef(function Explorer<T extends Data>(
|
|
|
339
342
|
|
|
340
343
|
const pageHeaderActionsHandler = (): PageHeaderActionProps[] => {
|
|
341
344
|
return (actions ?? []).map((action) => {
|
|
342
|
-
return
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
345
|
+
return isPageHeaderNavigationAction(action)
|
|
346
|
+
? action
|
|
347
|
+
: {
|
|
348
|
+
...action,
|
|
349
|
+
onClick: async () => {
|
|
350
|
+
try {
|
|
351
|
+
const result = await action.onClick();
|
|
352
|
+
if (result) {
|
|
353
|
+
setStationMessage(errMsg(result));
|
|
354
|
+
}
|
|
355
|
+
} catch (error) {
|
|
356
|
+
setStationMessage(errMsg(error, errAction));
|
|
357
|
+
}
|
|
358
|
+
},
|
|
359
|
+
};
|
|
355
360
|
});
|
|
356
361
|
};
|
|
357
362
|
|
|
358
|
-
const bulkActionsHandler = ():
|
|
363
|
+
const bulkActionsHandler = (): PageHeaderJsActionProps[] => {
|
|
359
364
|
return (bulkActions ?? []).map((action) => {
|
|
360
365
|
return {
|
|
361
366
|
...action,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { LocationDescriptor } from 'history';
|
|
1
2
|
import React, { ForwardedRef } from 'react';
|
|
2
3
|
import { Data } from '../../../types/data';
|
|
3
4
|
import { IconName } from '../../Icons';
|
|
@@ -10,10 +11,19 @@ export interface NavigationExplorerProps<T extends Data>
|
|
|
10
11
|
ExplorerProps<T>,
|
|
11
12
|
'selectionMode' | 'onBulkActionsToggled' | 'onItemClicked'
|
|
12
13
|
> {
|
|
13
|
-
/**
|
|
14
|
-
|
|
14
|
+
/**
|
|
15
|
+
* - If a `LocationDescriptor` is provided, it will be treated as a path to the station to
|
|
16
|
+
* navigate to, and a link will be generated.
|
|
17
|
+
* - If a `function` is provided, it will be called when the create action is
|
|
18
|
+
* clicked, and a button will be generated.
|
|
19
|
+
*/
|
|
20
|
+
onCreateAction?: (() => void) | LocationDescriptor;
|
|
15
21
|
|
|
16
|
-
/**
|
|
22
|
+
/**
|
|
23
|
+
* Function that calculates the URL to navigate to when a row of data is clicked.
|
|
24
|
+
* - The function should take the item data as input and return the URL string.
|
|
25
|
+
* - Navigation will not occur if bulk actions are open.
|
|
26
|
+
*/
|
|
17
27
|
calculateNavigateUrl?: (item: T) => string;
|
|
18
28
|
}
|
|
19
29
|
|
|
@@ -29,30 +39,41 @@ export interface NavigationExplorerProps<T extends Data>
|
|
|
29
39
|
* calculateNavigateUrl={(rowData => `/details/${rowData.id}`)}
|
|
30
40
|
* />
|
|
31
41
|
*/
|
|
32
|
-
|
|
33
42
|
export const NavigationExplorer = React.forwardRef(function NavigationExplorer<
|
|
34
43
|
T extends Data,
|
|
35
44
|
>(
|
|
36
|
-
|
|
45
|
+
{
|
|
46
|
+
onCreateAction,
|
|
47
|
+
calculateNavigateUrl,
|
|
48
|
+
actions = [],
|
|
49
|
+
...rest
|
|
50
|
+
}: NavigationExplorerProps<T>,
|
|
37
51
|
ref: ForwardedRef<ExplorerDataProviderConnection<T>>,
|
|
38
52
|
): JSX.Element {
|
|
39
|
-
const { onCreateAction, calculateNavigateUrl, actions = [], ...rest } = props;
|
|
40
|
-
|
|
41
53
|
return (
|
|
42
54
|
<Explorer<T>
|
|
43
|
-
ref={ref}
|
|
44
55
|
{...rest}
|
|
56
|
+
ref={ref}
|
|
45
57
|
actions={[
|
|
46
|
-
...
|
|
58
|
+
...actions,
|
|
59
|
+
...(onCreateAction && typeof onCreateAction !== 'function'
|
|
60
|
+
? [
|
|
61
|
+
{
|
|
62
|
+
label: 'New',
|
|
63
|
+
icon: IconName.Plus,
|
|
64
|
+
path: onCreateAction,
|
|
65
|
+
},
|
|
66
|
+
]
|
|
67
|
+
: []),
|
|
68
|
+
...(onCreateAction && typeof onCreateAction === 'function'
|
|
47
69
|
? [
|
|
48
|
-
...actions,
|
|
49
70
|
{
|
|
50
71
|
label: 'New',
|
|
51
72
|
icon: IconName.Plus,
|
|
52
73
|
onClick: onCreateAction,
|
|
53
74
|
},
|
|
54
75
|
]
|
|
55
|
-
: [
|
|
76
|
+
: []),
|
|
56
77
|
]}
|
|
57
78
|
selectionMode={ListSelectMode.None}
|
|
58
79
|
generateItemLink={calculateNavigateUrl}
|