@appbuckets/react-ui
Version:
Just Another React UI Framework
805 lines (798 loc) • 25.3 kB
JavaScript
'use strict';
var tslib = require('tslib');
var React = require('react');
var clsx = require('clsx');
var reactWindow = require('react-window');
var useElementSize = require('../hooks/useElementSize.js');
require('../BucketTheme/BucketTheme.js');
var BucketContext = require('../BucketTheme/BucketContext.js');
require('../RxTable/RxTable.js');
var RxTable_context = require('../RxTable/RxTable.context.js');
var RxTable_factory = require('../RxTable/RxTable.factory.js');
var BodyRow = require('../RxTable/components/BodyRow.js');
var FooterRow = require('../RxTable/components/FooterRow.js');
var FiltersRow = require('../RxTable/components/FiltersRow.js');
var HeaderRow = require('../RxTable/components/HeaderRow.js');
var StateDependentBodyRow = require('../RxTable/components/StateDependentBodyRow.js');
var RxTableBodyCell = require('../RxTable/defaults/RxTableBodyCell.js');
var RxTableBodyRow = require('../RxTable/defaults/RxTableBodyRow.js');
var RxTableFooterCell = require('../RxTable/defaults/RxTableFooterCell.js');
var RxTableHeaderCell = require('../RxTable/defaults/RxTableHeaderCell.js');
var RxTableEmptyContent = require('../RxTable/defaults/RxTableEmptyContent.js');
var RxTableError = require('../RxTable/defaults/RxTableError.js');
var RxTableLoader = require('../RxTable/defaults/RxTableLoader.js');
var ScrollOnTop = require('./atoms/ScrollOnTop.js');
function _interopDefaultLegacy(e) {
return e && typeof e === 'object' && 'default' in e ? 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 clsx__default = /*#__PURE__*/ _interopDefaultLegacy(clsx);
/* --------
* Memoize the BodyRow Component to be used with VariableSizeList
* -------- */
var MemoizedBodyRow = React__namespace.memo(BodyRow, reactWindow.areEqual);
/* --------
* Variable Size List Inner Element
* ---
* Is extracted from original code to avoid
* list rerender
* -------- */
var VariableSizeListInnerElement = React__namespace.forwardRef(function (
props,
ref
) {
/** Get Body Component */
var _a = RxTable_context.useRxTable(),
Body = _a.Components.Body,
classes = _a.classes,
styles = _a.styles;
/** Extract style and classes from props */
var style = props.style,
className = props.className,
rest = tslib.__rest(props, ['style', 'className']);
/** Merge Body Classes */
var bodyClasses = clsx__default['default'](className, classes.Body);
/** Render the Component */
return React__namespace.createElement(
Body,
tslib.__assign({}, rest, {
ref: ref,
className: bodyClasses,
style: tslib.__assign(tslib.__assign({}, styles.Body), style),
})
);
});
/* --------
* Variable Size List Outer Element
* ---
* Is extracted from original code to avoid
* list rerender
* -------- */
var VariableSizeListOuterElement = React__namespace.forwardRef(function (
props,
ref
) {
/** Get Body Component */
var _a = RxTable_context.useRxTable(),
BodyWrapper = _a.Components.BodyWrapper,
classes = _a.classes,
styles = _a.styles;
/** Extract style and classes from props */
var style = props.style,
className = props.className,
rest = tslib.__rest(props, ['style', 'className']);
/** Merge Body Classes */
var bodyWrapperClasses = clsx__default['default'](
className,
classes.BodyWrapper
);
/** Render the Component */
return React__namespace.createElement(
BodyWrapper,
tslib.__assign({}, rest, {
ref: ref,
className: bodyWrapperClasses,
style: tslib.__assign(tslib.__assign({}, styles.BodyWrapper), style),
})
);
});
/* --------
* Component Definition
* -------- */
var VirtualizedTable = function (receivedProps) {
var props = BucketContext.useWithDefaultProps(
'virtualizedTable',
receivedProps
);
var /** RxTable Shared Props */ userDefinedClasses = props.classes;
props.className;
var columns = props.columns,
userDefinedComponents = props.Components,
data = props.data,
defaultData = props.defaultData,
userDefinedDefaultReverseSorting = props.defaultReverseSorting,
userDefinedSelectedData = props.defaultSelectedData,
userDefinedDefaultSort = props.defaultSort,
disableHeader = props.disableHeader,
filterLogic = props.filterLogic,
userDefinedGetRowKey = props.getRowKey,
userDefinedHeight = props.height,
initiallyLoading = props.initiallyLoading,
loaderProps = props.loaderProps,
noFilteredDataEmptyContentProps = props.noFilteredDataEmptyContentProps,
noDataEmptyContentProps = props.noDataEmptyContentProps,
onRowClick = props.onRowClick,
onSortChange = props.onSortChange,
onSelectedDataChange = props.onSelectedDataChange,
reloadDependency = props.reloadDependency,
reloadSilently = props.reloadSilently,
userDefinedReverseSorting = props.reverseSorting,
scrollOnTopButtonProps = props.scrollOnTopButtonProps,
scrollOnTopOffsetVisibility = props.scrollOnTopOffsetVisibility,
selectable = props.selectable,
selectColumnProps = props.selectColumnProps,
userDefinedSort = props.sort,
style = props.style,
userDefinedStyles = props.styles,
userDefinedWidth = props.width,
useScrollOnTop = props.useScrollOnTop,
/** Dedicated VirtualizedTable Props */
compressed = props.compressed,
userDefinedFilterRowHeight = props.filterRowHeight,
userDefinedFooterRowHeight = props.footerRowHeight,
userDefinedHeaderHeight = props.headerHeight,
rowHeight = props.rowHeight,
/** Size Detector Props */
maximumWidth = props.maximumWidth,
maximumHeight = props.maximumHeight,
minimumWidth = props.minimumWidth,
minimumHeight = props.minimumHeight,
subtractToWidth = props.subtractToWidth,
subtractToHeight = props.subtractToHeight,
/** Extracted Variable Size List Props */
direction = props.direction,
itemKey = props.itemKey,
overscanCount = props.overscanCount,
onItemsRendered = props.onItemsRendered,
userDefinedOnScroll = props.onScroll,
useIsScrolling = props.useIsScrolling,
rest = tslib.__rest(props, [
'classes',
'className',
'columns',
'Components',
'data',
'defaultData',
'defaultReverseSorting',
'defaultSelectedData',
'defaultSort',
'disableHeader',
'filterLogic',
'getRowKey',
'height',
'initiallyLoading',
'loaderProps',
'noFilteredDataEmptyContentProps',
'noDataEmptyContentProps',
'onRowClick',
'onSortChange',
'onSelectedDataChange',
'reloadDependency',
'reloadSilently',
'reverseSorting',
'scrollOnTopButtonProps',
'scrollOnTopOffsetVisibility',
'selectable',
'selectColumnProps',
'sort',
'style',
'styles',
'width',
'useScrollOnTop',
'compressed',
'filterRowHeight',
'footerRowHeight',
'headerHeight',
'rowHeight',
'maximumWidth',
'maximumHeight',
'minimumWidth',
'minimumHeight',
'subtractToWidth',
'subtractToHeight',
'direction',
'itemKey',
'overscanCount',
'onItemsRendered',
'onScroll',
'useIsScrolling',
]);
// ----
// Initialize the VariableSizeList ref to use ScrollOnTop
// ----
var variableSizeListRef = React__namespace.useRef(null);
// ----
// Use an internal State to Show/Hide ScrollOnTop Component
// ----
var _a = tslib.__read(React__namespace.useState(false), 2),
scrollOnTopVisible = _a[0],
setScrollOnTopVisible = _a[1];
// ----
// Checker Builder
// ----
var hasFilterRow = React__namespace.useMemo(
function () {
return columns.some(function (column) {
return !!column.filter;
});
},
[columns]
);
var hasFooterRow = React__namespace.useMemo(
function () {
return columns.some(function (column) {
return !!column.footer;
});
},
[columns]
);
var hasHeaderRow = React__namespace.useMemo(
function () {
return columns.some(function (column) {
return !!column.header;
});
},
[columns]
);
// ----
// Initialize the Width Detector
// ----
var _b = tslib.__read(
useElementSize.useElementSize({
useDetectorWidthOnly: true,
fixedHeight: userDefinedHeight,
fixedWidth: userDefinedWidth,
maximumWidth: maximumWidth,
maximumHeight: maximumHeight,
minimumWidth: minimumWidth,
minimumHeight: minimumHeight,
subtractToWidth: subtractToWidth,
subtractToHeight: subtractToHeight,
}),
2
),
widthDetector = _b[0],
_c = _b[1],
width = _c.width,
height = _c.height;
var headerHeight = React__namespace.useMemo(
function () {
/** If table has not header row, return 0 */
if (!hasHeaderRow) {
return 0;
}
var baseHeaderHeight =
typeof userDefinedHeaderHeight === 'number'
? userDefinedHeaderHeight
: typeof rowHeight === 'number'
? rowHeight
: 0;
/** If table is not selectable, return the base height */
if (!selectable || hasFilterRow) {
return baseHeaderHeight;
}
return Math.max(40, baseHeaderHeight);
},
[hasFilterRow, hasHeaderRow, rowHeight, selectable, userDefinedHeaderHeight]
);
var filterRowHeight = hasFilterRow
? typeof userDefinedFilterRowHeight === 'number'
? userDefinedFilterRowHeight
: headerHeight
: 0;
var footerRowHeight = hasFooterRow
? typeof userDefinedFooterRowHeight === 'number'
? userDefinedFooterRowHeight
: headerHeight
: 0;
// ----
// Load RxTableProps
// ----
var rxTableProps = RxTable_factory.useRxTableFactory({
classes: tslib.__assign(
{
Body: clsx__default['default'](
'virtualized body',
userDefinedClasses === null || userDefinedClasses === void 0
? void 0
: userDefinedClasses.Body
),
BodyCell: clsx__default['default'](
'virtualized cell',
userDefinedClasses === null || userDefinedClasses === void 0
? void 0
: userDefinedClasses.BodyCell
),
BodyRow: clsx__default['default'](
'virtualized row',
userDefinedClasses === null || userDefinedClasses === void 0
? void 0
: userDefinedClasses.BodyRow
),
BodyWrapper: clsx__default['default'](
'virtualized table virtualized-body',
userDefinedClasses === null || userDefinedClasses === void 0
? void 0
: userDefinedClasses.BodyWrapper
),
ErrorCell: clsx__default['default'](
'cell error-cell',
userDefinedClasses === null || userDefinedClasses === void 0
? void 0
: userDefinedClasses.ErrorCell
),
ErrorRow: clsx__default['default'](
'row error-row',
userDefinedClasses === null || userDefinedClasses === void 0
? void 0
: userDefinedClasses.ErrorRow
),
Footer: clsx__default['default'](
'virtualized foot',
userDefinedClasses === null || userDefinedClasses === void 0
? void 0
: userDefinedClasses.Footer
),
FooterRow: clsx__default['default'](
'virtualized row',
userDefinedClasses === null || userDefinedClasses === void 0
? void 0
: userDefinedClasses.FooterRow
),
FooterWrapper: clsx__default['default'](
'virtualized table virtualized-foot',
userDefinedClasses === null || userDefinedClasses === void 0
? void 0
: userDefinedClasses.FooterWrapper
),
Header: clsx__default['default'](
'virtualized head',
userDefinedClasses === null || userDefinedClasses === void 0
? void 0
: userDefinedClasses.Header
),
HeaderRow: clsx__default['default'](
'virtualized row',
userDefinedClasses === null || userDefinedClasses === void 0
? void 0
: userDefinedClasses.HeaderRow
),
HeaderWrapper: clsx__default['default'](
'virtualized table virtualized-head',
userDefinedClasses === null || userDefinedClasses === void 0
? void 0
: userDefinedClasses.HeaderWrapper
),
LoaderCell: clsx__default['default'](
'cell loading-cell',
userDefinedClasses === null || userDefinedClasses === void 0
? void 0
: userDefinedClasses.LoaderCell
),
LoaderRow: clsx__default['default'](
'row loading-row',
userDefinedClasses === null || userDefinedClasses === void 0
? void 0
: userDefinedClasses.LoaderRow
),
NoContentCell: clsx__default['default'](
'cell no-content-cell',
userDefinedClasses === null || userDefinedClasses === void 0
? void 0
: userDefinedClasses.NoContentCell
),
NoContentRow: clsx__default['default'](
'row no-content-row',
userDefinedClasses === null || userDefinedClasses === void 0
? void 0
: userDefinedClasses.NoContentRow
),
},
userDefinedClasses
),
styles: tslib.__assign(
{
HeaderCell: tslib.__assign(
{ height: headerHeight },
userDefinedStyles === null || userDefinedStyles === void 0
? void 0
: userDefinedStyles.HeaderCell
),
FilterCell: tslib.__assign(
{ height: filterRowHeight },
userDefinedStyles === null || userDefinedStyles === void 0
? void 0
: userDefinedStyles.FilterCell
),
FooterCell: tslib.__assign(
{ height: footerRowHeight },
userDefinedStyles === null || userDefinedStyles === void 0
? void 0
: userDefinedStyles.FooterCell
),
},
userDefinedStyles
),
columns: columns,
data: data,
defaultData: defaultData,
defaultLoading: initiallyLoading,
defaultReverseSorting: userDefinedDefaultReverseSorting,
defaultSelectedData: userDefinedSelectedData,
defaultSort: userDefinedDefaultSort,
filterLogic: filterLogic,
getRowKey: userDefinedGetRowKey,
isVirtualized: true,
onRowClick: onRowClick,
onSelectedDataChange: onSelectedDataChange,
onSortChange: onSortChange,
reloadDependency: reloadDependency,
reloadSilently: reloadSilently,
reverseSorting: userDefinedReverseSorting,
selectable: selectable,
selectColumnProps: selectColumnProps,
sort: userDefinedSort,
width: width,
});
// ----
// Row Height Calculator
// ----
var estimatedItemSize = typeof rowHeight === 'number' ? rowHeight : undefined;
var getRowHeight = React__namespace.useCallback(
function (index) {
if (typeof rowHeight === 'number') {
return rowHeight;
}
return rowHeight(index);
},
[rowHeight]
);
// ----
// Compute Table Width and Height and Accessor
// ----
var tableBodyHeight =
height -
(!disableHeader ? headerHeight : 0) -
filterRowHeight -
footerRowHeight;
var tableDataHeight =
typeof rowHeight === 'number'
? rxTableProps.tableData.length * rowHeight
: typeof estimatedItemSize === 'number'
? rxTableProps.tableData.length * estimatedItemSize
: Number.MAX_SAFE_INTEGER;
var effectiveBodyHeight = Math.max(
0,
Math.min(tableBodyHeight, tableDataHeight)
);
var effectiveTableHeight =
effectiveBodyHeight +
(!disableHeader ? headerHeight : 0) +
filterRowHeight +
footerRowHeight;
// ----
// Row Key Getter
// ----
var getRowKey = React__namespace.useCallback(
function (index) {
/** If an itemKey function exists, use it */
if (typeof itemKey === 'function') {
return itemKey(index, rxTableProps.tableData);
}
/** Use the data selector function */
var extractedKey = rxTableProps.selection.getRowKey(
rxTableProps.tableData[index],
index,
rxTableProps.tableData
);
return extractedKey === '' ? index : extractedKey;
},
[itemKey, rxTableProps.selection, rxTableProps.tableData]
);
// ----
// Define Components
// ----
var Components = React__namespace.useMemo(
function () {
return tslib.__assign(
{
Body: 'div',
BodyCell: RxTableBodyCell,
BodyRow: RxTableBodyRow,
BodyWrapper: 'div',
Error: RxTableError,
ErrorRow: 'div',
ErrorCell: 'div',
Footer: 'div',
FooterCell: RxTableFooterCell,
FooterRow: 'div',
FooterWrapper: 'div',
Header: 'div',
HeaderCell: RxTableHeaderCell,
HeaderRow: 'div',
HeaderWrapper: 'div',
Loader: RxTableLoader,
LoaderRow: 'div',
LoaderCell: 'div',
NoContent: RxTableEmptyContent,
NoContentCell: 'div',
NoContentRow: 'div',
},
userDefinedComponents
);
},
[userDefinedComponents]
);
// ----
// Context Building
// ----
var rxTableContext = tslib.__assign(tslib.__assign({}, rxTableProps), {
Components: Components,
loaderProps: loaderProps,
noFilteredDataEmptyContentProps: noFilteredDataEmptyContentProps,
noDataEmptyContentProps: noDataEmptyContentProps,
});
// ----
// Fragments could not have properties extra from key
// ----
var headerWrapperProps =
Components.HeaderWrapper !== React__namespace.Fragment
? {
className: rxTableProps.classes.HeaderWrapper,
style: rxTableProps.styles.HeaderWrapper,
}
: {};
var footerWrapperProps =
Components.FooterWrapper !== React__namespace.Fragment
? {
className: rxTableProps.classes.FooterWrapper,
style: rxTableProps.styles.FooterWrapper,
}
: {};
// ----
// Build a custom onScroll handler to show/hide ScrollOnTop component
// ----
var handleTableScroll = React__namespace.useCallback(
function (scrollProps) {
/** If must use the OnScroll Component, check if this must be visible or invisible */
if (useScrollOnTop && effectiveBodyHeight > 0) {
/** Get the offset */
var offset = scrollOnTopOffsetVisibility || effectiveBodyHeight * 2;
/** Update only if is necessary */
if (scrollOnTopVisible !== scrollProps.scrollOffset > offset) {
setScrollOnTopVisible(scrollProps.scrollOffset > offset);
}
}
/** If a userDefinedOnScroll function exists, use it */
if (typeof userDefinedOnScroll === 'function') {
userDefinedOnScroll(scrollProps);
}
},
[
userDefinedOnScroll,
useScrollOnTop,
scrollOnTopOffsetVisibility,
effectiveBodyHeight,
scrollOnTopVisible,
]
);
var handleScrollOnTopClick = React__namespace.useCallback(function () {
/** Scroll the list on top */
if (variableSizeListRef.current) {
variableSizeListRef.current.scrollTo(0);
}
}, []);
// ----
// Wrap the StateDependentRow to avoid multiple Body and BodyWrapper component nest
// ----
var isShowingData = !(
rxTableProps.dataState.isLoading ||
rxTableProps.dataState.error ||
!rxTableProps.tableData.length
);
var BodyWrapper = Components.BodyWrapper,
Body = Components.Body;
var tableBodyContent = React__namespace.useMemo(
function () {
if (!isShowingData) {
var bodyWrapperProps =
BodyWrapper !== React__namespace.Fragment
? {
className: rxTableProps.classes.BodyWrapper,
style: rxTableProps.styles.BodyWrapper,
}
: {};
return React__namespace.createElement(
BodyWrapper,
tslib.__assign({}, bodyWrapperProps),
React__namespace.createElement(
Body,
{
style: rxTableProps.styles.Body,
className: rxTableProps.classes.Body,
},
React__namespace.createElement(StateDependentBodyRow, null)
)
);
}
return React__namespace.createElement(
reactWindow.VariableSizeList,
{
ref: variableSizeListRef,
direction: direction,
itemKey: getRowKey,
overscanCount: overscanCount,
onItemsRendered: onItemsRendered,
onScroll:
useScrollOnTop || typeof userDefinedOnScroll === 'function'
? handleTableScroll
: undefined,
useIsScrolling: useIsScrolling,
width: rxTableProps.layout.effectiveTableWidth,
height: effectiveBodyHeight,
itemSize: getRowHeight,
estimatedItemSize: estimatedItemSize,
itemCount: rxTableProps.tableData.length,
outerElementType: VariableSizeListOuterElement,
innerElementType: VariableSizeListInnerElement,
},
MemoizedBodyRow
);
},
[
isShowingData,
direction,
getRowKey,
overscanCount,
onItemsRendered,
useScrollOnTop,
userDefinedOnScroll,
handleTableScroll,
useIsScrolling,
rxTableProps.layout.effectiveTableWidth,
rxTableProps.tableData.length,
rxTableProps.classes.BodyWrapper,
rxTableProps.classes.Body,
rxTableProps.styles.BodyWrapper,
rxTableProps.styles.Body,
effectiveBodyHeight,
getRowHeight,
estimatedItemSize,
Body,
BodyWrapper,
]
);
// ----
// Build Table ClassList
// ----
var wrapperClasses = clsx__default['default'](
'virtualized-table',
compressed && 'compressed'
);
// ----
// Build Wrapper Style
// ----
var wrapperStyle = React__namespace.useMemo(
function () {
return isShowingData
? tslib.__assign(
{
height: ''.concat(effectiveTableHeight, 'px'),
width: ''.concat(width, 'px'),
overflow: 'auto',
maxHeight: '100vh',
minHeight: ''.concat(
(!disableHeader ? headerHeight : 0) + filterRowHeight,
'px'
),
},
style
)
: tslib.__assign({}, style);
},
[
effectiveTableHeight,
width,
style,
isShowingData,
disableHeader,
headerHeight,
filterRowHeight,
]
);
// ----
// Component Render
// ----
return React__namespace.createElement(
React__namespace.Fragment,
null,
widthDetector,
React__namespace.createElement(
'div',
tslib.__assign({}, rest, {
className: wrapperClasses,
style: wrapperStyle,
}),
React__namespace.createElement(
RxTable_context.RxTableProvider,
{ value: rxTableContext },
(rxTableProps.layout.hasHeaderRow ||
rxTableProps.layout.hasFilterRow) &&
React__namespace.createElement(
Components.HeaderWrapper,
tslib.__assign({}, headerWrapperProps),
React__namespace.createElement(
Components.Header,
{
className: rxTableProps.classes.Header,
style: rxTableProps.styles.Header,
},
rxTableProps.layout.hasHeaderRow &&
React__namespace.createElement(HeaderRow, null),
rxTableProps.layout.hasFilterRow &&
React__namespace.createElement(FiltersRow, null)
)
),
tableBodyContent,
rxTableProps.layout.hasFooterRow &&
React__namespace.createElement(
Components.FooterWrapper,
tslib.__assign({}, footerWrapperProps),
React__namespace.createElement(
Components.Footer,
{
style: rxTableProps.styles.Footer,
className: rxTableProps.classes.Footer,
},
React__namespace.createElement(FooterRow, null)
)
),
useScrollOnTop &&
React__namespace.createElement(
ScrollOnTop,
tslib.__assign({}, scrollOnTopButtonProps, {
visible: scrollOnTopVisible,
onClick: handleScrollOnTopClick,
})
)
)
)
);
};
VirtualizedTable.displayName = 'VirtualizedTable';
module.exports = VirtualizedTable;