@urbanos/react-discovery-ui 2.1.50 → 2.1.52

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.
@@ -43,20 +43,32 @@ var DataTable = function DataTable(_ref) {
43
43
  _useState2 = _slicedToArray(_useState, 2),
44
44
  pagination = _useState2[0],
45
45
  setPagination = _useState2[1];
46
- var _useState3 = (0, _react.useState)({
47
- row: 0,
48
- col: 0
49
- }),
46
+ var _useState3 = (0, _react.useState)({}),
50
47
  _useState4 = _slicedToArray(_useState3, 2),
51
- focusedCell = _useState4[0],
52
- setFocusedCell = _useState4[1];
53
- var focusedCellRef = (0, _react.useRef)({
54
- row: 0,
55
- col: 0
56
- });
48
+ columnSizing = _useState4[0],
49
+ setColumnSizing = _useState4[1];
57
50
  var totalRowsRef = (0, _react.useRef)(1);
58
51
  var totalColsRef = (0, _react.useRef)(columns.length);
59
52
  var tableRef = (0, _react.useRef)(null);
53
+
54
+ // Stable per-instance prefix so header IDs are unique if multiple tables are on the page
55
+ var tableId = (0, _react.useRef)("dv-".concat(Math.random().toString(36).slice(2, 7))).current;
56
+ var colHeaderId = function colHeaderId(colIndex) {
57
+ return "".concat(tableId, "-col-").concat(colIndex);
58
+ };
59
+ var rowHeaderId = function rowHeaderId(rowIndex) {
60
+ return "".concat(tableId, "-row-").concat(rowIndex);
61
+ };
62
+ var dataCellId = function dataCellId(rowIndex, colIndex) {
63
+ return "".concat(tableId, "-cell-").concat(rowIndex, "-").concat(colIndex);
64
+ };
65
+
66
+ // aria-activedescendant: track currently active cell by ID
67
+ var _useState5 = (0, _react.useState)(colHeaderId(0)),
68
+ _useState6 = _slicedToArray(_useState5, 2),
69
+ activeCellId = _useState6[0],
70
+ setActiveCellId = _useState6[1];
71
+ var activeCellIdRef = (0, _react.useRef)(colHeaderId(0));
60
72
  (0, _react.useEffect)(function () {
61
73
  setPagination(function (prev) {
62
74
  return _objectSpread(_objectSpread({}, prev), {}, {
@@ -68,7 +80,8 @@ var DataTable = function DataTable(_ref) {
68
80
  data: data || [],
69
81
  columns: columns,
70
82
  state: {
71
- pagination: pagination
83
+ pagination: pagination,
84
+ columnSizing: columnSizing
72
85
  },
73
86
  onPaginationChange: function onPaginationChange(updater) {
74
87
  var newPagination = typeof updater === 'function' ? updater(pagination) : updater;
@@ -77,6 +90,9 @@ var DataTable = function DataTable(_ref) {
77
90
  onNextPageClicked(newPagination.pageIndex);
78
91
  }
79
92
  },
93
+ onColumnSizingChange: setColumnSizing,
94
+ columnResizeMode: 'onChange',
95
+ enableColumnResizing: true,
80
96
  getCoreRowModel: (0, _reactTable.getCoreRowModel)(),
81
97
  getPaginationRowModel: (0, _reactTable.getPaginationRowModel)()
82
98
  });
@@ -85,15 +101,54 @@ var DataTable = function DataTable(_ref) {
85
101
  totalRowsRef.current = table.getRowModel().rows.length + 1; // row 0 = header
86
102
  totalColsRef.current = columns.length;
87
103
 
88
- // Native keydown listenerfires before React's document-level delegation,
89
- // so e.preventDefault() reliably cancels browser arrow-key scroll.
104
+ // Resolve cell ID from (row, col) coordinates row 0 = header, rows 1+ = data rows
105
+ var resolveId = function resolveId(row, col) {
106
+ if (row === 0) return colHeaderId(col);
107
+ var dataRowIndex = row - 1;
108
+ return col === 0 ? rowHeaderId(dataRowIndex) : dataCellId(dataRowIndex, col);
109
+ };
110
+
111
+ // Parse (row, col) from a cell element's data attributes
112
+ var parseCoords = function parseCoords(el) {
113
+ var row = parseInt(el.getAttribute('data-row'), 10);
114
+ var col = parseInt(el.getAttribute('data-col'), 10);
115
+ return isNaN(row) || isNaN(col) ? null : {
116
+ row: row,
117
+ col: col
118
+ };
119
+ };
120
+ var activateCell = function activateCell(row, col) {
121
+ var id = resolveId(row, col);
122
+ activeCellIdRef.current = id;
123
+ setActiveCellId(id);
124
+ var tableEl = tableRef.current;
125
+ if (!tableEl) return;
126
+ var cell = tableEl.querySelector("[data-row=\"".concat(row, "\"][data-col=\"").concat(col, "\"]"));
127
+ if (cell) {
128
+ cell.scrollIntoView({
129
+ block: 'nearest',
130
+ inline: 'nearest'
131
+ });
132
+ }
133
+ };
134
+
135
+ // Native keydown listener on the table container — reliable preventDefault for arrow keys
90
136
  (0, _react.useEffect)(function () {
91
137
  var tableEl = tableRef.current;
92
138
  if (!tableEl) return;
93
139
  var handleKeyDown = function handleKeyDown(e) {
94
- var _focusedCellRef$curre = focusedCellRef.current,
95
- row = _focusedCellRef$curre.row,
96
- col = _focusedCellRef$curre.col;
140
+ // Parse current coords from active cell ID via DOM lookup
141
+ var activeEl = tableEl.querySelector("#".concat(CSS.escape(activeCellIdRef.current)));
142
+ var coords = activeEl ? parseCoords(activeEl) : {
143
+ row: 0,
144
+ col: 0
145
+ };
146
+ var _ref2 = coords || {
147
+ row: 0,
148
+ col: 0
149
+ },
150
+ row = _ref2.row,
151
+ col = _ref2.col;
97
152
  var moves = {
98
153
  ArrowUp: [row - 1, col],
99
154
  ArrowDown: [row + 1, col],
@@ -104,43 +159,20 @@ var DataTable = function DataTable(_ref) {
104
159
  e.preventDefault();
105
160
  var r = Math.max(0, Math.min(totalRowsRef.current - 1, moves[e.key][0]));
106
161
  var c = Math.max(0, Math.min(totalColsRef.current - 1, moves[e.key][1]));
107
- focusedCellRef.current = {
108
- row: r,
109
- col: c
110
- };
111
- setFocusedCell({
112
- row: r,
113
- col: c
114
- });
115
- var cell = tableEl.querySelector("[data-row=\"".concat(r, "\"][data-col=\"").concat(c, "\"]"));
116
- if (cell) {
117
- cell.focus({
118
- preventScroll: true
119
- });
120
- cell.scrollIntoView({
121
- block: 'nearest',
122
- inline: 'nearest'
123
- });
124
- }
162
+ activateCell(r, c);
125
163
  };
126
164
  tableEl.addEventListener('keydown', handleKeyDown);
127
165
  return function () {
128
166
  return tableEl.removeEventListener('keydown', handleKeyDown);
129
167
  };
130
- }, []); // empty deps — all values accessed via refs
168
+ }, []); // empty deps — all values accessed via refs or DOM
131
169
 
132
- var tabIndex = function tabIndex(row, col) {
133
- return focusedCell.row === row && focusedCell.col === col ? 0 : -1;
134
- };
135
- var onCellFocus = function onCellFocus(row, col) {
136
- focusedCellRef.current = {
137
- row: row,
138
- col: col
139
- };
140
- setFocusedCell({
141
- row: row,
142
- col: col
143
- });
170
+ // Click-to-activate via event delegation on the table
171
+ var handleTableClick = function handleTableClick(e) {
172
+ var cell = e.target.closest('[data-row][data-col]');
173
+ if (!cell) return;
174
+ var coords = parseCoords(cell);
175
+ if (coords) activateCell(coords.row, coords.col);
144
176
  };
145
177
  var dataRows = table.getRowModel().rows;
146
178
  var pageIndex = pagination.pageIndex;
@@ -153,11 +185,14 @@ var DataTable = function DataTable(_ref) {
153
185
  }, /*#__PURE__*/_react.default.createElement("table", {
154
186
  ref: tableRef,
155
187
  role: "grid",
188
+ tabIndex: 0,
189
+ "aria-activedescendant": activeCellId,
156
190
  "aria-rowcount": dataRows.length + 1,
157
191
  "aria-colcount": columns.length,
158
192
  style: {
159
- minWidth: "".concat(columns.length * 120, "px")
160
- }
193
+ width: table.getTotalSize()
194
+ },
195
+ onClick: handleTableClick
161
196
  }, /*#__PURE__*/_react.default.createElement("caption", null, datasetName ? "".concat(datasetName, " Dataset Preview") : 'Dataset Preview'), /*#__PURE__*/_react.default.createElement("thead", null, table.getHeaderGroups().map(function (headerGroup) {
162
197
  return /*#__PURE__*/_react.default.createElement("tr", {
163
198
  key: headerGroup.id,
@@ -167,17 +202,23 @@ var DataTable = function DataTable(_ref) {
167
202
  var _header$column$column;
168
203
  return /*#__PURE__*/_react.default.createElement("th", {
169
204
  key: header.id,
205
+ id: colHeaderId(colIndex),
170
206
  role: "columnheader",
171
207
  scope: "col",
172
- tabIndex: tabIndex(0, colIndex),
173
208
  "data-row": 0,
174
209
  "data-col": colIndex,
175
210
  "aria-colindex": colIndex + 1,
176
- onFocus: function onFocus() {
177
- return onCellFocus(0, colIndex);
178
- },
179
- className: ((_header$column$column = header.column.columnDef.meta) === null || _header$column$column === void 0 ? void 0 : _header$column$column.headerClassName) || 'table-header'
180
- }, header.isPlaceholder ? null : (0, _reactTable.flexRender)(header.column.columnDef.header, header.getContext()));
211
+ className: "".concat(((_header$column$column = header.column.columnDef.meta) === null || _header$column$column === void 0 ? void 0 : _header$column$column.headerClassName) || 'table-header').concat(activeCellId === colHeaderId(colIndex) ? ' active-cell' : ''),
212
+ style: {
213
+ width: header.getSize(),
214
+ position: 'relative'
215
+ }
216
+ }, header.isPlaceholder ? null : (0, _reactTable.flexRender)(header.column.columnDef.header, header.getContext()), header.column.getCanResize() && /*#__PURE__*/_react.default.createElement("div", {
217
+ className: "resizer".concat(header.column.getIsResizing() ? ' isResizing' : ''),
218
+ onMouseDown: header.getResizeHandler(),
219
+ onTouchStart: header.getResizeHandler(),
220
+ "aria-hidden": "true"
221
+ }));
181
222
  }));
182
223
  })), /*#__PURE__*/_react.default.createElement("tbody", null, dataRows.length === 0 ? /*#__PURE__*/_react.default.createElement("tr", {
183
224
  role: "row"
@@ -197,26 +238,23 @@ var DataTable = function DataTable(_ref) {
197
238
  var content = (0, _reactTable.flexRender)(cell.column.columnDef.cell, cell.getContext());
198
239
  return colIndex === 0 ? /*#__PURE__*/_react.default.createElement("th", {
199
240
  key: cell.id,
241
+ id: rowHeaderId(rowIndex),
200
242
  role: "rowheader",
201
243
  scope: "row",
202
- tabIndex: tabIndex(tableRow, colIndex),
244
+ headers: colHeaderId(0),
203
245
  "data-row": tableRow,
204
246
  "data-col": colIndex,
205
247
  "aria-colindex": 1,
206
- onFocus: function onFocus() {
207
- return onCellFocus(tableRow, colIndex);
208
- },
209
- className: "row-header"
248
+ className: "row-header".concat(activeCellId === rowHeaderId(rowIndex) ? ' active-cell' : '')
210
249
  }, content) : /*#__PURE__*/_react.default.createElement("td", {
211
250
  key: cell.id,
251
+ id: dataCellId(rowIndex, colIndex),
212
252
  role: "gridcell",
213
- tabIndex: tabIndex(tableRow, colIndex),
253
+ headers: "".concat(colHeaderId(colIndex), " ").concat(rowHeaderId(rowIndex)),
214
254
  "data-row": tableRow,
215
255
  "data-col": colIndex,
216
256
  "aria-colindex": colIndex + 1,
217
- onFocus: function onFocus() {
218
- return onCellFocus(tableRow, colIndex);
219
- }
257
+ className: activeCellId === dataCellId(rowIndex, colIndex) ? 'active-cell' : undefined
220
258
  }, content);
221
259
  }));
222
260
  }))), /*#__PURE__*/_react.default.createElement("div", {
@@ -297,10 +335,10 @@ var cleanseField = function cleanseField(value) {
297
335
  }
298
336
  };
299
337
  var cleanseRow = function cleanseRow(row) {
300
- var reconstructedObject = Object.assign.apply(Object, [{}].concat(_toConsumableArray(Object.entries(row).map(function (_ref2) {
301
- var _ref3 = _slicedToArray(_ref2, 2),
302
- k = _ref3[0],
303
- v = _ref3[1];
338
+ var reconstructedObject = Object.assign.apply(Object, [{}].concat(_toConsumableArray(Object.entries(row).map(function (_ref3) {
339
+ var _ref4 = _slicedToArray(_ref3, 2),
340
+ k = _ref4[0],
341
+ v = _ref4[1];
304
342
  return _defineProperty({}, k, cleanseField(v));
305
343
  }))));
306
344
  return reconstructedObject;
@@ -312,10 +350,10 @@ var cleanseData = function cleanseData(data) {
312
350
  });
313
351
  };
314
352
  var _default = exports.default = function _default(props) {
315
- var _useState5 = (0, _react.useState)(0),
316
- _useState6 = _slicedToArray(_useState5, 2),
317
- index = _useState6[0],
318
- setIndex = _useState6[1];
353
+ var _useState7 = (0, _react.useState)(0),
354
+ _useState8 = _slicedToArray(_useState7, 2),
355
+ index = _useState8[0],
356
+ setIndex = _useState8[1];
319
357
  var isGeojson = props.format === 'geojson';
320
358
  var cleanData = isGeojson ? undefined : props.data ? cleanseData(props.data) : props.data;
321
359
  var columns = (0, _react.useMemo)(function () {
@@ -326,6 +364,8 @@ var _default = exports.default = function _default(props) {
326
364
  accessorFn: function accessorFn(row) {
327
365
  return row[column];
328
366
  },
367
+ size: 120,
368
+ minSize: 60,
329
369
  meta: {
330
370
  headerClassName: 'table-header'
331
371
  }
@@ -11,7 +11,7 @@
11
11
  color: black;
12
12
  }
13
13
 
14
- tbody tr:nth-child(even).striped-row {
14
+ tbody tr.striped-row {
15
15
  background-color: rgba(0, 0, 0, 0.03);
16
16
  }
17
17
 
@@ -32,10 +32,32 @@
32
32
 
33
33
  table {
34
34
  table-layout: fixed;
35
- width: 100%;
36
35
  border-collapse: collapse;
37
36
  }
38
37
 
38
+ .resizer {
39
+ position: absolute;
40
+ right: 0;
41
+ top: 0;
42
+ height: 100%;
43
+ width: 4px;
44
+ cursor: col-resize;
45
+ user-select: none;
46
+ touch-action: none;
47
+ background: rgba(0, 0, 0, 0.15);
48
+ opacity: 0;
49
+
50
+ &:hover,
51
+ &.isResizing {
52
+ opacity: 1;
53
+ background: #005fcc;
54
+ }
55
+ }
56
+
57
+ th:hover .resizer {
58
+ opacity: 1;
59
+ }
60
+
39
61
  th, td {
40
62
  overflow: hidden;
41
63
  text-overflow: ellipsis;
@@ -53,6 +75,16 @@
53
75
  font-weight: normal;
54
76
  text-align: left;
55
77
  }
78
+
79
+ .active-cell {
80
+ outline: 2px solid #005fcc;
81
+ outline-offset: -2px;
82
+ }
83
+
84
+ table:focus {
85
+ outline: 2px solid #005fcc;
86
+ outline-offset: 2px;
87
+ }
56
88
  }
57
89
 
58
90
  #data-view-raw {
@@ -89,7 +89,7 @@ dataset-detail-view {
89
89
  dataset-detail-view .name, dataset-organization .name {
90
90
  font-size:1rem;
91
91
  line-height:1.4;
92
- color:#999999;
92
+ color:#555555;
93
93
  font-weight:normal;
94
94
  }
95
95
  dataset-organization .organization-header {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@urbanos/react-discovery-ui",
3
- "version": "2.1.50",
3
+ "version": "2.1.52",
4
4
  "description": "React component for dataset discovery UI",
5
5
  "main": "./lib/ReactDiscoveryUI.js",
6
6
  "repository": {