@hrforte/react-pivottable 1.0.0 → 1.0.1

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.
@@ -0,0 +1,1067 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+
7
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
8
+
9
+ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
10
+
11
+ exports.applyCellFormatting = applyCellFormatting;
12
+
13
+ var _react = require('react');
14
+
15
+ var _react2 = _interopRequireDefault(_react);
16
+
17
+ var _propTypes = require('prop-types');
18
+
19
+ var _propTypes2 = _interopRequireDefault(_propTypes);
20
+
21
+ var _Utilities = require('./Utilities');
22
+
23
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
24
+
25
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
26
+
27
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
28
+
29
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
30
+
31
+ function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
32
+
33
+ // helper function for setting row/col-span in pivotTableRenderer
34
+ var spanSize = function spanSize(arr, i, j) {
35
+ var x = void 0;
36
+ if (i !== 0) {
37
+ var asc = void 0,
38
+ end = void 0;
39
+ var noDraw = true;
40
+ for (x = 0, end = j, asc = end >= 0; asc ? x <= end : x >= end; asc ? x++ : x--) {
41
+ if (arr[i - 1][x] !== arr[i][x]) {
42
+ noDraw = false;
43
+ }
44
+ }
45
+ if (noDraw) {
46
+ return -1;
47
+ }
48
+ }
49
+ var len = 0;
50
+ while (i + len < arr.length) {
51
+ var asc1 = void 0,
52
+ end1 = void 0;
53
+ var stop = false;
54
+ for (x = 0, end1 = j, asc1 = end1 >= 0; asc1 ? x <= end1 : x >= end1; asc1 ? x++ : x--) {
55
+ if (arr[i][x] !== arr[i + len][x]) {
56
+ stop = true;
57
+ }
58
+ }
59
+ if (stop) {
60
+ break;
61
+ }
62
+ len++;
63
+ }
64
+ return len;
65
+ };
66
+
67
+ // ==> Calculate the positions for GroupSegments <==
68
+ function buildHeaderGroupSegments(rowAttrs, rowGroupConfig) {
69
+ var attrToGroup = {};
70
+ (rowGroupConfig || []).forEach(function (_ref) {
71
+ var label = _ref.label,
72
+ match = _ref.match;
73
+
74
+ match.forEach(function (name) {
75
+ attrToGroup[name] = label;
76
+ });
77
+ });
78
+
79
+ var segments = [];
80
+ rowAttrs.forEach(function (name) {
81
+ // eslint-disable-next-line no-undefined
82
+ var group = attrToGroup[name] !== undefined ? attrToGroup[name] : null;
83
+ var last = segments[segments.length - 1];
84
+ if (group !== null && last && last.group === group) {
85
+ last.span += 1;
86
+ } else {
87
+ segments.push({ group: group, span: 1 });
88
+ }
89
+ });
90
+ return segments;
91
+ }
92
+
93
+ // Style cho ô có nhãn nhóm trong group header
94
+ var groupLabelStyle = {
95
+ textAlign: 'center'
96
+ };
97
+
98
+ function redColorScaleGenerator(values) {
99
+ var min = Math.min.apply(Math, values);
100
+ var max = Math.max.apply(Math, values);
101
+ return function (x) {
102
+ // eslint-disable-next-line no-magic-numbers
103
+ var nonRed = 255 - Math.round(255 * (x - min) / (max - min));
104
+ return { backgroundColor: 'rgb(255,' + nonRed + ',' + nonRed + ')' };
105
+ };
106
+ }
107
+
108
+ // Conditional formatting evaluation function
109
+ function evaluateCondition(value, condition) {
110
+ if (!condition || !condition.type) {
111
+ return false;
112
+ }
113
+
114
+ var type = condition.type,
115
+ conditionValue = condition.value;
116
+
117
+ var numValue = typeof value === 'number' ? value : parseFloat(value);
118
+ var numConditionValue = typeof conditionValue === 'number' ? conditionValue : parseFloat(conditionValue);
119
+
120
+ switch (type) {
121
+ case 'greaterThan':
122
+ return !isNaN(numValue) && !isNaN(numConditionValue) && numValue > numConditionValue;
123
+ case 'lessThan':
124
+ return !isNaN(numValue) && !isNaN(numConditionValue) && numValue < numConditionValue;
125
+ case 'greaterThanOrEqual':
126
+ return !isNaN(numValue) && !isNaN(numConditionValue) && numValue >= numConditionValue;
127
+ case 'lessThanOrEqual':
128
+ return !isNaN(numValue) && !isNaN(numConditionValue) && numValue <= numConditionValue;
129
+ case 'equal':
130
+ if (typeof value === 'string' && typeof conditionValue === 'string') {
131
+ return value === conditionValue;
132
+ }
133
+ return !isNaN(numValue) && !isNaN(numConditionValue) && numValue === numConditionValue;
134
+ case 'notEqual':
135
+ if (typeof value === 'string' && typeof conditionValue === 'string') {
136
+ return value !== conditionValue;
137
+ }
138
+ return isNaN(numValue) || isNaN(numConditionValue) || numValue !== numConditionValue;
139
+ case 'empty':
140
+ // Check for null, undefined, empty string, whitespace-only strings, or NaN
141
+ if (value === null || value === undefined) {
142
+ return true;
143
+ }
144
+ if (typeof value === 'string') {
145
+ return value.trim() === '';
146
+ }
147
+ if (typeof value === 'number') {
148
+ return isNaN(value);
149
+ }
150
+ return false;
151
+ case 'notEmpty':
152
+ // Check that value is not null, undefined, empty/whitespace string, or NaN
153
+ if (value === null || value === undefined) {
154
+ return false;
155
+ }
156
+ if (typeof value === 'string') {
157
+ return value.trim() !== '';
158
+ }
159
+ if (typeof value === 'number') {
160
+ return !isNaN(value);
161
+ }
162
+ // Other types (boolean, object, etc.) are considered not empty
163
+ return true;
164
+ case 'contains':
165
+ // Convert both values to strings for comparison
166
+ // This handles cases where values are numbers (from aggregators) or conditionValue is parsed as number
167
+ var valueStr = String(value || '');
168
+ var conditionValueStr = String(conditionValue || '');
169
+ if (valueStr && conditionValueStr) {
170
+ return valueStr.toLowerCase().includes(conditionValueStr.toLowerCase());
171
+ }
172
+ return false;
173
+ case 'notContains':
174
+ // Convert both values to strings for comparison
175
+ // This handles cases where values are numbers (from aggregators) or conditionValue is parsed as number
176
+ var valueStr2 = String(value || '');
177
+ var conditionValueStr2 = String(conditionValue || '');
178
+ if (valueStr2 && conditionValueStr2) {
179
+ return !valueStr2.toLowerCase().includes(conditionValueStr2.toLowerCase());
180
+ }
181
+ return true;
182
+ default:
183
+ return false;
184
+ }
185
+ }
186
+
187
+ // Apply conditional formatting rules to a value
188
+ function getConditionalFormattingStyle(value, conditionalFormatting) {
189
+ if (!conditionalFormatting || !Array.isArray(conditionalFormatting.rules)) {
190
+ return {};
191
+ }
192
+
193
+ // Evaluate rules in order, return first matching rule's style
194
+ var _iteratorNormalCompletion = true;
195
+ var _didIteratorError = false;
196
+ var _iteratorError = undefined;
197
+
198
+ try {
199
+ for (var _iterator = conditionalFormatting.rules[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
200
+ var rule = _step.value;
201
+
202
+ if (evaluateCondition(value, rule.condition)) {
203
+ // Return a copy of the style object to avoid mutations
204
+ return rule.style ? Object.assign({}, rule.style) : {};
205
+ }
206
+ }
207
+ } catch (err) {
208
+ _didIteratorError = true;
209
+ _iteratorError = err;
210
+ } finally {
211
+ try {
212
+ if (!_iteratorNormalCompletion && _iterator.return) {
213
+ _iterator.return();
214
+ }
215
+ } finally {
216
+ if (_didIteratorError) {
217
+ throw _iteratorError;
218
+ }
219
+ }
220
+ }
221
+
222
+ return {};
223
+ }
224
+
225
+ // Merge styles, with conditional formatting taking precedence
226
+ function mergeStyles() {
227
+ for (var _len = arguments.length, styles = Array(_len), _key = 0; _key < _len; _key++) {
228
+ styles[_key] = arguments[_key];
229
+ }
230
+
231
+ return Object.assign.apply(Object, [{}].concat(_toConsumableArray(styles.filter(function (s) {
232
+ return s && (typeof s === 'undefined' ? 'undefined' : _typeof(s)) === 'object';
233
+ }))));
234
+ }
235
+
236
+ // Helper function to check if a string contains special characters (like -, /, etc.)
237
+ // This prevents formatting of date strings or formatted strings
238
+ // Only pure numeric strings (with optional decimal point and minus sign) should be formatted
239
+ function containsSpecialCharacters(str) {
240
+ if (typeof str !== 'string') {
241
+ return false;
242
+ }
243
+ var trimmed = str.trim();
244
+ // Check if string contains any special characters that indicate it's not a raw number
245
+ // Allow: digits, decimal point, minus sign at start, plus sign at start, spaces
246
+ // Disallow: hyphens in middle, slashes, and other special characters
247
+ var pureNumericPattern = /^-?\d*\.?\d+$/;
248
+ return !pureNumericPattern.test(trimmed);
249
+ }
250
+
251
+ // Helper function to check if an aggregation should skip formatting
252
+ // Aggregations like Count, First, Last should not be formatted
253
+ // Aggregations like Sum, Average should be formatted
254
+ function shouldSkipFormattingForAggregation(aggregatorName) {
255
+ if (!aggregatorName) {
256
+ return false;
257
+ }
258
+
259
+ var name = aggregatorName.toLowerCase();
260
+ // Skip formatting for these aggregation types
261
+ var skipFormattingAggregations = ['count', 'count unique values', 'list unique values', 'first', 'last', 'minimum', 'maximum'];
262
+ return skipFormattingAggregations.includes(name);
263
+ }
264
+
265
+ // Apply cell formatting rules to a value
266
+ function applyCellFormatting(value, cellFormatting, defaultFormatter) {
267
+ var aggregatorName = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
268
+
269
+ // Don't format if aggregation type should skip formatting (e.g., Count, First, Last)
270
+ // Only use defaultFormatter if value is numeric, otherwise return as-is
271
+ var isNumeric = typeof value === 'number' && !isNaN(value) && isFinite(value) || typeof value === 'string' && value.trim() !== '' && !containsSpecialCharacters(value) && !isNaN(parseFloat(value)) && isFinite(parseFloat(value));
272
+ if (shouldSkipFormattingForAggregation(aggregatorName)) {
273
+ if (isNumeric && defaultFormatter) {
274
+ return defaultFormatter(value);
275
+ }
276
+ // Return raw value for non-numeric values (dates, strings, etc.)
277
+ return value;
278
+ }
279
+
280
+ // If no cellFormatting rules, always use default formatter to return to original format
281
+ // This ensures values return to their original format when cellFormatting is cleared
282
+ // Check for all possible cases: null, undefined, empty object, empty rules array
283
+ var hasFormattingRules = cellFormatting && (typeof cellFormatting === 'undefined' ? 'undefined' : _typeof(cellFormatting)) === 'object' && Array.isArray(cellFormatting.rules) && cellFormatting.rules.length > 0 && cellFormatting.rules.some(function (rule) {
284
+ return rule && rule.format;
285
+ });
286
+
287
+ if (!hasFormattingRules) {
288
+ // When cellFormatting rules are cleared, return the raw value (not formatted)
289
+ // This ensures all cells (regular, Totals, Aggregation) return to their original unformatted state
290
+ // Return the raw numeric value for numbers, or the value as-is for other types
291
+ if (isNumeric) {
292
+ // Return raw numeric value without any formatting
293
+ if (typeof value === 'number') {
294
+ return value;
295
+ }
296
+ // For string numbers, return the parsed numeric value
297
+ return parseFloat(value);
298
+ }
299
+ // For non-numeric values (dates, strings, etc.), return as-is
300
+ return value;
301
+ }
302
+
303
+ // Don't format if it contains special characters (dates, formatted strings, etc.)
304
+ // Only check this when cellFormatting rules exist
305
+ if (containsSpecialCharacters(value)) {
306
+ return defaultFormatter ? defaultFormatter(value) : String(value);
307
+ }
308
+
309
+ // Check if value is a number - only apply custom formatting to raw numbers
310
+ // Handle both number type and string numbers (e.g., "123.45")
311
+ // Exclude strings with special characters from formatting
312
+ var numericValue = value;
313
+
314
+ // Convert string numbers to actual numbers for formatting
315
+ if (isNumeric && typeof value === 'string') {
316
+ numericValue = parseFloat(value);
317
+ }
318
+
319
+ // Use the first rule (all rules apply to all values)
320
+ var matchingRule = cellFormatting.rules[0];
321
+
322
+ // If we found a matching rule and value is numeric, apply its formatting
323
+ if (matchingRule && matchingRule.format && isNumeric) {
324
+ var format = matchingRule.format;
325
+ var formatter = (0, _Utilities.numberFormat)({
326
+ digitsAfterDecimal: 'decimalPlaces' in format ? format.decimalPlaces : 2,
327
+ thousandsSep: 'thousandsSep' in format ? format.thousandsSep : ',',
328
+ decimalSep: 'decimalSep' in format ? format.decimalSep : '.',
329
+ prefix: 'prefix' in format ? format.prefix : '',
330
+ suffix: 'suffix' in format ? format.suffix : '',
331
+ showOriginal: 'showOriginal' in format ? format.showOriginal : false
332
+ });
333
+ return formatter(numericValue);
334
+ }
335
+
336
+ // Not numeric or no matching rule, use default formatter
337
+ return defaultFormatter ? defaultFormatter(value) : String(value);
338
+ }
339
+
340
+ function makeRenderer() {
341
+ var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
342
+
343
+ var TableRenderer = function (_React$PureComponent) {
344
+ _inherits(TableRenderer, _React$PureComponent);
345
+
346
+ function TableRenderer() {
347
+ _classCallCheck(this, TableRenderer);
348
+
349
+ return _possibleConstructorReturn(this, (TableRenderer.__proto__ || Object.getPrototypeOf(TableRenderer)).apply(this, arguments));
350
+ }
351
+
352
+ _createClass(TableRenderer, [{
353
+ key: 'render',
354
+ value: function render() {
355
+ var _this2 = this;
356
+
357
+ var pivotData = new _Utilities.PivotData(this.props);
358
+ var colAttrs = pivotData.props.cols;
359
+ var rowAttrs = pivotData.props.rows;
360
+ var aggregations = pivotData.getAggregations();
361
+ var primaryAggregation = pivotData.getPrimaryAggregation();
362
+ var hasMultipleAggregators = aggregations.length > 1;
363
+ var tableOptions = this.props.tableOptions || {};
364
+ var aggregationDisplayMode = tableOptions.aggregationDisplayMode === 'column' ? 'column' : 'row';
365
+ var isColumnAggregationMode = aggregationDisplayMode === 'column' && hasMultipleAggregators;
366
+ var rowAttrsToRender = hasMultipleAggregators && !isColumnAggregationMode ? rowAttrs.concat(['Values']) : rowAttrs;
367
+ var colAttrsToRender = colAttrs;
368
+ var hasColumnAttributes = colAttrsToRender.length > 0;
369
+ var showTotalsColumn = !isColumnAggregationMode;
370
+ var shouldRenderRowHeaderPlaceholder = rowAttrsToRender.length !== 0;
371
+
372
+ // --- Row group header (rowGroupConfig) ---
373
+ var rowGroupConfig = this.props.rowGroupConfig;
374
+ var hasHeaderGroup = Boolean(rowGroupConfig && rowGroupConfig.length);
375
+ var headerGroupSegments = hasHeaderGroup ? buildHeaderGroupSegments(rowAttrs, rowGroupConfig) : [];
376
+ // extraSpan accounts for the synthetic "Values" column added when there
377
+ // are multiple aggregators shown as rows; it isn't part of any group.
378
+ var headerGroupExtraSpan = rowAttrsToRender.length - rowAttrs.length;
379
+ var renderGroupSegments = function renderGroupSegments(rowSpan) {
380
+ var extraSpan = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
381
+
382
+ var cells = headerGroupSegments.map(function (seg, idx) {
383
+ return _react2.default.createElement(
384
+ 'th',
385
+ {
386
+ key: 'hgSeg' + idx,
387
+ colSpan: seg.span,
388
+ rowSpan: rowSpan
389
+ // eslint-disable-next-line no-undefined
390
+ , style: seg.group ? groupLabelStyle : undefined
391
+ },
392
+ seg.group || ''
393
+ );
394
+ });
395
+ if (extraSpan > 0) {
396
+ cells.push(_react2.default.createElement('th', { key: 'hgSegExtra', colSpan: extraSpan, rowSpan: rowSpan }));
397
+ }
398
+ return cells;
399
+ };
400
+ // --- End row group header ---
401
+
402
+ var rowKeys = pivotData.getRowKeys();
403
+ var baseRowKeys = hasMultipleAggregators && !isColumnAggregationMode && rowKeys.length === 0 ? [[]] : rowKeys;
404
+ var renderedRows = hasMultipleAggregators && !isColumnAggregationMode ? baseRowKeys.reduce(function (acc, rowKey) {
405
+ aggregations.forEach(function (agg) {
406
+ acc.push({
407
+ displayKey: rowKey.concat([agg.label || agg.aggregatorName]),
408
+ actualKey: rowKey,
409
+ aggregationKey: agg.key
410
+ });
411
+ });
412
+ return acc;
413
+ }, []) : baseRowKeys.map(function (rowKey) {
414
+ return {
415
+ displayKey: rowKey,
416
+ actualKey: rowKey,
417
+ aggregationKey: primaryAggregation.key
418
+ };
419
+ });
420
+ var rowKeyValues = renderedRows.map(function (r) {
421
+ return r.displayKey;
422
+ });
423
+ var colKeys = pivotData.getColKeys();
424
+ var baseColKeys = isColumnAggregationMode && colKeys.length === 0 ? [[]] : colKeys;
425
+ var columnMeta = isColumnAggregationMode ? baseColKeys.reduce(function (acc, colKey) {
426
+ aggregations.forEach(function (agg) {
427
+ acc.push({
428
+ displayKey: colKey.concat([agg.label || agg.aggregatorName]),
429
+ actualKey: colKey,
430
+ aggregationKey: agg.key
431
+ });
432
+ });
433
+ return acc;
434
+ }, []) : colKeys.map(function (colKey) {
435
+ return {
436
+ displayKey: colKey,
437
+ actualKey: colKey,
438
+ aggregationKey: primaryAggregation.key
439
+ };
440
+ });
441
+ var colKeyValues = columnMeta.map(function (col) {
442
+ return col.displayKey;
443
+ });
444
+
445
+ var renderAggregatorHeaderCells = function renderAggregatorHeaderCells() {
446
+ return columnMeta.map(function (colMeta, idx) {
447
+ var label = colMeta.displayKey[colMeta.displayKey.length - 1] || '';
448
+ // Calculate colspan/rowspan so aggregator headers line up with column groups
449
+ // aggregator index is the last element in displayKey (after column attrs)
450
+ var aggIndex = colAttrsToRender.length;
451
+ // When there are column attributes, each aggregator should appear once per column group,
452
+ // so each aggregator header should have colSpan = 1.
453
+ // When there are no column attributes, use spanSize to merge identical aggregator labels.
454
+ var colSpan = void 0;
455
+ if (hasColumnAttributes) {
456
+ // Each aggregator appears once per column group, so colSpan is always 1
457
+ // This ensures aggregator headers are listed in each column group and align
458
+ // correctly with the column groups above (which have colSpan = number of aggregators)
459
+ colSpan = 1;
460
+ } else {
461
+ // Use spanSize to merge identical aggregator labels when there are no column attributes
462
+ colSpan = spanSize(colKeyValues, idx, aggIndex);
463
+ // If spanSize returned -1 it means this cell is merged into a previous one
464
+ if (colSpan === -1) {
465
+ return null;
466
+ }
467
+ }
468
+
469
+ // When there are column attributes, rowSpan should account for the row header row
470
+ // When there are no column attributes, rowSpan is 1
471
+ var rowSpan = hasColumnAttributes && rowAttrsToRender.length !== 0 ? 1 : 1;
472
+
473
+ return _react2.default.createElement(
474
+ 'th',
475
+ {
476
+ className: 'pvtColLabel',
477
+ key: 'agg-label-' + idx,
478
+ colSpan: colSpan,
479
+ rowSpan: rowSpan
480
+ },
481
+ label
482
+ );
483
+ });
484
+ };
485
+
486
+ var valueCellColors = function valueCellColors() {};
487
+ var rowTotalColors = function rowTotalColors() {};
488
+ var colTotalColors = function colTotalColors() {};
489
+ if (opts.heatmapMode && !hasMultipleAggregators) {
490
+ var colorScaleGenerator = this.props.tableColorScaleGenerator;
491
+ var rowTotalValues = colKeys.map(function (x) {
492
+ return pivotData.getAggregator([], x, primaryAggregation.key).value();
493
+ });
494
+ rowTotalColors = colorScaleGenerator(rowTotalValues);
495
+ var colTotalValues = rowKeys.map(function (x) {
496
+ return pivotData.getAggregator(x, [], primaryAggregation.key).value();
497
+ });
498
+ colTotalColors = colorScaleGenerator(colTotalValues);
499
+
500
+ if (opts.heatmapMode === 'full') {
501
+ var allValues = [];
502
+ rowKeys.map(function (r) {
503
+ return colKeys.map(function (c) {
504
+ return allValues.push(pivotData.getAggregator(r, c, primaryAggregation.key).value());
505
+ });
506
+ });
507
+ var colorScale = colorScaleGenerator(allValues);
508
+ valueCellColors = function valueCellColors(r, c, v) {
509
+ return colorScale(v);
510
+ };
511
+ } else if (opts.heatmapMode === 'row') {
512
+ var rowColorScales = {};
513
+ rowKeys.map(function (r) {
514
+ var rowValues = colKeys.map(function (x) {
515
+ return pivotData.getAggregator(r, x, primaryAggregation.key).value();
516
+ });
517
+ rowColorScales[r] = colorScaleGenerator(rowValues);
518
+ });
519
+ valueCellColors = function valueCellColors(r, c, v) {
520
+ return rowColorScales[r](v);
521
+ };
522
+ } else if (opts.heatmapMode === 'col') {
523
+ var colColorScales = {};
524
+ colKeys.map(function (c) {
525
+ var colValues = rowKeys.map(function (x) {
526
+ return pivotData.getAggregator(x, c, primaryAggregation.key).value();
527
+ });
528
+ colColorScales[c] = colorScaleGenerator(colValues);
529
+ });
530
+ valueCellColors = function valueCellColors(r, c, v) {
531
+ return colColorScales[c](v);
532
+ };
533
+ }
534
+ }
535
+
536
+ // Get conditional formatting from tableOptions
537
+ var conditionalFormatting = tableOptions.conditionalFormatting || null;
538
+
539
+ // Get cell formatting from tableOptions
540
+ var cellFormatting = tableOptions.cellFormatting || null;
541
+
542
+ // Create lookup map from aggregationKey to aggregatorName
543
+ var aggregationNameLookup = {};
544
+ aggregations.forEach(function (agg) {
545
+ aggregationNameLookup[agg.key] = agg.aggregatorName;
546
+ });
547
+
548
+ // Helper function to get cell style with conditional formatting
549
+ var getCellStyle = function getCellStyle(value) {
550
+ var heatmapStyle = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
551
+
552
+ var conditionalStyle = getConditionalFormattingStyle(value, conditionalFormatting);
553
+ return mergeStyles(heatmapStyle, conditionalStyle);
554
+ };
555
+
556
+ // Helper function to format cell value with cell formatting rules
557
+ var formatCellValue = function formatCellValue(value, aggregator, aggregationKey) {
558
+ var aggregatorName = aggregationKey ? aggregationNameLookup[aggregationKey] : null;
559
+
560
+ return applyCellFormatting(value, cellFormatting, aggregator.format.bind(aggregator), aggregatorName);
561
+ };
562
+
563
+ // Helper function to format label text if it's numeric
564
+ // Used for both row and column labels
565
+ var formatLabel = function formatLabel(txt) {
566
+ // Check if txt is numeric (number or numeric string)
567
+ // Also exclude 'null' string which is used for missing values
568
+ if (txt === 'null' || txt === null || typeof txt === 'undefined') {
569
+ return txt;
570
+ }
571
+
572
+ // Don't format if it contains special characters (dates, formatted strings, etc.)
573
+ if (containsSpecialCharacters(txt)) {
574
+ return txt;
575
+ }
576
+
577
+ // Check if txt is numeric (number or numeric string)
578
+ // A string is numeric if it can be parsed as a finite number
579
+ // Exclude strings with special characters from formatting
580
+ var isNumeric = false;
581
+ var numericValue = null;
582
+
583
+ if (typeof txt === 'number') {
584
+ isNumeric = !isNaN(txt) && isFinite(txt);
585
+ if (isNumeric) {
586
+ numericValue = txt;
587
+ }
588
+ } else if (typeof txt === 'string' && txt.trim() !== '' && txt !== 'null' && !containsSpecialCharacters(txt)) {
589
+ var parsed = parseFloat(txt.trim());
590
+ isNumeric = !isNaN(parsed) && isFinite(parsed);
591
+ if (isNumeric) {
592
+ numericValue = parsed;
593
+ }
594
+ }
595
+
596
+ if (isNumeric && numericValue !== null && cellFormatting && Array.isArray(cellFormatting.rules) && cellFormatting.rules.length > 0) {
597
+ var matchingRule = cellFormatting.rules[0];
598
+ if (matchingRule && matchingRule.format) {
599
+ var format = matchingRule.format;
600
+ var formatter = (0, _Utilities.numberFormat)({
601
+ digitsAfterDecimal: 'decimalPlaces' in format ? format.decimalPlaces : 2,
602
+ thousandsSep: 'thousandsSep' in format ? format.thousandsSep : ',',
603
+ decimalSep: 'decimalSep' in format ? format.decimalSep : '.',
604
+ prefix: 'prefix' in format ? format.prefix : '',
605
+ suffix: 'suffix' in format ? format.suffix : '',
606
+ showOriginal: 'showOriginal' in format ? format.showOriginal : false
607
+ });
608
+ return formatter(numericValue);
609
+ }
610
+ }
611
+
612
+ // Not numeric or no formatting rules, return as-is
613
+ return txt;
614
+ };
615
+
616
+ // Helper function to format row label text if it's numeric
617
+ // Only formats if it's a numeric value, not aggregation labels
618
+ var formatRowLabel = function formatRowLabel(txt, index, isLastElement, hasMultipleAggregators, rowAttrsLength) {
619
+ // Don't format the last element if it's an aggregation label (when multiple aggregators)
620
+ // The last element is an aggregation label only if:
621
+ // 1. There are multiple aggregators
622
+ // 2. AND it's beyond the row attributes (index >= rowAttrsLength)
623
+ if (hasMultipleAggregators && isLastElement && index >= rowAttrsLength) {
624
+ return txt;
625
+ }
626
+
627
+ return formatLabel(txt);
628
+ };
629
+
630
+ var getClickHandler = tableOptions && tableOptions.clickCallback ? function (value, rowValues, colValues) {
631
+ var filters = {};
632
+ var _iteratorNormalCompletion2 = true;
633
+ var _didIteratorError2 = false;
634
+ var _iteratorError2 = undefined;
635
+
636
+ try {
637
+ for (var _iterator2 = Object.keys(colAttrs || {})[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
638
+ var i = _step2.value;
639
+
640
+ var attr = colAttrs[i];
641
+ if (colValues[i] !== null) {
642
+ filters[attr] = colValues[i];
643
+ }
644
+ }
645
+ } catch (err) {
646
+ _didIteratorError2 = true;
647
+ _iteratorError2 = err;
648
+ } finally {
649
+ try {
650
+ if (!_iteratorNormalCompletion2 && _iterator2.return) {
651
+ _iterator2.return();
652
+ }
653
+ } finally {
654
+ if (_didIteratorError2) {
655
+ throw _iteratorError2;
656
+ }
657
+ }
658
+ }
659
+
660
+ var _iteratorNormalCompletion3 = true;
661
+ var _didIteratorError3 = false;
662
+ var _iteratorError3 = undefined;
663
+
664
+ try {
665
+ for (var _iterator3 = Object.keys(rowAttrs || {})[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
666
+ var _i = _step3.value;
667
+
668
+ var attr = rowAttrs[_i];
669
+ if (rowValues[_i] !== null) {
670
+ filters[attr] = rowValues[_i];
671
+ }
672
+ }
673
+ } catch (err) {
674
+ _didIteratorError3 = true;
675
+ _iteratorError3 = err;
676
+ } finally {
677
+ try {
678
+ if (!_iteratorNormalCompletion3 && _iterator3.return) {
679
+ _iterator3.return();
680
+ }
681
+ } finally {
682
+ if (_didIteratorError3) {
683
+ throw _iteratorError3;
684
+ }
685
+ }
686
+ }
687
+
688
+ return function (e) {
689
+ return tableOptions.clickCallback(e, value, filters, pivotData);
690
+ };
691
+ } : null;
692
+
693
+ var handleColSort = function handleColSort(attr, e) {
694
+ e.stopPropagation();
695
+ if (_this2.props.onColSort) {
696
+ var currentSort = _this2.props.colSorts && _this2.props.colSorts[attr];
697
+ var nextSort = 'ASC';
698
+ if (currentSort === 'ASC') {
699
+ nextSort = 'DESC';
700
+ } else if (currentSort === 'DESC') {
701
+ nextSort = null;
702
+ }
703
+ _this2.props.onColSort(attr, nextSort);
704
+ }
705
+ };
706
+
707
+ var handleRowSort = function handleRowSort(attr, e) {
708
+ e.stopPropagation();
709
+ if (_this2.props.onRowSort) {
710
+ var currentSort = _this2.props.rowSorts && _this2.props.rowSorts[attr];
711
+ var nextSort = 'ASC';
712
+ if (currentSort === 'ASC') {
713
+ nextSort = 'DESC';
714
+ } else if (currentSort === 'DESC') {
715
+ nextSort = null;
716
+ }
717
+ _this2.props.onRowSort(attr, nextSort);
718
+ }
719
+ };
720
+
721
+ var getSortButton = function getSortButton(attr, isCol) {
722
+ var currentSort = isCol ? _this2.props.colSorts && _this2.props.colSorts[attr] : _this2.props.rowSorts && _this2.props.rowSorts[attr];
723
+ var handleSort = isCol ? handleColSort : handleRowSort;
724
+ var sortIcon = '';
725
+ if (currentSort !== null) {
726
+ if (isCol) {
727
+ sortIcon = _this2.props.colSortIcons[currentSort] || _this2.props.colSortIcons.DEFAULT;
728
+ } else {
729
+ sortIcon = _this2.props.rowSortIcons[currentSort] || _this2.props.rowSortIcons.DEFAULT;
730
+ }
731
+ }
732
+ return _react2.default.createElement(
733
+ 'button',
734
+ {
735
+ type: 'button',
736
+ className: 'pvtSortButton',
737
+ onClick: function onClick(e) {
738
+ return handleSort(attr, e);
739
+ },
740
+ title: currentSort === 'ASC' ? 'Sort Descending' : currentSort === 'DESC' ? 'Clear Sort' : 'Sort Ascending'
741
+ },
742
+ sortIcon
743
+ );
744
+ };
745
+
746
+ var totalRowAggregations = isColumnAggregationMode ? [primaryAggregation] : hasMultipleAggregators ? aggregations : [primaryAggregation];
747
+ var totalsLabelText = 'Totals';
748
+
749
+ return _react2.default.createElement(
750
+ 'table',
751
+ { className: 'pvtTable' },
752
+ _react2.default.createElement(
753
+ 'thead',
754
+ null,
755
+ colAttrsToRender.map(function (c, j) {
756
+
757
+ return _react2.default.createElement(
758
+ 'tr',
759
+ { key: 'colAttr' + j },
760
+ shouldRenderRowHeaderPlaceholder && (isColumnAggregationMode || j === 0) && !(isColumnAggregationMode && hasColumnAttributes && rowAttrsToRender.length === 1) && (hasHeaderGroup && j === 0 && !isColumnAggregationMode ? renderGroupSegments(colAttrsToRender.length, headerGroupExtraSpan) : _react2.default.createElement('th', {
761
+ colSpan: isColumnAggregationMode && hasColumnAttributes ? rowAttrsToRender.length - 1 : rowAttrsToRender.length,
762
+ rowSpan: isColumnAggregationMode && hasColumnAttributes ? 1 : colAttrsToRender.length
763
+ })),
764
+ c ? _react2.default.createElement(
765
+ 'th',
766
+ { className: 'pvtAxisLabel' },
767
+ c,
768
+ colAttrs.includes(c) && getSortButton(c, true)
769
+ ) : null,
770
+ colKeyValues.map(function (colKey, i) {
771
+ var x = spanSize(colKeyValues, i, j);
772
+
773
+ if (x === -1) {
774
+ return null;
775
+ }
776
+
777
+ var formattedColLabel = formatLabel(colKey[j]);
778
+ return _react2.default.createElement(
779
+ 'th',
780
+ {
781
+ className: 'pvtColLabel',
782
+ key: 'colKey' + i,
783
+ colSpan: x,
784
+ rowSpan: j === colAttrsToRender.length - 1 && rowAttrsToRender.length !== 0 && !isColumnAggregationMode ? 2 : 1
785
+ },
786
+ formattedColLabel
787
+ );
788
+ }),
789
+ showTotalsColumn && j === 0 && _react2.default.createElement(
790
+ 'th',
791
+ {
792
+ className: 'pvtTotalLabel',
793
+ rowSpan: colAttrsToRender.length + (rowAttrsToRender.length === 0 ? 0 : 1)
794
+ },
795
+ totalsLabelText
796
+ )
797
+ );
798
+ }),
799
+ hasHeaderGroup && colAttrsToRender.length === 0 && rowAttrsToRender.length !== 0 && _react2.default.createElement(
800
+ 'tr',
801
+ null,
802
+ renderGroupSegments(1, headerGroupExtraSpan),
803
+ _react2.default.createElement('th', null)
804
+ ),
805
+ isColumnAggregationMode && hasColumnAttributes && _react2.default.createElement(
806
+ 'tr',
807
+ null,
808
+ rowAttrsToRender.length !== 0 && rowAttrsToRender.map(function (r, i) {
809
+ var isRowAttr = i < rowAttrs.length;
810
+ var attr = isRowAttr ? rowAttrs[i] : null;
811
+ return _react2.default.createElement(
812
+ 'th',
813
+ { className: 'pvtAxisLabel', key: 'rowAttr-agg-' + i },
814
+ r,
815
+ isRowAttr && attr && getSortButton(attr, false)
816
+ );
817
+ }),
818
+ renderAggregatorHeaderCells()
819
+ ),
820
+ rowAttrsToRender.length !== 0 && !(isColumnAggregationMode && hasColumnAttributes) && _react2.default.createElement(
821
+ 'tr',
822
+ null,
823
+ rowAttrsToRender.map(function (r, i) {
824
+ var isRowAttr = i < rowAttrs.length;
825
+ var attr = isRowAttr ? rowAttrs[i] : null;
826
+ return _react2.default.createElement(
827
+ 'th',
828
+ { className: 'pvtAxisLabel', key: 'rowAttr' + i },
829
+ r,
830
+ isRowAttr && attr && getSortButton(attr, false)
831
+ );
832
+ }),
833
+ isColumnAggregationMode && !hasColumnAttributes ? renderAggregatorHeaderCells() : null,
834
+ showTotalsColumn && _react2.default.createElement(
835
+ 'th',
836
+ { className: 'pvtTotalLabel' },
837
+ colAttrs.length === 0 ? totalsLabelText : null
838
+ )
839
+ )
840
+ ),
841
+ _react2.default.createElement(
842
+ 'tbody',
843
+ null,
844
+ renderedRows.map(function (rowMeta, i) {
845
+ var totalAggregator = pivotData.getAggregator(rowMeta.actualKey, [], rowMeta.aggregationKey);
846
+ var displayKey = rowMeta.displayKey;
847
+ return _react2.default.createElement(
848
+ 'tr',
849
+ { key: 'rowKeyRow' + i },
850
+ displayKey.map(function (txt, j) {
851
+ var x = spanSize(rowKeyValues, i, j);
852
+ if (x === -1) {
853
+ return null;
854
+ }
855
+ var isLastElement = j === displayKey.length - 1;
856
+ var formattedTxt = formatRowLabel(txt, j, isLastElement, hasMultipleAggregators, rowAttrs.length);
857
+ return _react2.default.createElement(
858
+ 'th',
859
+ {
860
+ key: 'rowKeyLabel' + i + '-' + j,
861
+ className: 'pvtRowLabel',
862
+ rowSpan: x,
863
+ colSpan: showTotalsColumn && j === rowAttrsToRender.length - 1 && colAttrsToRender.length !== 0 ? 2 : 1
864
+ },
865
+ formattedTxt
866
+ );
867
+ }),
868
+ columnMeta.map(function (colMeta, j) {
869
+ var aggregationKeyForCell = isColumnAggregationMode ? colMeta.aggregationKey : rowMeta.aggregationKey;
870
+ var aggregator = pivotData.getAggregator(rowMeta.actualKey, colMeta.actualKey, aggregationKeyForCell);
871
+ var value = aggregator.value();
872
+ var heatmapStyle = valueCellColors(rowMeta.actualKey, colMeta.actualKey, value) || {};
873
+ return _react2.default.createElement(
874
+ 'td',
875
+ {
876
+ className: 'pvtVal',
877
+ key: 'pvtVal' + i + '-' + j,
878
+ onClick: getClickHandler && getClickHandler(value, rowMeta.actualKey, colMeta.actualKey),
879
+ style: getCellStyle(value, heatmapStyle)
880
+ },
881
+ formatCellValue(value, aggregator, aggregationKeyForCell)
882
+ );
883
+ }),
884
+ showTotalsColumn && _react2.default.createElement(
885
+ 'td',
886
+ {
887
+ className: 'pvtTotal',
888
+ onClick: getClickHandler && getClickHandler(totalAggregator.value(), rowMeta.actualKey, [null]),
889
+ style: getCellStyle(totalAggregator.value(), colTotalColors(totalAggregator.value()) || {})
890
+ },
891
+ formatCellValue(totalAggregator.value(), totalAggregator, rowMeta.aggregationKey)
892
+ )
893
+ );
894
+ }),
895
+ totalRowAggregations.map(function (agg) {
896
+ var grandTotalAggregator = pivotData.getAggregator([], [], isColumnAggregationMode ? primaryAggregation.key : agg.key);
897
+ var totalLabel = hasMultipleAggregators && !isColumnAggregationMode ? 'Totals \u2013 ' + (agg.label || agg.aggregatorName) : totalsLabelText;
898
+ return _react2.default.createElement(
899
+ 'tr',
900
+ { key: 'totalRow-' + agg.key },
901
+ _react2.default.createElement(
902
+ 'th',
903
+ {
904
+ className: 'pvtTotalLabel',
905
+ colSpan: rowAttrsToRender.length + (colAttrs.length === 0 || isColumnAggregationMode && hasColumnAttributes ? 0 : 1)
906
+ },
907
+ totalLabel
908
+ ),
909
+ columnMeta.map(function (colMeta, i) {
910
+ var totalAggregator = pivotData.getAggregator([], colMeta.actualKey, isColumnAggregationMode ? colMeta.aggregationKey : agg.key);
911
+ var totalValue = totalAggregator.value();
912
+ return _react2.default.createElement(
913
+ 'td',
914
+ {
915
+ className: 'pvtTotal',
916
+ key: 'total' + agg.key + '-' + i,
917
+ onClick: getClickHandler && getClickHandler(totalValue, [null], colMeta.actualKey),
918
+ style: getCellStyle(totalValue, rowTotalColors(totalValue) || {})
919
+ },
920
+ formatCellValue(totalValue, totalAggregator, agg.key)
921
+ );
922
+ }),
923
+ showTotalsColumn && _react2.default.createElement(
924
+ 'td',
925
+ {
926
+ onClick: getClickHandler && getClickHandler(grandTotalAggregator.value(), [null], [null]),
927
+ className: 'pvtGrandTotal',
928
+ style: getCellStyle(grandTotalAggregator.value(), {})
929
+ },
930
+ formatCellValue(grandTotalAggregator.value(), grandTotalAggregator, isColumnAggregationMode ? primaryAggregation.key : agg.key)
931
+ )
932
+ );
933
+ })
934
+ )
935
+ );
936
+ }
937
+ }]);
938
+
939
+ return TableRenderer;
940
+ }(_react2.default.PureComponent);
941
+
942
+ TableRenderer.defaultProps = _Utilities.PivotData.defaultProps;
943
+ TableRenderer.propTypes = _Utilities.PivotData.propTypes;
944
+ TableRenderer.defaultProps.tableColorScaleGenerator = redColorScaleGenerator;
945
+ TableRenderer.defaultProps.tableOptions = {};
946
+ TableRenderer.defaultProps.colSorts = {};
947
+ TableRenderer.defaultProps.rowSorts = {};
948
+ TableRenderer.defaultProps.rowGroupConfig = null;
949
+ TableRenderer.propTypes.tableColorScaleGenerator = _propTypes2.default.func;
950
+ TableRenderer.propTypes.tableOptions = _propTypes2.default.object;
951
+ TableRenderer.propTypes.colSorts = _propTypes2.default.objectOf(_propTypes2.default.oneOf(['ASC', 'DESC']));
952
+ TableRenderer.propTypes.rowSorts = _propTypes2.default.objectOf(_propTypes2.default.oneOf(['ASC', 'DESC']));
953
+ TableRenderer.propTypes.onColSort = _propTypes2.default.func;
954
+ TableRenderer.propTypes.onRowSort = _propTypes2.default.func;
955
+ TableRenderer.propTypes.rowGroupConfig = _propTypes2.default.arrayOf(_propTypes2.default.shape({
956
+ label: _propTypes2.default.string.isRequired,
957
+ match: _propTypes2.default.arrayOf(_propTypes2.default.string).isRequired
958
+ }));
959
+ TableRenderer.defaultProps.colSortIcons = {
960
+ ASC: '→',
961
+ DESC: '←',
962
+ DEFAULT: '↔'
963
+ };
964
+ TableRenderer.defaultProps.rowSortIcons = {
965
+ ASC: '↑',
966
+ DESC: '↓',
967
+ DEFAULT: '⇅'
968
+ };
969
+ TableRenderer.propTypes.colSortIcons = _propTypes2.default.shape({
970
+ ASC: _propTypes2.default.node,
971
+ DESC: _propTypes2.default.node,
972
+ DEFAULT: _propTypes2.default.node
973
+ });
974
+ TableRenderer.propTypes.rowSortIcons = _propTypes2.default.shape({
975
+ ASC: _propTypes2.default.node,
976
+ DESC: _propTypes2.default.node,
977
+ DEFAULT: _propTypes2.default.node
978
+ });
979
+ return TableRenderer;
980
+ }
981
+
982
+ var TSVExportRenderer = function (_React$PureComponent2) {
983
+ _inherits(TSVExportRenderer, _React$PureComponent2);
984
+
985
+ function TSVExportRenderer() {
986
+ _classCallCheck(this, TSVExportRenderer);
987
+
988
+ return _possibleConstructorReturn(this, (TSVExportRenderer.__proto__ || Object.getPrototypeOf(TSVExportRenderer)).apply(this, arguments));
989
+ }
990
+
991
+ _createClass(TSVExportRenderer, [{
992
+ key: 'render',
993
+ value: function render() {
994
+ var pivotData = new _Utilities.PivotData(this.props);
995
+ var rowAttrs = pivotData.props.rows;
996
+ var aggregations = pivotData.getAggregations();
997
+ var hasMultipleAggregators = aggregations.length > 1;
998
+ var rowKeys = pivotData.getRowKeys();
999
+ var colKeys = pivotData.getColKeys();
1000
+ var safeRowKeys = rowKeys.length === 0 ? [[]] : rowKeys;
1001
+ var safeColKeys = colKeys.length === 0 ? [[]] : colKeys;
1002
+
1003
+ var rowEntries = hasMultipleAggregators ? safeRowKeys.reduce(function (acc, rowKey) {
1004
+ aggregations.forEach(function (agg) {
1005
+ acc.push({ rowKey: rowKey, aggregationKey: agg.key, label: agg.label });
1006
+ });
1007
+ return acc;
1008
+ }, []) : safeRowKeys.map(function (rowKey) {
1009
+ return {
1010
+ rowKey: rowKey,
1011
+ aggregationKey: aggregations[0].key,
1012
+ label: aggregations[0].label || aggregations[0].aggregatorName
1013
+ };
1014
+ });
1015
+
1016
+ var headerRow = rowAttrs.slice();
1017
+ if (hasMultipleAggregators) {
1018
+ headerRow.push('Values');
1019
+ }
1020
+ if (safeColKeys.length === 1 && safeColKeys[0].length === 0) {
1021
+ headerRow.push(hasMultipleAggregators ? 'Value' : aggregations[0].label || aggregations[0].aggregatorName);
1022
+ } else {
1023
+ safeColKeys.map(function (c) {
1024
+ return headerRow.push(c.join('-'));
1025
+ });
1026
+ }
1027
+
1028
+ var result = rowEntries.map(function (entry) {
1029
+ var row = entry.rowKey.map(function (x) {
1030
+ return x;
1031
+ });
1032
+ if (hasMultipleAggregators) {
1033
+ row.push(entry.label || '');
1034
+ }
1035
+ safeColKeys.map(function (colKey) {
1036
+ var v = pivotData.getAggregator(entry.rowKey, colKey, entry.aggregationKey).value();
1037
+ row.push(v ? v : '');
1038
+ });
1039
+ return row;
1040
+ });
1041
+
1042
+ result.unshift(headerRow);
1043
+
1044
+ return _react2.default.createElement('textarea', {
1045
+ value: result.map(function (r) {
1046
+ return r.join('\t');
1047
+ }).join('\n'),
1048
+ style: { width: window.innerWidth / 2, height: window.innerHeight / 2 },
1049
+ readOnly: true
1050
+ });
1051
+ }
1052
+ }]);
1053
+
1054
+ return TSVExportRenderer;
1055
+ }(_react2.default.PureComponent);
1056
+
1057
+ TSVExportRenderer.defaultProps = _Utilities.PivotData.defaultProps;
1058
+ TSVExportRenderer.propTypes = _Utilities.PivotData.propTypes;
1059
+
1060
+ exports.default = {
1061
+ Table: makeRenderer(),
1062
+ 'Table Heatmap': makeRenderer({ heatmapMode: 'full' }),
1063
+ 'Table Col Heatmap': makeRenderer({ heatmapMode: 'col' }),
1064
+ 'Table Row Heatmap': makeRenderer({ heatmapMode: 'row' }),
1065
+ 'Exportable TSV': TSVExportRenderer
1066
+ };
1067
+ //# sourceMappingURL=TableRenderers.js.map