@axinom/mosaic-ui 0.64.0-rc.7 → 0.64.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/components/Explorer/BulkEdit/FormFieldsConfigConverter.d.ts +1 -1
- package/dist/components/Explorer/BulkEdit/GenerateMutation.d.ts.map +1 -1
- package/dist/components/Explorer/BulkEdit/index.d.ts +1 -0
- package/dist/components/Explorer/BulkEdit/index.d.ts.map +1 -1
- package/dist/components/Explorer/QuickEdit/useQuickEdit.d.ts.map +1 -1
- package/dist/components/Explorer/index.d.ts +1 -1
- package/dist/components/Explorer/index.d.ts.map +1 -1
- package/dist/components/InfoTooltip/InfoTooltip.d.ts.map +1 -1
- package/dist/components/InlineMenu/InlineMenu.d.ts.map +1 -1
- package/dist/components/List/List.d.ts +6 -1
- package/dist/components/List/List.d.ts.map +1 -1
- package/dist/components/List/ListRow/ListRow.d.ts +5 -20
- package/dist/components/List/ListRow/ListRow.d.ts.map +1 -1
- package/dist/components/List/ListRowRenderer/ListRowRenderer.d.ts +22 -0
- package/dist/components/List/ListRowRenderer/ListRowRenderer.d.ts.map +1 -0
- package/dist/index.es.js +4 -5
- package/dist/index.es.js.map +1 -1
- package/dist/index.js +4 -5
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/components/Explorer/BulkEdit/FormFieldsConfigConverter.spec.tsx +158 -14
- package/src/components/Explorer/BulkEdit/FormFieldsConfigConverter.tsx +2 -2
- package/src/components/Explorer/BulkEdit/GenerateMutation.spec.tsx +209 -0
- package/src/components/Explorer/BulkEdit/GenerateMutation.tsx +78 -12
- package/src/components/Explorer/BulkEdit/index.ts +1 -0
- package/src/components/Explorer/QuickEdit/useQuickEdit.tsx +1 -0
- package/src/components/Explorer/index.ts +1 -0
- package/src/components/InfoTooltip/InfoTooltip.scss +65 -65
- package/src/components/InfoTooltip/InfoTooltip.tsx +35 -31
- package/src/components/InlineMenu/InlineMenu.tsx +39 -33
- package/src/components/List/List.spec.tsx +209 -1
- package/src/components/List/List.stories.tsx +76 -0
- package/src/components/List/List.tsx +52 -31
- package/src/components/List/ListRow/ListRow.scss +5 -0
- package/src/components/List/ListRow/ListRow.spec.tsx +97 -155
- package/src/components/List/ListRow/ListRow.tsx +31 -57
- package/src/components/List/ListRowRenderer/ListRowRenderer.spec.tsx +353 -0
- package/src/components/List/ListRowRenderer/ListRowRenderer.tsx +68 -0
- package/src/components/PageHeader/PageHeaderActionsGroup/PageHeaderActionsGroup.scss +32 -32
|
@@ -24,8 +24,9 @@ import {
|
|
|
24
24
|
} from './List.model';
|
|
25
25
|
import classes from './List.scss';
|
|
26
26
|
import { ListHeader } from './ListHeader/ListHeader';
|
|
27
|
-
import {
|
|
27
|
+
import { ListRowProps } from './ListRow/ListRow';
|
|
28
28
|
import { ListRowLoader } from './ListRow/ListRowLoader';
|
|
29
|
+
import { ListRowRenderer } from './ListRowRenderer/ListRowRenderer';
|
|
29
30
|
import { getActionButtonVisibility, isTrigger, useSort } from './helpers';
|
|
30
31
|
import { useColumnsSize } from './useColumnsSize';
|
|
31
32
|
|
|
@@ -110,6 +111,10 @@ export interface ListProps<T extends Data> {
|
|
|
110
111
|
className?: string;
|
|
111
112
|
/** Provide inline actions which are available through '...' context menu */
|
|
112
113
|
inlineMenuActions?: (data: T) => ActionData[];
|
|
114
|
+
/** Function to determine if a specific row should be disabled */
|
|
115
|
+
isRowDisabled?: (data: T, index: number) => boolean;
|
|
116
|
+
/** Custom row renderer - if it returns null, the default ListRow will be used */
|
|
117
|
+
customRowRenderer?: (props: ListRowProps<T>) => ReactElement | null;
|
|
113
118
|
}
|
|
114
119
|
|
|
115
120
|
const ListRenderer = <T extends Data>(
|
|
@@ -145,6 +150,8 @@ const ListRenderer = <T extends Data>(
|
|
|
145
150
|
generateItemLink,
|
|
146
151
|
className = '',
|
|
147
152
|
inlineMenuActions,
|
|
153
|
+
isRowDisabled,
|
|
154
|
+
customRowRenderer,
|
|
148
155
|
}: PropsWithChildren<ListProps<T>>,
|
|
149
156
|
ref?: React.ForwardedRef<ListElement>,
|
|
150
157
|
): JSX.Element => {
|
|
@@ -290,6 +297,21 @@ const ListRenderer = <T extends Data>(
|
|
|
290
297
|
}
|
|
291
298
|
}, [selectionMode]);
|
|
292
299
|
|
|
300
|
+
const getRowDisabledState = useCallback(
|
|
301
|
+
(item: ListItem<T>, index: number): boolean => {
|
|
302
|
+
const isDisabledDueToSelectAll =
|
|
303
|
+
isAllItemsChecked.current &&
|
|
304
|
+
!enableSelectAllDeselect &&
|
|
305
|
+
selectionMode === ListSelectMode.Multi;
|
|
306
|
+
|
|
307
|
+
const isDisabledByCustomLogic =
|
|
308
|
+
isRowDisabled?.(item.data, index) ?? false;
|
|
309
|
+
|
|
310
|
+
return isDisabledDueToSelectAll || isDisabledByCustomLogic;
|
|
311
|
+
},
|
|
312
|
+
[enableSelectAllDeselect, selectionMode, isRowDisabled],
|
|
313
|
+
);
|
|
314
|
+
|
|
293
315
|
return (
|
|
294
316
|
<div
|
|
295
317
|
className={clsx(classes.wrapper, 'list-wrapper', className)}
|
|
@@ -319,43 +341,42 @@ const ListRenderer = <T extends Data>(
|
|
|
319
341
|
onColumnSizesChanged={setColumnSizes}
|
|
320
342
|
hasActionColumn={hasActionColumn}
|
|
321
343
|
/>
|
|
344
|
+
|
|
322
345
|
{/* Rows */}
|
|
323
346
|
{listItems.map((item: ListItem<T>, index) => (
|
|
324
|
-
<
|
|
347
|
+
<ListRowRenderer<T>
|
|
325
348
|
key={String(item.data[keyProperty] || index)}
|
|
326
|
-
|
|
327
|
-
data={item.data}
|
|
328
|
-
itemSelected={item.selected}
|
|
349
|
+
customRowRenderer={customRowRenderer}
|
|
329
350
|
isTrigger={isTrigger<T>(index, listItems, loadingTriggerOffset)}
|
|
330
|
-
isRowDisabled={
|
|
331
|
-
isAllItemsChecked.current &&
|
|
332
|
-
!enableSelectAllDeselect &&
|
|
333
|
-
selectionMode === ListSelectMode.Multi
|
|
334
|
-
}
|
|
335
|
-
columnSizes={columnSizes}
|
|
336
|
-
columnGap={columnGap}
|
|
337
|
-
rowHeight={listRowHeight}
|
|
338
|
-
actionSize={listRowActionSize}
|
|
339
|
-
horizontalTextAlign={horizontalTextAlign}
|
|
340
|
-
verticalTextAlign={verticalTextAlign}
|
|
341
|
-
textWrap={textWrap}
|
|
342
|
-
selectionMode={selectionMode}
|
|
343
|
-
showActionButton={
|
|
344
|
-
selectionMode === ListSelectMode.None &&
|
|
345
|
-
getActionButtonVisibility(item.data, showActionButton)
|
|
346
|
-
}
|
|
347
|
-
showCheckMark={selectionMode === ListSelectMode.Single}
|
|
348
|
-
showItemCheckbox={selectionMode === ListSelectMode.Multi}
|
|
349
|
-
onItemClicked={
|
|
350
|
-
generateItemLink
|
|
351
|
-
? generateItemLink(item.data)
|
|
352
|
-
: (data) => itemClickedHandler(data, index)
|
|
353
|
-
}
|
|
354
351
|
onTriggered={onTriggeredHandler}
|
|
355
|
-
|
|
356
|
-
|
|
352
|
+
listRowProps={{
|
|
353
|
+
columns,
|
|
354
|
+
data: item.data,
|
|
355
|
+
itemSelected: item.selected,
|
|
356
|
+
isRowDisabled: getRowDisabledState(item, index),
|
|
357
|
+
columnSizes,
|
|
358
|
+
columnGap,
|
|
359
|
+
rowHeight: listRowHeight,
|
|
360
|
+
actionSize: listRowActionSize,
|
|
361
|
+
horizontalTextAlign,
|
|
362
|
+
verticalTextAlign,
|
|
363
|
+
textWrap,
|
|
364
|
+
selectionMode,
|
|
365
|
+
showActionButton:
|
|
366
|
+
selectionMode === ListSelectMode.None &&
|
|
367
|
+
getActionButtonVisibility(item.data, showActionButton),
|
|
368
|
+
showCheckMark: selectionMode === ListSelectMode.Single,
|
|
369
|
+
showItemCheckbox: selectionMode === ListSelectMode.Multi,
|
|
370
|
+
onItemClicked: generateItemLink
|
|
371
|
+
? generateItemLink(item.data)
|
|
372
|
+
: (data: T) => itemClickedHandler(data, index),
|
|
373
|
+
onItemSelected: (checked: boolean) =>
|
|
374
|
+
itemSelectedHandler(checked, index),
|
|
375
|
+
inlineMenuActions,
|
|
376
|
+
}}
|
|
357
377
|
/>
|
|
358
378
|
))}
|
|
379
|
+
|
|
359
380
|
{isLoading && (
|
|
360
381
|
<ListRowLoader
|
|
361
382
|
columnSizes={columnSizes}
|
|
@@ -275,194 +275,136 @@ describe('ListRow', () => {
|
|
|
275
275
|
expect(spy).toHaveBeenCalledWith(true);
|
|
276
276
|
});
|
|
277
277
|
|
|
278
|
-
|
|
279
|
-
const
|
|
280
|
-
const observe = jest.fn();
|
|
281
|
-
beforeEach(() => {
|
|
282
|
-
window.IntersectionObserver = jest.fn().mockImplementation(() => ({
|
|
283
|
-
observe,
|
|
284
|
-
}));
|
|
285
|
-
});
|
|
286
|
-
|
|
287
|
-
afterEach(() => {
|
|
288
|
-
window.IntersectionObserver = windowIntersectionObserver;
|
|
289
|
-
});
|
|
290
|
-
|
|
291
|
-
it('creates the IntersectionObserver when row has isTrigger===true', () => {
|
|
292
|
-
const spy = jest.fn();
|
|
293
|
-
const wrapper = mount(
|
|
294
|
-
<ListRow {...mockProps} isTrigger={true} onTriggered={spy} />,
|
|
295
|
-
);
|
|
296
|
-
|
|
297
|
-
expect(window.IntersectionObserver).toHaveBeenCalledTimes(1);
|
|
298
|
-
expect(observe).toHaveBeenCalledWith(wrapper.getDOMNode());
|
|
299
|
-
expect(spy).not.toHaveBeenCalled();
|
|
300
|
-
});
|
|
301
|
-
|
|
302
|
-
it('creates no IntersectionObserver when row has isTrigger===false', () => {
|
|
303
|
-
const spy = jest.fn();
|
|
304
|
-
|
|
305
|
-
mount(<ListRow {...mockProps} isTrigger={false} onTriggered={spy} />);
|
|
306
|
-
|
|
307
|
-
expect(window.IntersectionObserver).not.toHaveBeenCalled();
|
|
308
|
-
expect(spy).not.toHaveBeenCalled();
|
|
309
|
-
});
|
|
278
|
+
it(`does not have the 'selected' class by default`, () => {
|
|
279
|
+
const wrapper = mount(<ListRow {...mockProps} />);
|
|
310
280
|
|
|
311
|
-
|
|
312
|
-
let intersectionFn: IntersectionObserverCallback = () => null;
|
|
313
|
-
const spy = jest.fn();
|
|
314
|
-
|
|
315
|
-
(window.IntersectionObserver as jest.Mock).mockImplementation((fn) => {
|
|
316
|
-
// Remember the callback function
|
|
317
|
-
intersectionFn = fn;
|
|
318
|
-
// Return the mocked object
|
|
319
|
-
return { observe };
|
|
320
|
-
});
|
|
321
|
-
|
|
322
|
-
mount(<ListRow {...mockProps} isTrigger={true} onTriggered={spy} />);
|
|
323
|
-
|
|
324
|
-
// Manually trigger the intersection callback
|
|
325
|
-
intersectionFn(
|
|
326
|
-
[{ isIntersecting: true } as IntersectionObserverEntry],
|
|
327
|
-
{} as IntersectionObserver,
|
|
328
|
-
);
|
|
329
|
-
|
|
330
|
-
expect(spy).toHaveBeenCalledTimes(1);
|
|
331
|
-
});
|
|
332
|
-
|
|
333
|
-
it(`does not have the 'selected' class by default`, () => {
|
|
334
|
-
const wrapper = mount(<ListRow {...mockProps} />);
|
|
335
|
-
|
|
336
|
-
const row = wrapper.find('.columnsRoot');
|
|
337
|
-
|
|
338
|
-
expect(row.hasClass('selected')).toBe(false);
|
|
339
|
-
});
|
|
281
|
+
const row = wrapper.find('.columnsRoot');
|
|
340
282
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
<ListRow {...mockProps} itemSelected={true} showItemCheckbox={true} />,
|
|
344
|
-
);
|
|
283
|
+
expect(row.hasClass('selected')).toBe(false);
|
|
284
|
+
});
|
|
345
285
|
|
|
346
|
-
|
|
286
|
+
it(`only has the 'selected' class if both itemSelect and showItemCheckbox props are true`, () => {
|
|
287
|
+
const wrapper = mount(
|
|
288
|
+
<ListRow {...mockProps} itemSelected={true} showItemCheckbox={true} />,
|
|
289
|
+
);
|
|
347
290
|
|
|
348
|
-
|
|
349
|
-
});
|
|
291
|
+
const row = wrapper.find('.columnsRoot');
|
|
350
292
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
const onItemSelectedSpy = jest.fn();
|
|
293
|
+
expect(row.hasClass('selected')).toBe(true);
|
|
294
|
+
});
|
|
354
295
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
showItemCheckbox={true}
|
|
359
|
-
onItemClicked={onItemClickedSpy}
|
|
360
|
-
onItemSelected={onItemSelectedSpy}
|
|
361
|
-
/>,
|
|
362
|
-
);
|
|
296
|
+
it(`raises onItemClicked if list selectionMode is set to None(the default mode)`, () => {
|
|
297
|
+
const onItemClickedSpy = jest.fn();
|
|
298
|
+
const onItemSelectedSpy = jest.fn();
|
|
363
299
|
|
|
364
|
-
|
|
300
|
+
const wrapper = mount(
|
|
301
|
+
<ListRow
|
|
302
|
+
{...mockProps}
|
|
303
|
+
showItemCheckbox={true}
|
|
304
|
+
onItemClicked={onItemClickedSpy}
|
|
305
|
+
onItemSelected={onItemSelectedSpy}
|
|
306
|
+
/>,
|
|
307
|
+
);
|
|
365
308
|
|
|
366
|
-
|
|
309
|
+
const row = wrapper.find('.content');
|
|
367
310
|
|
|
368
|
-
|
|
369
|
-
expect(onItemSelectedSpy).not.toHaveBeenCalled();
|
|
370
|
-
});
|
|
311
|
+
row.simulate('click');
|
|
371
312
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
313
|
+
expect(onItemClickedSpy).toHaveBeenCalledTimes(1);
|
|
314
|
+
expect(onItemSelectedSpy).not.toHaveBeenCalled();
|
|
315
|
+
});
|
|
375
316
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
showItemCheckbox={true}
|
|
380
|
-
selectionMode={ListSelectMode.Single}
|
|
381
|
-
onItemClicked={onItemClickedSpy}
|
|
382
|
-
onItemSelected={onItemSelectedSpy}
|
|
383
|
-
/>,
|
|
384
|
-
);
|
|
317
|
+
it(`raises onItemClicked if list selectionMode is set to Single`, () => {
|
|
318
|
+
const onItemClickedSpy = jest.fn();
|
|
319
|
+
const onItemSelectedSpy = jest.fn();
|
|
385
320
|
|
|
386
|
-
|
|
321
|
+
const wrapper = mount(
|
|
322
|
+
<ListRow
|
|
323
|
+
{...mockProps}
|
|
324
|
+
showItemCheckbox={true}
|
|
325
|
+
selectionMode={ListSelectMode.Single}
|
|
326
|
+
onItemClicked={onItemClickedSpy}
|
|
327
|
+
onItemSelected={onItemSelectedSpy}
|
|
328
|
+
/>,
|
|
329
|
+
);
|
|
387
330
|
|
|
388
|
-
|
|
331
|
+
const row = wrapper.find('.content');
|
|
389
332
|
|
|
390
|
-
|
|
391
|
-
expect(onItemSelectedSpy).not.toHaveBeenCalled();
|
|
392
|
-
});
|
|
333
|
+
row.simulate('click');
|
|
393
334
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
const mockChecked = false;
|
|
335
|
+
expect(onItemClickedSpy).toHaveBeenCalledTimes(1);
|
|
336
|
+
expect(onItemSelectedSpy).not.toHaveBeenCalled();
|
|
337
|
+
});
|
|
398
338
|
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
selectionMode={ListSelectMode.Multi}
|
|
404
|
-
onItemClicked={onItemClickedSpy}
|
|
405
|
-
onItemSelected={onItemSelectedSpy}
|
|
406
|
-
/>,
|
|
407
|
-
);
|
|
339
|
+
it(`raises onItemSelected and toggles item selection if list selectionMode is set to Multi and checkbox is not disabled`, async () => {
|
|
340
|
+
const onItemClickedSpy = jest.fn();
|
|
341
|
+
const onItemSelectedSpy = jest.fn();
|
|
342
|
+
const mockChecked = false;
|
|
408
343
|
|
|
409
|
-
|
|
344
|
+
const wrapper = mount(
|
|
345
|
+
<ListRow
|
|
346
|
+
{...mockProps}
|
|
347
|
+
showItemCheckbox={true}
|
|
348
|
+
selectionMode={ListSelectMode.Multi}
|
|
349
|
+
onItemClicked={onItemClickedSpy}
|
|
350
|
+
onItemSelected={onItemSelectedSpy}
|
|
351
|
+
/>,
|
|
352
|
+
);
|
|
410
353
|
|
|
411
|
-
|
|
354
|
+
const row = wrapper.find('.content');
|
|
412
355
|
|
|
413
|
-
|
|
356
|
+
row.simulate('click');
|
|
414
357
|
|
|
415
|
-
|
|
416
|
-
expect(onItemSelectedSpy).toHaveBeenCalledWith(!mockChecked);
|
|
417
|
-
expect(onItemClickedSpy).not.toHaveBeenCalled();
|
|
418
|
-
});
|
|
358
|
+
wrapper.update();
|
|
419
359
|
|
|
420
|
-
|
|
421
|
-
|
|
360
|
+
expect(onItemSelectedSpy).toHaveBeenCalledTimes(1);
|
|
361
|
+
expect(onItemSelectedSpy).toHaveBeenCalledWith(!mockChecked);
|
|
362
|
+
expect(onItemClickedSpy).not.toHaveBeenCalled();
|
|
363
|
+
});
|
|
422
364
|
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
{...mockProps}
|
|
426
|
-
showItemCheckbox={true}
|
|
427
|
-
selectionMode={ListSelectMode.Multi}
|
|
428
|
-
onItemSelected={onItemSelectedSpy}
|
|
429
|
-
isRowDisabled={true}
|
|
430
|
-
/>,
|
|
431
|
-
);
|
|
365
|
+
it(`does not raise onItemSelected if the row is disabled`, async () => {
|
|
366
|
+
const onItemSelectedSpy = jest.fn();
|
|
432
367
|
|
|
433
|
-
|
|
368
|
+
const wrapper = mount(
|
|
369
|
+
<ListRow
|
|
370
|
+
{...mockProps}
|
|
371
|
+
showItemCheckbox={true}
|
|
372
|
+
selectionMode={ListSelectMode.Multi}
|
|
373
|
+
onItemSelected={onItemSelectedSpy}
|
|
374
|
+
isRowDisabled={true}
|
|
375
|
+
/>,
|
|
376
|
+
);
|
|
434
377
|
|
|
435
|
-
|
|
378
|
+
const row = wrapper.find('.columnsRoot');
|
|
436
379
|
|
|
437
|
-
|
|
380
|
+
row.simulate('click');
|
|
438
381
|
|
|
439
|
-
|
|
440
|
-
expect(row.hasClass('disabled')).toBe(true);
|
|
441
|
-
});
|
|
382
|
+
wrapper.update();
|
|
442
383
|
|
|
443
|
-
|
|
444
|
-
|
|
384
|
+
expect(onItemSelectedSpy).not.toHaveBeenCalled();
|
|
385
|
+
expect(row.hasClass('disabled')).toBe(true);
|
|
386
|
+
});
|
|
445
387
|
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
{...mockProps}
|
|
449
|
-
showItemCheckbox={true}
|
|
450
|
-
onItemClicked={onItemClickedSpy}
|
|
451
|
-
isRowDisabled={true}
|
|
452
|
-
/>,
|
|
453
|
-
);
|
|
388
|
+
it(`does not onItemClicked if the row is disabled`, async () => {
|
|
389
|
+
const onItemClickedSpy = jest.fn();
|
|
454
390
|
|
|
455
|
-
|
|
391
|
+
const wrapper = mount(
|
|
392
|
+
<ListRow
|
|
393
|
+
{...mockProps}
|
|
394
|
+
showItemCheckbox={true}
|
|
395
|
+
onItemClicked={onItemClickedSpy}
|
|
396
|
+
isRowDisabled={true}
|
|
397
|
+
/>,
|
|
398
|
+
);
|
|
456
399
|
|
|
457
|
-
|
|
400
|
+
const row = wrapper.find('.columnsRoot');
|
|
458
401
|
|
|
459
|
-
|
|
402
|
+
row.simulate('click');
|
|
460
403
|
|
|
461
|
-
|
|
462
|
-
expect(row.hasClass('disabled')).toBe(true);
|
|
463
|
-
});
|
|
404
|
+
wrapper.update();
|
|
464
405
|
|
|
465
|
-
|
|
406
|
+
expect(onItemClickedSpy).not.toHaveBeenCalled();
|
|
407
|
+
expect(row.hasClass('disabled')).toBe(true);
|
|
466
408
|
});
|
|
467
409
|
|
|
468
410
|
describe('linking', () => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import clsx from 'clsx';
|
|
2
2
|
import { LocationDescriptor } from 'history';
|
|
3
|
-
import React, { PropsWithChildren, useCallback
|
|
3
|
+
import React, { PropsWithChildren, useCallback } from 'react';
|
|
4
4
|
import { Link } from 'react-router-dom';
|
|
5
5
|
import { noop } from '../../../helpers/utils';
|
|
6
6
|
import { Data } from '../../../types/data';
|
|
@@ -34,8 +34,6 @@ export interface ListRowProps<T extends Data> {
|
|
|
34
34
|
columns: Column<T>[];
|
|
35
35
|
/** Whether or not the item is selected (default: false) */
|
|
36
36
|
itemSelected?: boolean;
|
|
37
|
-
/** Whether or not the item is a trigger for pagination (default: false) */
|
|
38
|
-
isTrigger?: boolean;
|
|
39
37
|
/** Determines which selection mode the list is in. (default: ListSelectMode.None) */
|
|
40
38
|
selectionMode?: ListSelectMode;
|
|
41
39
|
/** Defines whether an action button will be rendered (default: true) */
|
|
@@ -46,7 +44,6 @@ export interface ListRowProps<T extends Data> {
|
|
|
46
44
|
showItemCheckbox?: boolean;
|
|
47
45
|
/** Defines whether a row is disabled (default: false) */
|
|
48
46
|
isRowDisabled?: boolean;
|
|
49
|
-
|
|
50
47
|
/** Used for when a row is clicked. This can be either a callback function that will be executed
|
|
51
48
|
* or a URL where the user should be navigated to.
|
|
52
49
|
* When the list should navigate the user to e.g. a details page of a entry it is recommended to
|
|
@@ -56,10 +53,6 @@ export interface ListRowProps<T extends Data> {
|
|
|
56
53
|
* A function that is getting called, when the selection state of the row changes.
|
|
57
54
|
*/
|
|
58
55
|
onItemSelected?: (checked: boolean) => void;
|
|
59
|
-
/**
|
|
60
|
-
* A function that is getting called, when the element acts as a trigger (`isTrigger = true`) and gets into view.
|
|
61
|
-
*/
|
|
62
|
-
onTriggered?: () => void;
|
|
63
56
|
/** Provide inline actions which are available through '...' context menu */
|
|
64
57
|
inlineMenuActions?: (data: T) => ActionData[];
|
|
65
58
|
}
|
|
@@ -214,28 +207,29 @@ const renderData = <T extends Data>(
|
|
|
214
207
|
* verticalTextAlign={'center'}
|
|
215
208
|
* />
|
|
216
209
|
*/
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
210
|
+
const ListRowComponent = <T extends Data>(
|
|
211
|
+
{
|
|
212
|
+
columnSizes,
|
|
213
|
+
columnGap,
|
|
214
|
+
actionSize,
|
|
215
|
+
horizontalTextAlign = 'left',
|
|
216
|
+
verticalTextAlign = 'center',
|
|
217
|
+
textWrap = false,
|
|
218
|
+
rowHeight = textWrap ? 'auto' : '50px',
|
|
219
|
+
data,
|
|
220
|
+
itemSelected = false,
|
|
221
|
+
columns,
|
|
222
|
+
selectionMode = ListSelectMode.None,
|
|
223
|
+
showActionButton = true,
|
|
224
|
+
showCheckMark = false,
|
|
225
|
+
showItemCheckbox = false,
|
|
226
|
+
onItemClicked = noop,
|
|
227
|
+
onItemSelected = noop,
|
|
228
|
+
isRowDisabled = false,
|
|
229
|
+
inlineMenuActions,
|
|
230
|
+
}: PropsWithChildren<ListRowProps<T>>,
|
|
231
|
+
ref: React.Ref<HTMLDivElement>,
|
|
232
|
+
): JSX.Element => {
|
|
239
233
|
const customRootStyles = {
|
|
240
234
|
gridAutoRows: `minmax(50px, ${rowHeight})`,
|
|
241
235
|
gridColumnGap: columnGap,
|
|
@@ -244,32 +238,6 @@ export const ListRow = <T extends Data>({
|
|
|
244
238
|
gridTemplateColumns: columnSizes,
|
|
245
239
|
} as React.CSSProperties;
|
|
246
240
|
|
|
247
|
-
// Trigger based on: https://www.youtube.com/watch?v=NZKUirTtxcg
|
|
248
|
-
const onTriggeredHandler = useCallback(() => {
|
|
249
|
-
onTriggered && onTriggered();
|
|
250
|
-
}, [onTriggered]);
|
|
251
|
-
const observer = useRef<IntersectionObserver>();
|
|
252
|
-
const elementRef = useCallback(
|
|
253
|
-
(node: HTMLDivElement) => {
|
|
254
|
-
if (isTrigger === false) {
|
|
255
|
-
return;
|
|
256
|
-
}
|
|
257
|
-
if (observer.current) {
|
|
258
|
-
observer.current.disconnect();
|
|
259
|
-
}
|
|
260
|
-
observer.current = new IntersectionObserver(([entry]) => {
|
|
261
|
-
if (entry.isIntersecting) {
|
|
262
|
-
onTriggeredHandler();
|
|
263
|
-
}
|
|
264
|
-
});
|
|
265
|
-
|
|
266
|
-
if (node) {
|
|
267
|
-
observer.current.observe(node);
|
|
268
|
-
}
|
|
269
|
-
},
|
|
270
|
-
[isTrigger, onTriggeredHandler],
|
|
271
|
-
);
|
|
272
|
-
|
|
273
241
|
const onItemClickedHandler = useCallback(
|
|
274
242
|
(data: T) => {
|
|
275
243
|
// Do nothing if row is disabled
|
|
@@ -334,7 +302,7 @@ export const ListRow = <T extends Data>({
|
|
|
334
302
|
[classes.disabled]: isRowDisabled,
|
|
335
303
|
})}
|
|
336
304
|
style={customRootStyles}
|
|
337
|
-
ref={
|
|
305
|
+
ref={ref}
|
|
338
306
|
data-test-id="list-entry"
|
|
339
307
|
>
|
|
340
308
|
{/* Items */}
|
|
@@ -416,3 +384,9 @@ export const ListRow = <T extends Data>({
|
|
|
416
384
|
|
|
417
385
|
return Row;
|
|
418
386
|
};
|
|
387
|
+
|
|
388
|
+
export const ListRow = React.forwardRef(ListRowComponent) as <T extends Data>(
|
|
389
|
+
props: PropsWithChildren<ListRowProps<T>> & {
|
|
390
|
+
ref?: React.Ref<HTMLDivElement>;
|
|
391
|
+
},
|
|
392
|
+
) => JSX.Element;
|