@imposium-hub/components 2.5.11 → 2.5.12

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 (92) hide show
  1. package/dist/cjs/components/assets/AssetsTableAssetIdCell.d.ts +2 -0
  2. package/dist/cjs/components/assets/AssetsTableAssetIdCell.js +54 -0
  3. package/dist/cjs/components/assets/AssetsTableAssetIdCell.js.map +1 -0
  4. package/dist/cjs/components/assets/AssetsTableAssetIdFilter.d.ts +2 -0
  5. package/dist/cjs/components/assets/AssetsTableAssetIdFilter.js +94 -0
  6. package/dist/cjs/components/assets/AssetsTableAssetIdFilter.js.map +1 -0
  7. package/dist/cjs/components/assets/AssetsTableGlobalCell.js +2 -1
  8. package/dist/cjs/components/assets/AssetsTableGlobalCell.js.map +1 -1
  9. package/dist/cjs/components/assets/StoryTableNameFilter.d.ts +2 -0
  10. package/dist/cjs/components/assets/StoryTableNameFilter.js +94 -0
  11. package/dist/cjs/components/assets/StoryTableNameFilter.js.map +1 -0
  12. package/dist/cjs/components/card/Card.d.ts +1 -0
  13. package/dist/cjs/components/card/Card.js +17 -4
  14. package/dist/cjs/components/card/Card.js.map +1 -1
  15. package/dist/cjs/components/color-field/ColorField.js +9 -14
  16. package/dist/cjs/components/color-field/ColorField.js.map +1 -1
  17. package/dist/cjs/components/data-table/DataTable.d.ts +3 -2
  18. package/dist/cjs/components/data-table/DataTable.js +78 -10
  19. package/dist/cjs/components/data-table/DataTable.js.map +1 -1
  20. package/dist/cjs/components/data-table/Paginator.js +76 -11
  21. package/dist/cjs/components/data-table/Paginator.js.map +1 -1
  22. package/dist/cjs/components/header/Header.d.ts +2 -0
  23. package/dist/cjs/components/header/Header.js +39 -8
  24. package/dist/cjs/components/header/Header.js.map +1 -1
  25. package/dist/cjs/components/smpte-field/SMPTEField.d.ts +2 -1
  26. package/dist/cjs/components/smpte-field/SMPTEField.js +9 -3
  27. package/dist/cjs/components/smpte-field/SMPTEField.js.map +1 -1
  28. package/dist/cjs/index.d.ts +6 -1
  29. package/dist/cjs/index.js +14 -2
  30. package/dist/cjs/index.js.map +1 -1
  31. package/dist/cjs/redux/actions/story-filter.d.ts +4 -0
  32. package/dist/cjs/redux/actions/story-filter.js +18 -0
  33. package/dist/cjs/redux/actions/story-filter.js.map +1 -0
  34. package/dist/cjs/redux/reducers/story-filter.d.ts +2 -0
  35. package/dist/cjs/redux/reducers/story-filter.js +33 -0
  36. package/dist/cjs/redux/reducers/story-filter.js.map +1 -0
  37. package/dist/esm/components/assets/AssetsTableAssetIdCell.d.ts +2 -0
  38. package/dist/esm/components/assets/AssetsTableAssetIdCell.js +29 -0
  39. package/dist/esm/components/assets/AssetsTableAssetIdCell.js.map +1 -0
  40. package/dist/esm/components/assets/AssetsTableAssetIdFilter.d.ts +2 -0
  41. package/dist/esm/components/assets/AssetsTableAssetIdFilter.js +20 -0
  42. package/dist/esm/components/assets/AssetsTableAssetIdFilter.js.map +1 -0
  43. package/dist/esm/components/assets/AssetsTableGlobalCell.js +2 -1
  44. package/dist/esm/components/assets/AssetsTableGlobalCell.js.map +1 -1
  45. package/dist/esm/components/assets/StoryTableNameFilter.d.ts +2 -0
  46. package/dist/esm/components/assets/StoryTableNameFilter.js +20 -0
  47. package/dist/esm/components/assets/StoryTableNameFilter.js.map +1 -0
  48. package/dist/esm/components/card/Card.d.ts +1 -0
  49. package/dist/esm/components/card/Card.js +16 -4
  50. package/dist/esm/components/card/Card.js.map +1 -1
  51. package/dist/esm/components/color-field/ColorField.js +9 -14
  52. package/dist/esm/components/color-field/ColorField.js.map +1 -1
  53. package/dist/esm/components/data-table/DataTable.d.ts +3 -2
  54. package/dist/esm/components/data-table/DataTable.js +76 -8
  55. package/dist/esm/components/data-table/DataTable.js.map +1 -1
  56. package/dist/esm/components/data-table/Paginator.js +95 -44
  57. package/dist/esm/components/data-table/Paginator.js.map +1 -1
  58. package/dist/esm/components/header/Header.d.ts +2 -0
  59. package/dist/esm/components/header/Header.js +30 -7
  60. package/dist/esm/components/header/Header.js.map +1 -1
  61. package/dist/esm/components/smpte-field/SMPTEField.d.ts +2 -1
  62. package/dist/esm/components/smpte-field/SMPTEField.js +9 -3
  63. package/dist/esm/components/smpte-field/SMPTEField.js.map +1 -1
  64. package/dist/esm/index.d.ts +6 -1
  65. package/dist/esm/index.js +6 -1
  66. package/dist/esm/index.js.map +1 -1
  67. package/dist/esm/redux/actions/story-filter.d.ts +4 -0
  68. package/dist/esm/redux/actions/story-filter.js +13 -0
  69. package/dist/esm/redux/actions/story-filter.js.map +1 -0
  70. package/dist/esm/redux/reducers/story-filter.d.ts +2 -0
  71. package/dist/esm/redux/reducers/story-filter.js +16 -0
  72. package/dist/esm/redux/reducers/story-filter.js.map +1 -0
  73. package/dist/styles.css +13 -5
  74. package/dist/styles.less +16 -8
  75. package/less/components/data-table.less +4 -0
  76. package/less/components/form-field.less +7 -3
  77. package/less/components/header.less +0 -5
  78. package/less/components/tag.less +5 -0
  79. package/package.json +1 -1
  80. package/src/components/assets/AssetsTableAssetIdCell.tsx +64 -0
  81. package/src/components/assets/AssetsTableAssetIdFilter.tsx +41 -0
  82. package/src/components/assets/AssetsTableGlobalCell.tsx +11 -1
  83. package/src/components/assets/StoryTableNameFilter.tsx +40 -0
  84. package/src/components/card/Card.tsx +27 -13
  85. package/src/components/color-field/ColorField.tsx +16 -17
  86. package/src/components/data-table/DataTable.tsx +96 -12
  87. package/src/components/data-table/Paginator.tsx +162 -93
  88. package/src/components/header/Header.tsx +42 -6
  89. package/src/components/smpte-field/SMPTEField.tsx +8 -3
  90. package/src/index.ts +11 -0
  91. package/src/redux/actions/story-filter.ts +15 -0
  92. package/src/redux/reducers/story-filter.ts +18 -0
package/dist/styles.css CHANGED
@@ -1077,6 +1077,9 @@ body a {
1077
1077
  border-top: 0;
1078
1078
  background-color: #242424;
1079
1079
  }
1080
+ .ip-table-wrapper .ip-table-pagination input[type=number] {
1081
+ -moz-appearance: textfield;
1082
+ }
1080
1083
  .ip-table-wrapper .ip-table-pagination .paginator-input {
1081
1084
  display: inline-block;
1082
1085
  background: #1d1d1d;
@@ -1258,6 +1261,9 @@ body a {
1258
1261
  .form-field textarea:disabled:hover {
1259
1262
  background: #1d1d1d;
1260
1263
  }
1264
+ .form-field input[type=number] {
1265
+ -moz-appearance: textfield;
1266
+ }
1261
1267
  .form-field textarea {
1262
1268
  height: 60px;
1263
1269
  resize: none;
@@ -1393,14 +1399,15 @@ body a {
1393
1399
  padding-top: 1px;
1394
1400
  box-sizing: border-box;
1395
1401
  color: #939393;
1402
+ background: #373737;
1396
1403
  }
1397
1404
  .button-group-field .button-group .button-group-option:hover {
1398
1405
  background: #101010;
1399
1406
  }
1400
1407
  .button-group-field .button-group .button-group-option.active {
1401
1408
  cursor: auto;
1402
- background: #373737;
1403
- color: #dfdfdf;
1409
+ background: unset;
1410
+ color: unset;
1404
1411
  }
1405
1412
  .button-group-field .button-group .button-group-option.disabled svg {
1406
1413
  color: gray;
@@ -1893,9 +1900,6 @@ body a {
1893
1900
  cursor: pointer;
1894
1901
  height: 244px;
1895
1902
  }
1896
- .imposium-header .stories-menu .ip-table-body .ip-table-row:hover .ip-table-col {
1897
- background-color: #393939;
1898
- }
1899
1903
  .imposium-header .orgs-menu {
1900
1904
  width: 240px;
1901
1905
  }
@@ -2848,6 +2852,10 @@ body a {
2848
2852
  margin-top: 2px;
2849
2853
  cursor: pointer;
2850
2854
  }
2855
+ .imposium-asset-id {
2856
+ cursor: pointer;
2857
+ user-select: none;
2858
+ }
2851
2859
  h1,
2852
2860
  h2,
2853
2861
  h3,
package/dist/styles.less CHANGED
@@ -1246,6 +1246,10 @@ body{
1246
1246
  border-top: 0;
1247
1247
  background-color: darken(@background, 1%);
1248
1248
 
1249
+ input[type=number] {
1250
+ -moz-appearance: textfield;
1251
+ }
1252
+
1249
1253
  .paginator-input {
1250
1254
  .inputMixin;
1251
1255
  width: 60px;
@@ -1375,6 +1379,10 @@ body{
1375
1379
  padding:4px;
1376
1380
  }
1377
1381
 
1382
+ input[type=number] {
1383
+ -moz-appearance: textfield;
1384
+ }
1385
+
1378
1386
  textarea{
1379
1387
  height:@inputHeight * 3;
1380
1388
  resize:none;
@@ -1476,15 +1484,15 @@ body{
1476
1484
  padding-top: 1px;
1477
1485
  box-sizing: border-box;
1478
1486
  color:darken(@textDefault, 30%);
1479
-
1487
+ background: #373737;
1480
1488
  &:hover{
1481
1489
  background:darken(@inputBackground, 5%);
1482
1490
  }
1483
1491
 
1484
1492
  &.active{
1485
1493
  cursor:auto;
1486
- background:lighten(@inputBackground, 10%);
1487
- color:@textDefault;
1494
+ background:unset;
1495
+ color:unset;
1488
1496
  }
1489
1497
 
1490
1498
  &.disabled svg {
@@ -1917,11 +1925,6 @@ body{
1917
1925
  .ip-table-body {
1918
1926
  cursor: pointer;
1919
1927
  height: 244px;
1920
- .ip-table-row:hover{
1921
- .ip-table-col {
1922
- background-color: darken(@backgroundHighlight, 15%);
1923
- }
1924
- }
1925
1928
  }
1926
1929
  }
1927
1930
 
@@ -2936,6 +2939,11 @@ body{
2936
2939
  }
2937
2940
  }
2938
2941
  }
2942
+
2943
+ .imposium-asset-id {
2944
+ cursor: pointer;
2945
+ user-select: none;
2946
+ }
2939
2947
  h1, h2, h3, h4, h5 {
2940
2948
  font-family: 'Oswald', sans-serif;
2941
2949
  color:@headerTextDefault;
@@ -207,6 +207,10 @@
207
207
  border-top: 0;
208
208
  background-color: darken(@background, 1%);
209
209
 
210
+ input[type=number] {
211
+ -moz-appearance: textfield;
212
+ }
213
+
210
214
  .paginator-input {
211
215
  .inputMixin;
212
216
  width: 60px;
@@ -55,6 +55,10 @@
55
55
  padding:4px;
56
56
  }
57
57
 
58
+ input[type=number] {
59
+ -moz-appearance: textfield;
60
+ }
61
+
58
62
  textarea{
59
63
  height:@inputHeight * 3;
60
64
  resize:none;
@@ -156,15 +160,15 @@
156
160
  padding-top: 1px;
157
161
  box-sizing: border-box;
158
162
  color:darken(@textDefault, 30%);
159
-
163
+ background: #373737;
160
164
  &:hover{
161
165
  background:darken(@inputBackground, 5%);
162
166
  }
163
167
 
164
168
  &.active{
165
169
  cursor:auto;
166
- background:lighten(@inputBackground, 10%);
167
- color:@textDefault;
170
+ background:unset;
171
+ color:unset;
168
172
  }
169
173
 
170
174
  &.disabled svg {
@@ -298,11 +298,6 @@
298
298
  .ip-table-body {
299
299
  cursor: pointer;
300
300
  height: 244px;
301
- .ip-table-row:hover{
302
- .ip-table-col {
303
- background-color: darken(@backgroundHighlight, 15%);
304
- }
305
- }
306
301
  }
307
302
  }
308
303
 
@@ -40,4 +40,9 @@
40
40
  cursor: pointer;
41
41
  }
42
42
  }
43
+ }
44
+
45
+ .imposium-asset-id {
46
+ cursor: pointer;
47
+ user-select: none;
43
48
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@imposium-hub/components",
3
- "version": "2.5.11",
3
+ "version": "2.5.12",
4
4
  "description": "React & Typescript component / asset library for Imposium front-ends",
5
5
  "main": "./dist/cjs/index.js",
6
6
  "module": "./dist/esm/index.js",
@@ -0,0 +1,64 @@
1
+ import * as React from 'react';
2
+ import { copying } from '../../constants/copy';
3
+ import { updateFilters } from '../../redux/actions/asset-filters';
4
+ import { connect } from 'react-redux';
5
+ import { bindActionCreators } from 'redux';
6
+
7
+ interface IAssetsTableAssetIdCellProps {
8
+ cell: any;
9
+ onNotification?: (e) => void;
10
+ onError?: (e) => void;
11
+ }
12
+
13
+ const AssetsTableAssetIdCell: React.FC<IAssetsTableAssetIdCellProps> = (
14
+ props: IAssetsTableAssetIdCellProps
15
+ ) => {
16
+ const {
17
+ onNotification,
18
+ onError,
19
+ cell: {
20
+ row: {
21
+ original: { id }
22
+ }
23
+ }
24
+ } = props;
25
+
26
+ const copyToClipboard = (e) => {
27
+ navigator.clipboard.writeText(e.target.textContent).then(
28
+ () => {
29
+ if (onNotification) {
30
+ onNotification(`${copying.copied}`);
31
+ }
32
+ },
33
+ () => {
34
+ if (onError) {
35
+ onError(`${copying.error}`);
36
+ }
37
+ }
38
+ );
39
+ };
40
+
41
+ return (
42
+ <div
43
+ key={id}
44
+ className='imposium-asset-id'
45
+ onClick={(e) => copyToClipboard(e)}>
46
+ {id}
47
+ </div>
48
+ );
49
+ };
50
+
51
+ const mapDispatchToProps = (dispatch): any => {
52
+ return bindActionCreators({ updateFilters }, dispatch);
53
+ };
54
+
55
+ const mapStateToProps = (state): any => {
56
+ return { assetFilters: state.assetFilters };
57
+ };
58
+
59
+ const AssetsTableAssetIdCellMemoized = connect(
60
+ mapStateToProps,
61
+ mapDispatchToProps
62
+ )(React.memo(AssetsTableAssetIdCell));
63
+
64
+ export default AssetsTableAssetIdCellMemoized;
@@ -0,0 +1,41 @@
1
+ import * as React from 'react';
2
+ import TextField from '../text-field/TextField';
3
+ import { updateFilters } from '../../redux/actions/asset-filters';
4
+ import { connect } from 'react-redux';
5
+ import { bindActionCreators } from 'redux';
6
+
7
+ interface IAssetsTableAssetIdFilterProps {
8
+ assetFilters: any;
9
+ updateFilters: (filters: any) => any;
10
+ }
11
+
12
+ class AssetsTableAssetIdFilter extends React.PureComponent<IAssetsTableAssetIdFilterProps> {
13
+ public render = (): JSX.Element => {
14
+ const { assetFilters } = this.props;
15
+
16
+ return (
17
+ <TextField
18
+ className='asset-id'
19
+ submittable
20
+ submittableType='search'
21
+ value={assetFilters.id}
22
+ doSubmit={(n) => this.props.updateFilters({ id: n })}
23
+ />
24
+ );
25
+ };
26
+ }
27
+
28
+ const mapDispatchToProps = (dispatch): any => {
29
+ return bindActionCreators({ updateFilters }, dispatch);
30
+ };
31
+
32
+ const mapStateToProps = (state): any => {
33
+ return { assetFilters: state.assetFilters };
34
+ };
35
+
36
+ const AssetsTableAssetIdFilterMemoized = connect(
37
+ mapStateToProps,
38
+ mapDispatchToProps
39
+ )(React.memo(AssetsTableAssetIdFilter));
40
+
41
+ export default AssetsTableAssetIdFilterMemoized;
@@ -6,8 +6,18 @@ interface IAssetsTableGlobalCell {
6
6
  }
7
7
 
8
8
  const AssetsTableGlobalCell: React.FC<IAssetsTableGlobalCell> = (p: IAssetsTableGlobalCell) => {
9
+ const {
10
+ cell: {
11
+ row: {
12
+ original: { story_id }
13
+ }
14
+ }
15
+ } = p;
16
+
9
17
  return (
10
- <div className='asset-global-cell'>{p.cell.row.original.story_id ? null : ICON_GLOBE}</div>
18
+ <div className='asset-global-cell'>
19
+ {story_id || story_id === undefined ? null : ICON_GLOBE}
20
+ </div>
11
21
  );
12
22
  };
13
23
 
@@ -0,0 +1,40 @@
1
+ import * as React from 'react';
2
+ import TextField from '../text-field/TextField';
3
+ import { connect } from 'react-redux';
4
+ import { bindActionCreators } from 'redux';
5
+ import { updateStoryFilter } from '../../redux/actions/story-filter';
6
+
7
+ interface IStoryTableNameFilterProps {
8
+ storyFilter: any;
9
+ updateStoryFilter: (filters: any) => any;
10
+ }
11
+
12
+ class StoryTableNameFilter extends React.PureComponent<IStoryTableNameFilterProps> {
13
+ public render = (): JSX.Element => {
14
+ const { storyFilter } = this.props;
15
+
16
+ return (
17
+ <TextField
18
+ className='story-name'
19
+ focusOnMount
20
+ value={storyFilter}
21
+ onChange={(n) => this.props.updateStoryFilter({ name: n })}
22
+ />
23
+ );
24
+ };
25
+ }
26
+
27
+ const mapDispatchToProps = (dispatch): any => {
28
+ return bindActionCreators({ updateStoryFilter }, dispatch);
29
+ };
30
+
31
+ const mapStateToProps = (state): any => {
32
+ return { storyFilter: state.storyFilter.name };
33
+ };
34
+
35
+ const StoryTableNameFilterMemoized = connect(
36
+ mapStateToProps,
37
+ mapDispatchToProps
38
+ )(React.memo(StoryTableNameFilter));
39
+
40
+ export default StoryTableNameFilterMemoized;
@@ -11,6 +11,7 @@ interface ICardProps {
11
11
  onOpen?: (e: any) => any;
12
12
  onClose?: (e: any) => any;
13
13
  onToggle?: (toggle: boolean) => any;
14
+ buttons?: any[];
14
15
  }
15
16
 
16
17
  interface ICardState {
@@ -97,9 +98,7 @@ class Card extends React.PureComponent<ICardProps, ICardState> {
97
98
 
98
99
  return (
99
100
  <div className={`card ${openClass} ${collapsableClass} ${styleClass}`}>
100
- <div
101
- className='card-header'
102
- onClick={this.evtHandlers.toggleOpen}>
101
+ <div className='card-header'>
103
102
  {this.renderTitle(styleClass)}
104
103
  {this.renderButtons()}
105
104
  </div>
@@ -109,21 +108,36 @@ class Card extends React.PureComponent<ICardProps, ICardState> {
109
108
  }
110
109
 
111
110
  public renderButtons() {
112
- const { collapsable } = this.props;
111
+ const { collapsable, buttons } = this.props;
113
112
  const { open } = this.state;
114
113
  const buttonIcon = open ? ICON_CARET_UP : ICON_CARET_DOWN;
115
114
 
115
+ let buttonArray: JSX.Element[];
116
+
117
+ const toggleBtn = (
118
+ <Button
119
+ key='toggleOpen'
120
+ style='subtle'
121
+ onClick={(e) => this.toggleOpen(e)}>
122
+ {buttonIcon}
123
+ </Button>
124
+ );
125
+
126
+ if (buttons && buttons.length > 0) {
127
+ buttonArray = buttons.map((button) => {
128
+ return button;
129
+ });
130
+ }
131
+
116
132
  if (collapsable) {
117
- return (
118
- <div className='header-buttons'>
119
- <Button
120
- style='subtle'
121
- onClick={this.evtHandlers.toggleOpen}>
122
- {buttonIcon}
123
- </Button>
124
- </div>
125
- );
133
+ if (buttonArray && buttonArray.length > 0) {
134
+ buttonArray.push(toggleBtn);
135
+ } else {
136
+ buttonArray = [toggleBtn];
137
+ }
126
138
  }
139
+
140
+ return <div className='header-buttons'>{buttonArray}</div>;
127
141
  }
128
142
  }
129
143
 
@@ -127,18 +127,14 @@ class ColorField extends React.PureComponent<IColorFieldProps, IColorFieldState>
127
127
  />
128
128
  ) : null;
129
129
 
130
- let swatchStyle;
131
- if (value === 'transparent' || value === 'rgba(0,0,0,0)') {
132
- swatchStyle = {
133
- background: this.transparentBg,
134
- border: '1px solid #1d1d1d',
135
- boxSizing: 'border-box'
136
- };
137
- } else {
138
- swatchStyle = {
139
- backgroundColor: value
140
- };
141
- }
130
+ const swatchStyle = {
131
+ backgroundColor: value
132
+ };
133
+
134
+ const transparentBg = {
135
+ background: this.transparentBg,
136
+ height: '20px'
137
+ };
142
138
 
143
139
  return (
144
140
  <FieldWrapper
@@ -150,11 +146,14 @@ class ColorField extends React.PureComponent<IColorFieldProps, IColorFieldState>
150
146
  labelPosition={labelPosition}
151
147
  labelWidth={labelWidth}
152
148
  width={width}>
153
- <div
154
- className='swatch'
155
- style={swatchStyle}
156
- onClick={(e) => this.togglePicker(e)}
157
- />
149
+ <div style={transparentBg}>
150
+ <div
151
+ className='swatch'
152
+ style={swatchStyle}
153
+ onClick={(e) => this.togglePicker(e)}
154
+ />
155
+ </div>
156
+
158
157
  <div
159
158
  className={`picker picker-${pickerPos}`}
160
159
  ref={this.picker}>
@@ -82,14 +82,16 @@ interface IDataTableProps {
82
82
 
83
83
  // controlled selection props
84
84
  highlightBy?: any;
85
- onRowClick?: (row) => void;
86
- onRowDoubleClick?: (row) => void;
85
+ onRowClick?: (row, shiftKey?) => void;
86
+ onRowDoubleClick?: (row, shiftKey?) => void;
87
87
 
88
88
  renderPivotComponent?: (row) => JSX.Element;
89
89
 
90
90
  disableKeyScroll?: boolean;
91
91
 
92
92
  expandTags?: boolean;
93
+
94
+ keyboardNav?: boolean;
93
95
  }
94
96
 
95
97
  const processColumnData = (freshColumns): any[] => {
@@ -119,7 +121,7 @@ const DataTable: React.FC<IDataTableProps> = (props: IDataTableProps) => {
119
121
  const [didMount, setDidMount] = React.useState(false);
120
122
  const [data, setData] = React.useState([]);
121
123
  const [columns, setColumns] = React.useState([]);
122
-
124
+ const [selectedRowId, setSelectedRowId] = React.useState<number>(null);
123
125
  const manualPagination: boolean =
124
126
  Number.isInteger(props.currentPage) && typeof props.onPage === 'function';
125
127
  const manualSortBy: boolean =
@@ -205,6 +207,8 @@ const DataTable: React.FC<IDataTableProps> = (props: IDataTableProps) => {
205
207
  React.useEffect(() => {
206
208
  if (Array.isArray(props.data)) {
207
209
  setData(props.data);
210
+ setSelectedRowId(null);
211
+ scrollToTop();
208
212
  }
209
213
  }, [props.data]);
210
214
 
@@ -226,6 +230,64 @@ const DataTable: React.FC<IDataTableProps> = (props: IDataTableProps) => {
226
230
  }
227
231
  }, [sortBy]);
228
232
 
233
+ const getRowElem = () => {
234
+ return document.getElementsByClassName('ip-table-row selected keyboardNav')[0];
235
+ };
236
+
237
+ const getBodyEle = () => {
238
+ return document.querySelector('tbody.ip-table-body.keyboardNav');
239
+ };
240
+
241
+ const scrollIntoView = () => {
242
+ getRowElem().scrollIntoView({ behavior: 'smooth', block: 'center' });
243
+ };
244
+
245
+ const scrollToTop = () => {
246
+ if (getBodyEle()) {
247
+ getBodyEle().scrollTo({ top: 0, behavior: 'smooth' });
248
+ }
249
+ };
250
+
251
+ const scrollToBottom = () => {
252
+ const y = getRowElem().scrollHeight * rowData.length;
253
+ getBodyEle().scrollTo({ top: y, behavior: 'smooth' });
254
+ };
255
+
256
+ const rowSelector = (e) => {
257
+ e.preventDefault();
258
+ e.stopPropagation();
259
+ let rowId = 0;
260
+ const maxRowId = rowData.length - 1;
261
+ if (e.key === 'ArrowUp') {
262
+ if (selectedRowId === 0 || selectedRowId === null) {
263
+ setSelectedRowId(maxRowId);
264
+ scrollToBottom();
265
+ }
266
+ if (selectedRowId !== 0 && selectedRowId !== null) {
267
+ setSelectedRowId(selectedRowId - 1);
268
+ scrollIntoView();
269
+ }
270
+ }
271
+
272
+ if (e.key === 'ArrowDown') {
273
+ if (selectedRowId === null) {
274
+ setSelectedRowId(0);
275
+ } else {
276
+ rowId = selectedRowId === maxRowId ? 0 : selectedRowId + 1;
277
+ setSelectedRowId(rowId);
278
+ if (rowId === 0) {
279
+ scrollToTop();
280
+ } else {
281
+ scrollIntoView();
282
+ }
283
+ }
284
+ }
285
+
286
+ if (e.key === 'Enter' && typeof props.onRowClick === 'function' && selectedRowId !== null) {
287
+ props.onRowClick(rows[selectedRowId], e.shiftKey);
288
+ }
289
+ };
290
+
229
291
  return (
230
292
  <section
231
293
  ref={wrapperRef}
@@ -246,7 +308,17 @@ const DataTable: React.FC<IDataTableProps> = (props: IDataTableProps) => {
246
308
  <React.Fragment key='head-fragment'>
247
309
  <tr
248
310
  {...headerGroup.getHeaderGroupProps()}
249
- className='ip-table-head-row'>
311
+ className='ip-table-head-row'
312
+ onKeyDown={(e) => {
313
+ if (
314
+ (e.key === 'ArrowUp' ||
315
+ e.key === 'ArrowDown' ||
316
+ e.key === 'Enter') &&
317
+ props.keyboardNav
318
+ ) {
319
+ rowSelector(e);
320
+ }
321
+ }}>
250
322
  {headerGroup.headers.map((column) => {
251
323
  const searchable: boolean = column.hasOwnProperty('Search');
252
324
  const toggleProps: any = column.getSortByToggleProps();
@@ -326,7 +398,7 @@ const DataTable: React.FC<IDataTableProps> = (props: IDataTableProps) => {
326
398
 
327
399
  <tbody
328
400
  {...getTableBodyProps()}
329
- className='ip-table-body'>
401
+ className={`ip-table-body ${props.keyboardNav ? 'keyboardNav' : ''}`}>
330
402
  {rowData.map((row, i) => {
331
403
  let selectedClass: string = '';
332
404
  let activeRef: any;
@@ -351,30 +423,43 @@ const DataTable: React.FC<IDataTableProps> = (props: IDataTableProps) => {
351
423
 
352
424
  prepareRow(row);
353
425
 
426
+ if (i === selectedRowId) {
427
+ selectedClass = 'selected';
428
+ }
429
+
354
430
  const rowProps = row.getRowProps();
355
- rowProps.className = `ip-table-row ${selectedClass}`;
431
+ rowProps.className = `ip-table-row ${selectedClass} ${
432
+ props.keyboardNav ? 'keyboardNav' : ''
433
+ }`;
356
434
  rowProps.onClick = (e) => {
357
- const onClick = () => {
435
+ const onClick = (shift: boolean) => {
358
436
  if (typeof props.onRowClick === 'function') {
359
- props.onRowClick(row);
437
+ props.onRowClick(row, shift);
360
438
  }
361
439
  };
362
440
 
363
441
  if (!doubleClickEnabled) {
364
- onClick();
442
+ onClick(e.shiftKey);
365
443
  }
366
444
 
367
445
  if (e.detail === 1 && doubleClickEnabled) {
368
- doubleClickTimeout = window.setTimeout(onClick, 200);
446
+ doubleClickTimeout = window.setTimeout(
447
+ () => onClick(e.shiftKey),
448
+ 200
449
+ );
369
450
  }
370
451
  };
371
452
  rowProps.onDoubleClick = (e) => {
372
453
  clearTimeout(doubleClickTimeout);
373
454
  if (doubleClickEnabled) {
374
- props.onRowDoubleClick(row);
455
+ props.onRowDoubleClick(row, e.shiftKey);
375
456
  }
376
457
  };
377
458
 
459
+ rowProps.onMouseMove = () => {
460
+ setSelectedRowId(i);
461
+ };
462
+
378
463
  const rowContent = row.cells.map((cell) => (
379
464
  <td
380
465
  {...cell.getCellProps()}
@@ -386,7 +471,6 @@ const DataTable: React.FC<IDataTableProps> = (props: IDataTableProps) => {
386
471
  ));
387
472
  const rowId = row?.original?.id || i;
388
473
  const rowKey = `row-${rowId}`;
389
-
390
474
  const expanded = props.expandTags ? props.expandTags : row.isExpanded;
391
475
  return (
392
476
  <React.Fragment key={rowKey}>