@czi-sds/data-viz
Version:
2023 Science Initiative Data Visualization Component Library
1,256 lines (1,204 loc) • 996 kB
JavaScript
"use client";
'use strict';
var jsxRuntime = require('react/jsx-runtime');
var echarts = require('echarts');
var React = require('react');
var lodash = require('lodash');
var styled = require('@emotion/styled');
var _styled = require('@emotion/styled/base');
var react = require('@emotion/react');
var material = require('@mui/material');
require('@mui/icons-material');
var css$1 = require('@emotion/css');
var Button$2 = require('@mui/material/Button');
var styles = require('@mui/material/styles');
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
function _interopNamespace(e) {
if (e && e.__esModule) return e;
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n.default = e;
return Object.freeze(n);
}
var React__namespace = /*#__PURE__*/_interopNamespace(React);
var styled__default = /*#__PURE__*/_interopDefault(styled);
var _styled__default = /*#__PURE__*/_interopDefault(_styled);
var Button$2__default = /*#__PURE__*/_interopDefault(Button$2);
/******************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/* global Reflect, Promise, SuppressedError, Symbol, Iterator */
var __assign$1 = function() {
__assign$1 = Object.assign || function __assign(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
}
return t;
};
return __assign$1.apply(this, arguments);
};
function __rest(s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
}
function __spreadArray(to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
}
function __makeTemplateObject(cooked, raw) {
if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
return cooked;
}
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
var e = new Error(message);
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
};
var EMPTY_OBJECT$1 = {};
var DEFAULT_ITEM_STYLE = {
color: function () {
return "rgb(0, 0, 0)";
},
};
function createChartOptions(props) {
var axisPointer = props.axisPointer, camera = props.camera, data = props.data, dataZoom = props.dataZoom, emphasis = props.emphasis, encode = props.encode, gridProp = props.grid, _a = props.itemStyle, itemStyle = _a === void 0 ? DEFAULT_ITEM_STYLE : _a, options = props.options, symbolSize = props.symbolSize, _b = props.symbol, symbol = _b === void 0 ? "rect" : _b;
var _c = generateDefaultValues(props), defaultAxisPointer = _c.defaultAxisPointer, defaultDataZoom = _c.defaultDataZoom, defaultEmphasis = _c.defaultEmphasis, defaultGrid = _c.defaultGrid, defaultXAxis = _c.defaultXAxis, defaultYAxis = _c.defaultYAxis;
var customGrid = typeof gridProp === "function" ? gridProp(defaultGrid) : gridProp;
var _d = options || {}, optionsAxisPointer = _d.axisPointer, optionsDataZoom = _d.dataZoom, optionsSeries = _d.series, optionsXAxis = _d.xAxis, optionsYAxis = _d.yAxis, optionsRest = __rest(_d, ["axisPointer", "dataZoom", "series", "xAxis", "yAxis"]);
return __assign$1({ animation: false, axisPointer: mergeAxisPointer(defaultAxisPointer, axisPointer, optionsAxisPointer), dataZoom: (camera === null || camera === void 0 ? void 0 : camera.active)
? mergeDataZoom(defaultDataZoom, dataZoom, optionsDataZoom)
: [], dataset: {
source: data,
}, grid: customGrid || defaultGrid, series: [
Object.assign({
emphasis: Object.assign(defaultEmphasis, emphasis),
encode: encode,
itemStyle: itemStyle,
legendHoverLink: false,
symbol: symbol,
symbolSize: symbolSize,
}, optionsSeries
? Array.isArray(optionsSeries)
? optionsSeries[0]
: optionsSeries
: [], { symbol: symbol, type: "scatter" }),
], xAxis: [
Object.assign(defaultXAxis, optionsXAxis
? Array.isArray(optionsXAxis)
? optionsXAxis[0]
: optionsXAxis
: {}),
], yAxis: [
Object.assign(defaultYAxis, optionsYAxis
? Array.isArray(optionsYAxis)
? optionsYAxis[0]
: optionsYAxis
: {}),
] }, optionsRest);
}
function mergeAxisPointer(defaultAxisPointer, axisPointer, optionsAxisPointer) {
var finalAxisPointer = Array.isArray(axisPointer)
? axisPointer // if it's an array, assume that the user has [{...propsToChangeOnX}] OR [ , {...propsToChangeOnY}] OR [{...propsToChangeOnX}, {...propsToChangeOnY}]
: [axisPointer, axisPointer]; // else if the user only supplies one AxisPointer object, we assume they want the props to apply to both x and y axisPointer objects
var finalOptionsAxisPointer = Array.isArray(optionsAxisPointer)
? optionsAxisPointer
: [optionsAxisPointer, optionsAxisPointer];
// merge x axisPointer options
var x = __assign$1(__assign$1(__assign$1({}, defaultAxisPointer), finalAxisPointer[0]), finalOptionsAxisPointer === null || finalOptionsAxisPointer === void 0 ? void 0 : finalOptionsAxisPointer[0]);
// merge y axisPointer options
var y = __assign$1(__assign$1(__assign$1({}, defaultAxisPointer), finalAxisPointer[1]), finalOptionsAxisPointer[1]);
return [x, y];
}
function mergeDataZoom(defaultDataZoom, dataZoom, optionsDataZoom) {
var finalDataZoom = Array.isArray(dataZoom)
? dataZoom // if it's an array, assume that the user has [{...propsToChangeOnX}] OR [ , {...propsToChangeOnY}] OR [{...propsToChangeOnX}, {...propsToChangeOnY}]
: [dataZoom, dataZoom]; // else if the user only supplies one dataZoom object, we assume they want the props to apply to both x and y zoom objects
var finalOptionsDataZoom = Array.isArray(optionsDataZoom)
? optionsDataZoom
: [optionsDataZoom, optionsDataZoom];
// merge x dataZoom options
var x = __assign$1(__assign$1(__assign$1({}, defaultDataZoom[0]), finalDataZoom[0]), finalOptionsDataZoom === null || finalOptionsDataZoom === void 0 ? void 0 : finalOptionsDataZoom[0]);
// merge y dataZoom options
var y = __assign$1(__assign$1(__assign$1({}, defaultDataZoom[1]), finalDataZoom[1]), finalOptionsDataZoom[1]);
return [x, y];
}
function generateDefaultValues(props) {
var camera = props.camera, height = props.height, symbol = props.symbol, width = props.width, xAxisData = props.xAxisData, yAxisData = props.yAxisData;
var defaultGrid = {
height: "".concat(height, "px"),
left: 0,
top: 0,
// (atarashansky): this is the key change to align x and y axis
// labels to fixed spaces
width: "".concat(width, "px"),
};
var defaultAxisPointer = {
label: { show: false },
show: false,
triggerOn: "mousemove",
};
var defaultXAxis = {
axisLabel: { fontSize: 0, rotate: 90 },
axisLine: {
show: false,
},
axisTick: {
show: false,
},
boundaryGap: true,
data: xAxisData,
splitLine: {
show: false,
},
type: "category",
};
var defaultYAxis = {
axisLabel: { fontSize: 0 },
axisLine: {
show: false,
},
axisTick: {
show: false,
},
boundaryGap: true,
data: yAxisData,
splitLine: {
show: false,
},
};
var defaultEmphasis = {
itemStyle: {
borderColor: symbol === "circle" ? "black" : "white",
borderType: "solid",
borderWidth: symbol === "circle" ? 2 : 4,
opacity: 1,
},
scale: false,
};
var defaultCamera = {
height: camera && camera.height ? camera.height : 20,
width: camera && camera.width ? camera.width : 40,
};
var defaultDataZoom = [
{
// end index of the x axis window
endValue: defaultCamera.width - 1,
filterMode: "filter",
moveOnMouseMove: true,
// There's a PR to allow touchpad panning
// https://github.com/apache/echarts/pull/19352
moveOnMouseWheel: false,
orient: "horizontal",
preventDefaultMouseMove: true,
// start index of the x axis window
startValue: 0,
throttle: 0,
type: "inside",
xAxisIndex: 0,
zoomOnMouseWheel: false,
},
{
// end index of the y axis window
endValue: defaultCamera.height - 1,
filterMode: "filter",
moveOnMouseMove: true,
moveOnMouseWheel: true,
orient: "vertical",
preventDefaultMouseMove: true,
// start index of the y axis window
startValue: 0,
throttle: 0,
type: "inside",
yAxisIndex: 0,
zoomOnMouseWheel: false,
},
];
return {
defaultAxisPointer: defaultAxisPointer,
defaultDataZoom: defaultDataZoom,
defaultEmphasis: defaultEmphasis,
defaultGrid: defaultGrid,
defaultXAxis: defaultXAxis,
defaultYAxis: defaultYAxis,
};
}
var UPDATE_THROTTLE_MS = 1 * 100;
function useUpdateChart(_a) {
var axisPointer = _a.axisPointer, camera = _a.camera, chart = _a.chart, data = _a.data, emphasis = _a.emphasis, xAxisData = _a.xAxisData, yAxisData = _a.yAxisData, width = _a.width, height = _a.height, encode = _a.encode, itemStyle = _a.itemStyle, symbol = _a.symbol, symbolSize = _a.symbolSize, grid = _a.grid, options = _a.options, onEvents = _a.onEvents;
var throttledUpdateChart = React.useMemo(function () {
return lodash.throttle(function () {
if (!chart || !data || !xAxisData || !yAxisData) {
return;
}
// (thuang): resize() needs to be called before setOption() to prevent
// TypeError: Cannot read properties of undefined (reading 'shouldBePainted')
chart.resize();
var chartOptions = createChartOptions({
axisPointer: axisPointer,
camera: camera,
data: data,
emphasis: emphasis,
encode: encode,
grid: grid,
height: height,
itemStyle: itemStyle,
options: options,
symbol: symbol,
symbolSize: symbolSize,
width: width,
xAxisData: xAxisData,
yAxisData: yAxisData,
});
chart.setOption(chartOptions, {
replaceMerge: ["dataZoom", "tooltip"],
});
/**
* We need to remove old event listeners and bind new ones to
* make sure that the event listeners are updated when the props change.
*/
if (onEvents) {
var _loop_1 = function (eventName) {
if (Object.prototype.hasOwnProperty.call(onEvents, eventName) &&
typeof eventName === "string" &&
typeof onEvents[eventName] === "function") {
// Remove old event listener
chart.off(eventName);
// Add new event listener
chart.on(eventName, function (event) {
onEvents[eventName](event, chart);
});
}
};
for (var eventName in onEvents) {
_loop_1(eventName);
}
}
}, UPDATE_THROTTLE_MS,
// (thuang): Trailing guarantees that the last call to the function will
// be executed
{ trailing: true });
}, [
axisPointer,
camera,
chart,
data,
emphasis,
xAxisData,
yAxisData,
width,
height,
encode,
itemStyle,
symbol,
symbolSize,
grid,
options,
onEvents,
]);
React.useEffect(function () {
return function () { return throttledUpdateChart.cancel(); };
}, [throttledUpdateChart]);
// Update the charts
React.useEffect(function () {
throttledUpdateChart();
}, [
axisPointer,
camera,
chart,
data,
emphasis,
xAxisData,
yAxisData,
throttledUpdateChart,
width,
height,
encode,
itemStyle,
symbol,
symbolSize,
grid,
options,
onEvents,
]);
}
var ChartContainer = styled__default.default("div")(templateObject_1$1 || (templateObject_1$1 = __makeTemplateObject(["\n ", "\n"], ["\n ", "\n"])), getWidthAndHeight);
function getWidthAndHeight(_a) {
var width = _a.width, height = _a.height;
return "\n width: ".concat(width, "px;\n height: ").concat(height, "px;\n ");
}
var templateObject_1$1;
var HeatmapChart = React.forwardRef(function (props, ref
// eslint-disable-next-line sonarjs/cognitive-complexity
) {
var axisPointer = props.axisPointer, width = props.width, height = props.height, _a = props.echartsRendererMode, echartsRendererMode = _a === void 0 ? "svg" : _a, camera = props.camera, onEvents = props.onEvents, xAxisData = props.xAxisData, yAxisData = props.yAxisData, data = props.data, encode = props.encode, emphasis = props.emphasis, itemStyle = props.itemStyle, symbol = props.symbol, _b = props.symbolSize, symbolSize = _b === void 0 ? 5 : _b, grid = props.grid, options = props.options, rest = __rest(props, ["axisPointer", "width", "height", "echartsRendererMode", "camera", "onEvents", "xAxisData", "yAxisData", "data", "encode", "emphasis", "itemStyle", "symbol", "symbolSize", "grid", "options"]);
// Validate width and height
if (!width || !height) {
throw Error("Heatmap must have width and height bigger than Zero!");
}
// Ref for the chart container
var innerRef = React.useRef(null);
/**
* (thuang): We need both a state and a ref to store the chart instance, so
* some hooks can opt out of re-rendering when the chart instance changes.
*/
var _c = React.useState(null), chart = _c[0], setChart = _c[1];
var chartRef = React.useRef(chart);
/**
* (thuang): Use this ref to store the onEvents prop to prevent
* unnecessary re-renders when the onEvents prop changes.
* NOTE: This implies that `onEvents` prop changes alone from the parent
* won't re-render the chart
*/
var onEventsRef = React.useRef(onEvents);
/**
* (thuang): Use this function to dispose the chart instance for both
* the state and the ref. This is to prevent memory leaks.
*/
var disposeChart = React.useCallback(function () {
var _a;
(_a = chartRef.current) === null || _a === void 0 ? void 0 : _a.dispose();
chartRef.current = null;
setChart(null);
}, []);
// Function to initialize the chart
var initChart = React.useCallback(function () {
var onEventsCurrent = onEventsRef.current;
var current = innerRef.current;
if (!current ||
chartRef.current ||
// (thuang): echart's `init()` will throw error if the container has 0 width or height
(current === null || current === void 0 ? void 0 : current.getAttribute("height")) === "0" ||
(current === null || current === void 0 ? void 0 : current.getAttribute("width")) === "0") {
return;
}
// Initialize ECharts instance
var rawChart = echarts.init(current, EMPTY_OBJECT$1, {
renderer: echartsRendererMode,
useDirtyRect: true,
});
// Bind events if provided
if (onEventsCurrent) {
bindEvents(rawChart, onEventsCurrent);
}
setChart(rawChart);
chartRef.current = rawChart;
// Cleanup function
return function () {
disposeChart();
// Unbind events if provided
if (onEventsCurrent) {
for (var eventName in onEventsCurrent) {
if (Object.prototype.hasOwnProperty.call(onEventsCurrent, eventName) &&
typeof eventName === "string" &&
typeof onEventsCurrent[eventName] === "function") {
rawChart.off(eventName, onEventsCurrent[eventName]);
}
}
}
};
}, [echartsRendererMode, disposeChart]);
// Initialize charts on component mount
React.useEffect(function () {
disposeChart();
initChart();
}, [initChart, disposeChart]);
// Hook to update chart data and options
useUpdateChart({
axisPointer: axisPointer,
camera: camera,
chart: chart,
data: data,
emphasis: emphasis,
encode: encode,
grid: grid,
height: height,
itemStyle: itemStyle,
onEvents: onEvents,
options: options,
symbol: symbol,
symbolSize: symbolSize,
width: width,
xAxisData: xAxisData,
yAxisData: yAxisData,
});
// Render the chart container
return (jsxRuntime.jsx(ChartContainer, __assign$1({ height: height, width: width, ref: handleRef }, rest)));
// Function to bind events to the ECharts instance
function bindEvents(instance, events) {
function innerBindEvent(eventName, func) {
// Ignore invalid event configurations
if (typeof eventName === "string" && typeof func === "function") {
// Bind event
instance.on(eventName, function (param) {
func(param, instance);
});
}
}
// Loop through events and bind them
for (var eventName in events) {
if (Object.prototype.hasOwnProperty.call(events, eventName)) {
innerBindEvent(eventName, events[eventName]);
}
}
}
// Function to handle the ref of the chart container
function handleRef(element) {
innerRef.current = element;
if (!ref)
return;
// (thuang): `ref` from `forwardRef` can be a function or a ref object
if (typeof ref === "function") {
ref(element);
}
else {
ref.current = element;
}
}
});
var index$1 = React.memo(HeatmapChart);
/**
* table-core
*
* Copyright (c) TanStack
*
* This source code is licensed under the MIT license found in the
* LICENSE.md file in the root directory of this source tree.
*
* @license MIT
*/
// type Person = {
// firstName: string
// lastName: string
// age: number
// visits: number
// status: string
// progress: number
// createdAt: Date
// nested: {
// foo: [
// {
// bar: 'bar'
// }
// ]
// bar: { subBar: boolean }[]
// baz: {
// foo: 'foo'
// bar: {
// baz: 'baz'
// }
// }
// }
// }
// Is this type a tuple?
// If this type is a tuple, what indices are allowed?
///
function functionalUpdate(updater, input) {
return typeof updater === 'function' ? updater(input) : updater;
}
function makeStateUpdater(key, instance) {
return updater => {
instance.setState(old => {
return {
...old,
[key]: functionalUpdate(updater, old[key])
};
});
};
}
function isFunction(d) {
return d instanceof Function;
}
function isNumberArray(d) {
return Array.isArray(d) && d.every(val => typeof val === 'number');
}
function flattenBy(arr, getChildren) {
const flat = [];
const recurse = subArr => {
subArr.forEach(item => {
flat.push(item);
const children = getChildren(item);
if (children != null && children.length) {
recurse(children);
}
});
};
recurse(arr);
return flat;
}
function memo(getDeps, fn, opts) {
let deps = [];
let result;
return depArgs => {
let depTime;
if (opts.key && opts.debug) depTime = Date.now();
const newDeps = getDeps(depArgs);
const depsChanged = newDeps.length !== deps.length || newDeps.some((dep, index) => deps[index] !== dep);
if (!depsChanged) {
return result;
}
deps = newDeps;
let resultTime;
if (opts.key && opts.debug) resultTime = Date.now();
result = fn(...newDeps);
opts == null || opts.onChange == null || opts.onChange(result);
if (opts.key && opts.debug) {
if (opts != null && opts.debug()) {
const depEndTime = Math.round((Date.now() - depTime) * 100) / 100;
const resultEndTime = Math.round((Date.now() - resultTime) * 100) / 100;
const resultFpsPercentage = resultEndTime / 16;
const pad = (str, num) => {
str = String(str);
while (str.length < num) {
str = ' ' + str;
}
return str;
};
console.info(`%c⏱ ${pad(resultEndTime, 5)} /${pad(depEndTime, 5)} ms`, `
font-size: .6rem;
font-weight: bold;
color: hsl(${Math.max(0, Math.min(120 - 120 * resultFpsPercentage, 120))}deg 100% 31%);`, opts == null ? void 0 : opts.key);
}
}
return result;
};
}
function getMemoOptions(tableOptions, debugLevel, key, onChange) {
return {
debug: () => {
var _tableOptions$debugAl;
return (_tableOptions$debugAl = tableOptions == null ? void 0 : tableOptions.debugAll) != null ? _tableOptions$debugAl : tableOptions[debugLevel];
},
key: process.env.NODE_ENV === 'development' && key,
onChange
};
}
function createCell(table, row, column, columnId) {
const getRenderValue = () => {
var _cell$getValue;
return (_cell$getValue = cell.getValue()) != null ? _cell$getValue : table.options.renderFallbackValue;
};
const cell = {
id: `${row.id}_${column.id}`,
row,
column,
getValue: () => row.getValue(columnId),
renderValue: getRenderValue,
getContext: memo(() => [table, column, row, cell], (table, column, row, cell) => ({
table,
column,
row,
cell: cell,
getValue: cell.getValue,
renderValue: cell.renderValue
}), getMemoOptions(table.options, 'debugCells', 'cell.getContext'))
};
table._features.forEach(feature => {
feature.createCell == null || feature.createCell(cell, column, row, table);
}, {});
return cell;
}
function createColumn(table, columnDef, depth, parent) {
var _ref, _resolvedColumnDef$id;
const defaultColumn = table._getDefaultColumnDef();
const resolvedColumnDef = {
...defaultColumn,
...columnDef
};
const accessorKey = resolvedColumnDef.accessorKey;
let id = (_ref = (_resolvedColumnDef$id = resolvedColumnDef.id) != null ? _resolvedColumnDef$id : accessorKey ? typeof String.prototype.replaceAll === 'function' ? accessorKey.replaceAll('.', '_') : accessorKey.replace(/\./g, '_') : undefined) != null ? _ref : typeof resolvedColumnDef.header === 'string' ? resolvedColumnDef.header : undefined;
let accessorFn;
if (resolvedColumnDef.accessorFn) {
accessorFn = resolvedColumnDef.accessorFn;
} else if (accessorKey) {
// Support deep accessor keys
if (accessorKey.includes('.')) {
accessorFn = originalRow => {
let result = originalRow;
for (const key of accessorKey.split('.')) {
var _result;
result = (_result = result) == null ? void 0 : _result[key];
if (process.env.NODE_ENV !== 'production' && result === undefined) {
console.warn(`"${key}" in deeply nested key "${accessorKey}" returned undefined.`);
}
}
return result;
};
} else {
accessorFn = originalRow => originalRow[resolvedColumnDef.accessorKey];
}
}
if (!id) {
if (process.env.NODE_ENV !== 'production') {
throw new Error(resolvedColumnDef.accessorFn ? `Columns require an id when using an accessorFn` : `Columns require an id when using a non-string header`);
}
throw new Error();
}
let column = {
id: `${String(id)}`,
accessorFn,
parent: parent,
depth,
columnDef: resolvedColumnDef,
columns: [],
getFlatColumns: memo(() => [true], () => {
var _column$columns;
return [column, ...((_column$columns = column.columns) == null ? void 0 : _column$columns.flatMap(d => d.getFlatColumns()))];
}, getMemoOptions(table.options, 'debugColumns', 'column.getFlatColumns')),
getLeafColumns: memo(() => [table._getOrderColumnsFn()], orderColumns => {
var _column$columns2;
if ((_column$columns2 = column.columns) != null && _column$columns2.length) {
let leafColumns = column.columns.flatMap(column => column.getLeafColumns());
return orderColumns(leafColumns);
}
return [column];
}, getMemoOptions(table.options, 'debugColumns', 'column.getLeafColumns'))
};
for (const feature of table._features) {
feature.createColumn == null || feature.createColumn(column, table);
}
// Yes, we have to convert table to unknown, because we know more than the compiler here.
return column;
}
const debug = 'debugHeaders';
//
function createHeader(table, column, options) {
var _options$id;
const id = (_options$id = options.id) != null ? _options$id : column.id;
let header = {
id,
column,
index: options.index,
isPlaceholder: !!options.isPlaceholder,
placeholderId: options.placeholderId,
depth: options.depth,
subHeaders: [],
colSpan: 0,
rowSpan: 0,
headerGroup: null,
getLeafHeaders: () => {
const leafHeaders = [];
const recurseHeader = h => {
if (h.subHeaders && h.subHeaders.length) {
h.subHeaders.map(recurseHeader);
}
leafHeaders.push(h);
};
recurseHeader(header);
return leafHeaders;
},
getContext: () => ({
table,
header: header,
column
})
};
table._features.forEach(feature => {
feature.createHeader == null || feature.createHeader(header, table);
});
return header;
}
const Headers = {
createTable: table => {
// Header Groups
table.getHeaderGroups = memo(() => [table.getAllColumns(), table.getVisibleLeafColumns(), table.getState().columnPinning.left, table.getState().columnPinning.right], (allColumns, leafColumns, left, right) => {
var _left$map$filter, _right$map$filter;
const leftColumns = (_left$map$filter = left == null ? void 0 : left.map(columnId => leafColumns.find(d => d.id === columnId)).filter(Boolean)) != null ? _left$map$filter : [];
const rightColumns = (_right$map$filter = right == null ? void 0 : right.map(columnId => leafColumns.find(d => d.id === columnId)).filter(Boolean)) != null ? _right$map$filter : [];
const centerColumns = leafColumns.filter(column => !(left != null && left.includes(column.id)) && !(right != null && right.includes(column.id)));
const headerGroups = buildHeaderGroups(allColumns, [...leftColumns, ...centerColumns, ...rightColumns], table);
return headerGroups;
}, getMemoOptions(table.options, debug, 'getHeaderGroups'));
table.getCenterHeaderGroups = memo(() => [table.getAllColumns(), table.getVisibleLeafColumns(), table.getState().columnPinning.left, table.getState().columnPinning.right], (allColumns, leafColumns, left, right) => {
leafColumns = leafColumns.filter(column => !(left != null && left.includes(column.id)) && !(right != null && right.includes(column.id)));
return buildHeaderGroups(allColumns, leafColumns, table, 'center');
}, getMemoOptions(table.options, debug, 'getCenterHeaderGroups'));
table.getLeftHeaderGroups = memo(() => [table.getAllColumns(), table.getVisibleLeafColumns(), table.getState().columnPinning.left], (allColumns, leafColumns, left) => {
var _left$map$filter2;
const orderedLeafColumns = (_left$map$filter2 = left == null ? void 0 : left.map(columnId => leafColumns.find(d => d.id === columnId)).filter(Boolean)) != null ? _left$map$filter2 : [];
return buildHeaderGroups(allColumns, orderedLeafColumns, table, 'left');
}, getMemoOptions(table.options, debug, 'getLeftHeaderGroups'));
table.getRightHeaderGroups = memo(() => [table.getAllColumns(), table.getVisibleLeafColumns(), table.getState().columnPinning.right], (allColumns, leafColumns, right) => {
var _right$map$filter2;
const orderedLeafColumns = (_right$map$filter2 = right == null ? void 0 : right.map(columnId => leafColumns.find(d => d.id === columnId)).filter(Boolean)) != null ? _right$map$filter2 : [];
return buildHeaderGroups(allColumns, orderedLeafColumns, table, 'right');
}, getMemoOptions(table.options, debug, 'getRightHeaderGroups'));
// Footer Groups
table.getFooterGroups = memo(() => [table.getHeaderGroups()], headerGroups => {
return [...headerGroups].reverse();
}, getMemoOptions(table.options, debug, 'getFooterGroups'));
table.getLeftFooterGroups = memo(() => [table.getLeftHeaderGroups()], headerGroups => {
return [...headerGroups].reverse();
}, getMemoOptions(table.options, debug, 'getLeftFooterGroups'));
table.getCenterFooterGroups = memo(() => [table.getCenterHeaderGroups()], headerGroups => {
return [...headerGroups].reverse();
}, getMemoOptions(table.options, debug, 'getCenterFooterGroups'));
table.getRightFooterGroups = memo(() => [table.getRightHeaderGroups()], headerGroups => {
return [...headerGroups].reverse();
}, getMemoOptions(table.options, debug, 'getRightFooterGroups'));
// Flat Headers
table.getFlatHeaders = memo(() => [table.getHeaderGroups()], headerGroups => {
return headerGroups.map(headerGroup => {
return headerGroup.headers;
}).flat();
}, getMemoOptions(table.options, debug, 'getFlatHeaders'));
table.getLeftFlatHeaders = memo(() => [table.getLeftHeaderGroups()], left => {
return left.map(headerGroup => {
return headerGroup.headers;
}).flat();
}, getMemoOptions(table.options, debug, 'getLeftFlatHeaders'));
table.getCenterFlatHeaders = memo(() => [table.getCenterHeaderGroups()], left => {
return left.map(headerGroup => {
return headerGroup.headers;
}).flat();
}, getMemoOptions(table.options, debug, 'getCenterFlatHeaders'));
table.getRightFlatHeaders = memo(() => [table.getRightHeaderGroups()], left => {
return left.map(headerGroup => {
return headerGroup.headers;
}).flat();
}, getMemoOptions(table.options, debug, 'getRightFlatHeaders'));
// Leaf Headers
table.getCenterLeafHeaders = memo(() => [table.getCenterFlatHeaders()], flatHeaders => {
return flatHeaders.filter(header => {
var _header$subHeaders;
return !((_header$subHeaders = header.subHeaders) != null && _header$subHeaders.length);
});
}, getMemoOptions(table.options, debug, 'getCenterLeafHeaders'));
table.getLeftLeafHeaders = memo(() => [table.getLeftFlatHeaders()], flatHeaders => {
return flatHeaders.filter(header => {
var _header$subHeaders2;
return !((_header$subHeaders2 = header.subHeaders) != null && _header$subHeaders2.length);
});
}, getMemoOptions(table.options, debug, 'getLeftLeafHeaders'));
table.getRightLeafHeaders = memo(() => [table.getRightFlatHeaders()], flatHeaders => {
return flatHeaders.filter(header => {
var _header$subHeaders3;
return !((_header$subHeaders3 = header.subHeaders) != null && _header$subHeaders3.length);
});
}, getMemoOptions(table.options, debug, 'getRightLeafHeaders'));
table.getLeafHeaders = memo(() => [table.getLeftHeaderGroups(), table.getCenterHeaderGroups(), table.getRightHeaderGroups()], (left, center, right) => {
var _left$0$headers, _left$, _center$0$headers, _center$, _right$0$headers, _right$;
return [...((_left$0$headers = (_left$ = left[0]) == null ? void 0 : _left$.headers) != null ? _left$0$headers : []), ...((_center$0$headers = (_center$ = center[0]) == null ? void 0 : _center$.headers) != null ? _center$0$headers : []), ...((_right$0$headers = (_right$ = right[0]) == null ? void 0 : _right$.headers) != null ? _right$0$headers : [])].map(header => {
return header.getLeafHeaders();
}).flat();
}, getMemoOptions(table.options, debug, 'getLeafHeaders'));
}
};
function buildHeaderGroups(allColumns, columnsToGroup, table, headerFamily) {
var _headerGroups$0$heade, _headerGroups$;
// Find the max depth of the columns:
// build the leaf column row
// build each buffer row going up
// placeholder for non-existent level
// real column for existing level
let maxDepth = 0;
const findMaxDepth = function (columns, depth) {
if (depth === void 0) {
depth = 1;
}
maxDepth = Math.max(maxDepth, depth);
columns.filter(column => column.getIsVisible()).forEach(column => {
var _column$columns;
if ((_column$columns = column.columns) != null && _column$columns.length) {
findMaxDepth(column.columns, depth + 1);
}
}, 0);
};
findMaxDepth(allColumns);
let headerGroups = [];
const createHeaderGroup = (headersToGroup, depth) => {
// The header group we are creating
const headerGroup = {
depth,
id: [headerFamily, `${depth}`].filter(Boolean).join('_'),
headers: []
};
// The parent columns we're going to scan next
const pendingParentHeaders = [];
// Scan each column for parents
headersToGroup.forEach(headerToGroup => {
// What is the latest (last) parent column?
const latestPendingParentHeader = [...pendingParentHeaders].reverse()[0];
const isLeafHeader = headerToGroup.column.depth === headerGroup.depth;
let column;
let isPlaceholder = false;
if (isLeafHeader && headerToGroup.column.parent) {
// The parent header is new
column = headerToGroup.column.parent;
} else {
// The parent header is repeated
column = headerToGroup.column;
isPlaceholder = true;
}
if (latestPendingParentHeader && (latestPendingParentHeader == null ? void 0 : latestPendingParentHeader.column) === column) {
// This column is repeated. Add it as a sub header to the next batch
latestPendingParentHeader.subHeaders.push(headerToGroup);
} else {
// This is a new header. Let's create it
const header = createHeader(table, column, {
id: [headerFamily, depth, column.id, headerToGroup == null ? void 0 : headerToGroup.id].filter(Boolean).join('_'),
isPlaceholder,
placeholderId: isPlaceholder ? `${pendingParentHeaders.filter(d => d.column === column).length}` : undefined,
depth,
index: pendingParentHeaders.length
});
// Add the headerToGroup as a subHeader of the new header
header.subHeaders.push(headerToGroup);
// Add the new header to the pendingParentHeaders to get grouped
// in the next batch
pendingParentHeaders.push(header);
}
headerGroup.headers.push(headerToGroup);
headerToGroup.headerGroup = headerGroup;
});
headerGroups.push(headerGroup);
if (depth > 0) {
createHeaderGroup(pendingParentHeaders, depth - 1);
}
};
const bottomHeaders = columnsToGroup.map((column, index) => createHeader(table, column, {
depth: maxDepth,
index
}));
createHeaderGroup(bottomHeaders, maxDepth - 1);
headerGroups.reverse();
// headerGroups = headerGroups.filter(headerGroup => {
// return !headerGroup.headers.every(header => header.isPlaceholder)
// })
const recurseHeadersForSpans = headers => {
const filteredHeaders = headers.filter(header => header.column.getIsVisible());
return filteredHeaders.map(header => {
let colSpan = 0;
let rowSpan = 0;
let childRowSpans = [0];
if (header.subHeaders && header.subHeaders.length) {
childRowSpans = [];
recurseHeadersForSpans(header.subHeaders).forEach(_ref => {
let {
colSpan: childColSpan,
rowSpan: childRowSpan
} = _ref;
colSpan += childColSpan;
childRowSpans.push(childRowSpan);
});
} else {
colSpan = 1;
}
const minChildRowSpan = Math.min(...childRowSpans);
rowSpan = rowSpan + minChildRowSpan;
header.colSpan = colSpan;
header.rowSpan = rowSpan;
return {
colSpan,
rowSpan
};
});
};
recurseHeadersForSpans((_headerGroups$0$heade = (_headerGroups$ = headerGroups[0]) == null ? void 0 : _headerGroups$.headers) != null ? _headerGroups$0$heade : []);
return headerGroups;
}
const createRow = (table, id, original, rowIndex, depth, subRows, parentId) => {
let row = {
id,
index: rowIndex,
original,
depth,
parentId,
_valuesCache: {},
_uniqueValuesCache: {},
getValue: columnId => {
if (row._valuesCache.hasOwnProperty(columnId)) {
return row._valuesCache[columnId];
}
const column = table.getColumn(columnId);
if (!(column != null && column.accessorFn)) {
return undefined;
}
row._valuesCache[columnId] = column.accessorFn(row.original, rowIndex);
return row._valuesCache[columnId];
},
getUniqueValues: columnId => {
if (row._uniqueValuesCache.hasOwnProperty(columnId)) {
return row._uniqueValuesCache[columnId];
}
const column = table.getColumn(columnId);
if (!(column != null && column.accessorFn)) {
return undefined;
}
if (!column.columnDef.getUniqueValues) {
row._uniqueValuesCache[columnId] = [row.getValue(columnId)];
return row._uniqueValuesCache[columnId];
}
row._uniqueValuesCache[columnId] = column.columnDef.getUniqueValues(row.original, rowIndex);
return row._uniqueValuesCache[columnId];
},
renderValue: columnId => {
var _row$getValue;
return (_row$getValue = row.getValue(columnId)) != null ? _row$getValue : table.options.renderFallbackValue;
},
subRows: [],
getLeafRows: () => flattenBy(row.subRows, d => d.subRows),
getParentRow: () => row.parentId ? table.getRow(row.parentId, true) : undefined,
getParentRows: () => {
let parentRows = [];
let currentRow = row;
while (true) {
const parentRow = currentRow.getParentRow();
if (!parentRow) break;
parentRows.push(parentRow);
currentRow = parentRow;
}
return parentRows.reverse();
},
getAllCells: memo(() => [table.getAllLeafColumns()], leafColumns => {
return leafColumns.map(column => {
return createCell(table, row, column, column.id);
});
}, getMemoOptions(table.options, 'debugRows', 'getAllCells')),
_getAllCellsByColumnId: memo(() => [row.getAllCells()], allCells => {
return allCells.reduce((acc, cell) => {
acc[cell.column.id] = cell;
return acc;
}, {});
}, getMemoOptions(table.options, 'debugRows', 'getAllCellsByColumnId'))
};
for (let i = 0; i < table._features.length; i++) {
const feature = table._features[i];
feature == null || feature.createRow == null || feature.createRow(row, table);
}
return row;
};
//
const ColumnFaceting = {
createColumn: (column, table) => {
column._getFacetedRowModel = table.options.getFacetedRowModel && table.options.getFacetedRowModel(table, column.id);
column.getFacetedRowModel = () => {
if (!column._getFacetedRowModel) {
return table.getPreFilteredRowModel();
}
return column._getFacetedRowModel();
};
column._getFacetedUniqueValues = table.options.getFacetedUniqueValues && table.options.getFacetedUniqueValues(table, column.id);
column.getFacetedUniqueValues = () => {
if (!column._getFacetedUniqueValues) {
return new Map();
}
return column._getFacetedUniqueValues();
};
column._getFacetedMinMaxValues = table.options.getFacetedMinMaxValues && table.options.getFacetedMinMaxValues(table, column.id);
column.getFacetedMinMaxValues = () => {
if (!column._getFacetedMinMaxValues) {
return undefined;
}
return column._getFacetedMinMaxValues();
};
}
};
const includesString = (row, columnId, filterValue) => {
var _filterValue$toString, _row$getValue;
const search = filterValue == null || (_filterValue$toString = filterValue.toString()) == null ? void 0 : _filterValue$toString.toLowerCase();
return Boolean((_row$getValue = row.getValue(columnId)) == null || (_row$getValue = _row$getValue.toString()) == null || (_row$getValue = _row$getValue.toLowerCase()) == null ? void 0 : _row$getValue.includes(search));
};
includesString.autoRemove = val => testFalsey(val);
const includesStringSensitive = (row, columnId, filterValue) => {
var _row$getValue2;
return Boolean((_row$getValue2 = row.getValue(columnId)) == null || (_row$getValue2 = _row$getValue2.toString()) == null ? void 0 : _row$getValue2.includes(filterValue));
};
includesStringSensitive.autoRemove = val => testFalsey(val);
const equalsString = (row, columnId, filterValue) => {
var _row$getValue3;
return ((_row$getValue3 = row.getValue(columnId)) == null || (_row$getValue3 = _row$getValue3.toString()) == null ? void 0 : _row$getValue3.toLowerCase()) === (filterValue == null ? void 0 : filterValue.toLowerCase());
};
equalsString.autoRemove = val => testFalsey(val);
const arrIncludes = (row, columnId, filterValue) => {
var _row$getValue4;
return (_row$getValue4 = row.getValue(columnId)) == null ? void 0 : _row$getValue4.includes(filterValue);
};
arrIncludes.autoRemove = val => testFalsey(val);
const arrIncludesAll = (row, columnId, filterValue) => {
return !filterValue.some(val => {
var _row$getValue5;
return !((_row$getValue5 = row.getValue(columnId)) != null && _row$getValue5.includes(val));
});
};
arrIncludesAll.autoRemove = val => testFalsey(val) || !(val != null && val.length);
const arrIncludesSome = (row, columnId, filterValue) => {
return filterValue.some(val => {
var _row$getValue6;
return (_row$getValue6 = row.getValue(columnId)) == null ? void 0 : _row$getValue6.includes(val);
});
};
arrIncludesSome.autoRemove = val => testFalsey(val) || !(val != null && val.length);
const equals = (row, columnId, filterValue) => {
return row.getValue(columnId) === filterValue;
};
equals.autoRemove = val => testFalsey(val);
const weakEquals = (row, columnId, filterValue) => {
return row.getValue(columnId) == filterValue;
};
weakEquals.autoRemove = val => testFalsey(val);
const inNumberRange = (row, columnId, filterValue) => {
let [min, max] = filterValue;
const rowValue = row.getValue(columnId);
return rowValue >= min && rowValue <= max;
};
inNumberRange.resolveFilterValue = val => {
let [unsafeMin, unsafeMax] = val;
let parsedMin = typeof unsafeMin !== 'number' ? parseFloat(unsafeMin) : unsafeMin;
let parsedMax = typeof unsafeMax !== 'number' ? parseFloat(unsafeMax) : unsafeMax;
let min = unsafeMin === null || Number.isNaN(parsedMin) ? -Infinity : parsedMin;
let max = unsafeMax === null || Number.isNaN(parsedMax) ? Infinity : parsedMax;
if (min > max) {
const temp = min;
min = max;
max = temp;
}
return [min, max];
};
inNumberRange.autoRemove = val => testFalsey(val) || testFalsey(val[0]) && testFalsey(val[1]);
// Export
const filterFns = {
includesString,
includesStringSensitive,
equalsString,
arrIncludes,
arrIncludesAll,
arrIncludesSome,
equals,
weakEquals,
inNumberRange
};
// Utils
function testFalsey(val) {
return val === undefined || val === null || val === '';
}
//
const ColumnFiltering = {
getDefaultColumnDef: () => {
return {
filterFn: 'auto'
};
},
getInitialState: state => {
return {
columnFilters: [],
...state
};
},
getDefaultOptions: table => {
return {
onColumnFiltersChange: makeStateUpdater('columnFilters', table),
filterFromLeafRows: false,
maxLeafRowFilterDepth: 100
};
},
createColumn: (column, table) => {
column.getAutoFilterFn = () => {
const firstRow = table.getCoreRowModel().flatRows[0];
const value = firstRow == null ? void 0 : firstRow.getValue(column.id);
if (typeof value === 'string') {
return filterFns.includesString;
}
if (typeof value === 'number') {
return filterFns.inNumberRange;
}
if (typeof value === 'boolean') {
return filterFns.equals;
}
if (value !== null && typeof value === 'object') {
return filterFns.equals;
}
if (Array.isArray(value)) {
return filterFns.arrIncludes;
}
return filterFns.weakEquals;
};
column.getFilterFn = () => {
var _table$options$filter, _table$options$filter2;
return isFunction(column.columnDef.filterFn) ? column.columnDef.filterFn : column.columnDef.filterFn === 'auto' ? column.getAutoFilterFn() : // @ts-ignore
(_table$options$filter = (_table$options$filter2 = table.options.filterFns) == null ? void 0 : _table$options$filter2[column.columnDef.filterFn]) != null ? _table$options$filter : filterFns[column.columnDef.filterFn];
};
column.getCanFilter = () => {
var _column$columnDef$ena, _table$options$enable, _table$options$enable2;
return ((_column$columnDef$ena = column.columnDef.enableColumnFilter) != null ? _column$columnDef$ena : true) && ((_table$options$enable = table.options.enableColumnFilters) != null ? _table$options$enable : true) && ((_table$options$enable2 = table.options.enableFilters) != null ? _table$options$enable2 : true) && !!column.accessorFn;
};
column.getIsFiltered = () => column.getFilterIndex() > -1;
column.getFilterValue = () => {
var _table$getState$colum;
return (_table$getState$colum = table.getState().columnFilters) == null || (_table$getState$colum = _table$getState$colum.find(d => d.id === column.id)) == null ? void 0 : _table$getState$colum.value;
};
column.getFilterIndex = () => {
var _table$getState$colum2, _table$getState$colum3;
return (_table$getState$colum2 = (_table$getState$colum3 = table.getState().columnFilters) == null ? void 0 : _table$getState$colum3.findIndex(d => d.id === column.id)) != null ? _table$getState$colum2 : -1;
};
column.setFilterValue = value => {
table.setColumnFilters(old => {
const filterFn = column.getFilterFn();
const previousFilter = old == null ? void 0 : old.find(d => d.id === column.id);
const newFilter = functionalUpdate(value, previousFilter ? previousFilter.value : undefined);
//
if (shouldAutoRemoveFilter(filterFn, newFilter, column)) {
var _old$filter;
return (_old$filter = old == null ? void 0 : old.filter(d => d.id !== column.id)) != null ? _old$filter : [];
}
const newFilterObj = {
id: column.id,
value: newFilter
};
if (previousFilter) {
var _old$map;
return (_old$map = old == null ? void 0 : old.map(d => {
if (d.id === column.id) {
return newFilterObj;
}
return d;
})) != null ? _old$map : [];
}
if (old != null && old.length) {
return [...old, newFilterObj];
}
return [newFilterObj];
});
};
},
createRow: (row, _table) => {
row.columnFilters = {};
row.columnFiltersMeta = {};
},
createTable: table => {
table.setColumnFilters = updater => {
const leafColumns = table.getAllLeafColumns();
const updateFn = old => {
var _functionalUpdate;
return (_functionalUpdate = functionalUpdate(updater, old)) == null ? void 0 : _functionalUpdate.filter(filter => {
const column = leafColumns.find(d