@majoo-ui/react 2.1.0 → 2.1.2

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.
@@ -6,6 +6,15 @@ import 'core-js/modules/es.iterator.for-each.js';
6
6
  import 'core-js/modules/es.iterator.map.js';
7
7
  import 'core-js/modules/es.json.parse.js';
8
8
  import 'core-js/modules/es.json.stringify.js';
9
+ import 'core-js/modules/es.map.get-or-insert.js';
10
+ import 'core-js/modules/es.map.get-or-insert-computed.js';
11
+ import 'core-js/modules/es.set.difference.v2.js';
12
+ import 'core-js/modules/es.set.intersection.v2.js';
13
+ import 'core-js/modules/es.set.is-disjoint-from.v2.js';
14
+ import 'core-js/modules/es.set.is-subset-of.v2.js';
15
+ import 'core-js/modules/es.set.is-superset-of.v2.js';
16
+ import 'core-js/modules/es.set.symmetric-difference.v2.js';
17
+ import 'core-js/modules/es.set.union.v2.js';
9
18
  import { __rest } from 'tslib';
10
19
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
11
20
  import * as React from 'react';
@@ -28,7 +37,7 @@ import useMediaQuery from '../../utils/useMediaQuery.esm.js';
28
37
  import { ConditionalWrapper } from '../../wrapper/ConditionalWrapper.esm.js';
29
38
  import { ContextMenuTrigger, ContextMenu, ContextMenuItem, ContextMenuSeparator } from '../contextMenu/ContextMenu.esm.js';
30
39
  import MobileTable from './MobileTable.esm.js';
31
- import { useSticky } from 'react-table-sticky';
40
+ import { useSticky, getStickyValue, getMarginRight } from 'react-table-sticky';
32
41
  import { useTranslation } from 'react-i18next';
33
42
  import { useVirtual } from 'react-virtual';
34
43
  import { PlusPrimitive } from '@majoo-ui/icons';
@@ -380,6 +389,88 @@ const stickyShadowStyling = (column, tableScrollPosition, scrollAreaWidth) => {
380
389
  }
381
390
  return {};
382
391
  };
392
+ const resolveCellCss = cell => {
393
+ const {
394
+ cellCss
395
+ } = cell.column;
396
+ return typeof cellCss === 'function' ? cellCss(cell) : cellCss;
397
+ };
398
+ /**
399
+ * react-table-sticky only decorates header and body cells, so footer cells work out the same
400
+ * sticky offset themselves.
401
+ */
402
+ const getStickyFooterProps = (column, flatHeaders) => {
403
+ const sticky = getStickyValue(column);
404
+ if (!sticky) return {};
405
+ const margin = sticky === 'left' ? column.totalLeft : getMarginRight(column.id, flatHeaders.filter(header => header.depth === column.depth));
406
+ return {
407
+ style: {
408
+ position: 'sticky',
409
+ zIndex: 3,
410
+ [sticky]: `${margin}px`
411
+ },
412
+ 'data-sticky-td': true
413
+ };
414
+ };
415
+ /**
416
+ * Cells per header row. With `spanRows`, a column outside any group is drawn once across every
417
+ * header row instead of under the empty placeholder cells react-table puts above it.
418
+ */
419
+ const buildHeaderRows = (headerGroups, spanRows) => {
420
+ if (!spanRows) {
421
+ return headerGroups.map(headerGroup => headerGroup.headers.map(column => ({
422
+ column,
423
+ rowSpan: 1
424
+ })));
425
+ }
426
+ const coveredIds = new Set();
427
+ headerGroups.forEach(headerGroup => headerGroup.headers.forEach(header => {
428
+ if (header.placeholderOf) coveredIds.add(header.placeholderOf.id);
429
+ }));
430
+ return headerGroups.map(headerGroup => headerGroup.headers.filter(header => !coveredIds.has(header.id)).map(header => {
431
+ let column = header;
432
+ let rowSpan = 1;
433
+ while (column.placeholderOf) {
434
+ column = column.placeholderOf;
435
+ rowSpan += 1;
436
+ }
437
+ return {
438
+ column,
439
+ rowSpan
440
+ };
441
+ }));
442
+ };
443
+ /**
444
+ * rowSpan of the body cells whose column sets `rowSpan`, looked up by column id then row id. The
445
+ * first row of a run of equal keys spans the run; the rows it covers get 0 and render no cell. A
446
+ * run never crosses an expanded row, whose sub rows sit in between.
447
+ */
448
+ const getCellRowSpans = (rows, spanColumns) => {
449
+ const spans = new Map();
450
+ spanColumns.forEach(column => {
451
+ // Nested by column: joining ids into one string would let row `0` + column `1.x` collide with
452
+ // sub row `0.1` + column `x`.
453
+ const columnSpans = new Map();
454
+ spans.set(column.id, columnSpans);
455
+ let anchorId = null;
456
+ let anchorKey;
457
+ rows.forEach((row, index) => {
458
+ var _a;
459
+ if (!row) return;
460
+ const key = typeof column.rowSpan === 'function' ? column.rowSpan(row) : row.values[column.id];
461
+ const hasKey = key !== null && key !== undefined;
462
+ if (anchorId !== null && hasKey && key === anchorKey && !((_a = rows[index - 1]) === null || _a === void 0 ? void 0 : _a.isExpanded)) {
463
+ columnSpans.set(anchorId, columnSpans.get(anchorId) + 1);
464
+ columnSpans.set(row.id, 0);
465
+ return;
466
+ }
467
+ anchorId = hasKey ? row.id : null;
468
+ anchorKey = key;
469
+ columnSpans.set(row.id, 1);
470
+ });
471
+ });
472
+ return spans;
473
+ };
383
474
  const formattingData = (rawData, rowGroup) => {
384
475
  if ((rowGroup === null || rowGroup === void 0 ? void 0 : rowGroup.groupKey) && !(rowGroup === null || rowGroup === void 0 ? void 0 : rowGroup.isManuallyFormatted)) {
385
476
  const {
@@ -609,6 +700,7 @@ function Table({
609
700
  showDuplicatedData,
610
701
  onRowClick,
611
702
  hidePagination = false,
703
+ paginationLabel,
612
704
  searchQuery,
613
705
  additionalExceptionIds = [],
614
706
  expanded: controlledExpanded = {},
@@ -623,7 +715,11 @@ function Table({
623
715
  draggable = false,
624
716
  onDragEnd,
625
717
  isExpandableTree,
626
- subRows = 'subRows'
718
+ subRows = 'subRows',
719
+ footerData,
720
+ initialSortBy,
721
+ disableSortRemove = false,
722
+ headerRowSpan = false
627
723
  }) {
628
724
  var _a, _b, _c, _d;
629
725
  const [openMenu, setOpen] = useState(false);
@@ -660,6 +756,11 @@ function Table({
660
756
  expanded: controlledExpanded
661
757
  });
662
758
  }
759
+ if (initialSortBy) {
760
+ Object.assign(initialState, {
761
+ sortBy: initialSortBy
762
+ });
763
+ }
663
764
  return Object.keys(initialState).length > 0 ? initialState : undefined;
664
765
  };
665
766
  const records = useMemo(() => formattingData(rawData, rowGroup), [rawData, rowGroup]);
@@ -685,6 +786,7 @@ function Table({
685
786
  defaultCanSort: true,
686
787
  pageCount: totalPage || Math.ceil(totalData / limit),
687
788
  autoResetSortBy: false,
789
+ disableSortRemove,
688
790
  autoResetExpanded,
689
791
  onExpandedChange,
690
792
  autoResetPage: false,
@@ -696,6 +798,7 @@ function Table({
696
798
  getTableProps,
697
799
  getTableBodyProps,
698
800
  headerGroups,
801
+ flatHeaders,
699
802
  visibleColumns,
700
803
  prepareRow,
701
804
  rows,
@@ -736,36 +839,56 @@ function Table({
736
839
  });
737
840
  if (fetchData) fetchData(fetchParams);
738
841
  };
739
- const renderFooter = () => jsx(Pagination, {
740
- hidePagination: hidePagination || isExpandableTree,
741
- hideInputPageSection: false,
742
- limit: pageSize,
743
- currentPage: pageIndex + 1,
744
- totalData: totalData,
745
- totalPage: totalPage,
746
- onLimitChange: selectedItem => {
747
- if (selectedItem) {
748
- // always reset page when limit changed
749
- gotoPage(0);
750
- doFetchData(0, selectedItem);
751
- setPageSize(selectedItem);
752
- setLimit(selectedItem);
753
- }
754
- },
755
- hideDataInfo: hideDataInfo || isExpandableTree,
756
- onPageChange: page => {
757
- doFetchData(page - 1, pageSize);
758
- gotoPage(page - 1);
759
- },
760
- rowsPerPageOptions: rowsPerPageOptions,
761
- css: {
762
- backgroundColor: '$bgWhite',
763
- padding: '$spacing-04 0',
764
- '@md': {
765
- padding: '$spacing-06 $spacing-03'
842
+ const renderFooter = () => {
843
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
844
+ return jsx(Pagination, {
845
+ hidePagination: hidePagination || isExpandableTree,
846
+ hideInputPageSection: false,
847
+ limit: pageSize,
848
+ currentPage: pageIndex + 1,
849
+ totalData: totalData,
850
+ totalPage: totalPage,
851
+ onLimitChange: selectedItem => {
852
+ if (selectedItem) {
853
+ // always reset page when limit changed
854
+ gotoPage(0);
855
+ doFetchData(0, selectedItem);
856
+ setPageSize(selectedItem);
857
+ setLimit(selectedItem);
858
+ }
859
+ },
860
+ hideDataInfo: hideDataInfo || isExpandableTree,
861
+ onPageChange: page => {
862
+ doFetchData(page - 1, pageSize);
863
+ gotoPage(page - 1);
864
+ },
865
+ rowsPerPageOptions: rowsPerPageOptions,
866
+ showingText: (_a = paginationLabel === null || paginationLabel === void 0 ? void 0 : paginationLabel.showingText) !== null && _a !== void 0 ? _a : t('pagination.showingText', 'Tampilkan:'),
867
+ showingCountText: (_b = paginationLabel === null || paginationLabel === void 0 ? void 0 : paginationLabel.showingCountText) !== null && _b !== void 0 ? _b : ({
868
+ from,
869
+ to,
870
+ total
871
+ }) => t('pagination.showingCountText', `Ditampilkan ${from} - ${to} dari ${total} data`, {
872
+ from,
873
+ to,
874
+ total
875
+ }),
876
+ dialogShowingText: (_c = paginationLabel === null || paginationLabel === void 0 ? void 0 : paginationLabel.dialogShowingText) !== null && _c !== void 0 ? _c : t('pagination.dialogShowingText', 'Tampilkan Data'),
877
+ previousButton: (_d = paginationLabel === null || paginationLabel === void 0 ? void 0 : paginationLabel.previousButton) !== null && _d !== void 0 ? _d : t('pagination.previousButton', 'Sebelumnya'),
878
+ nextButton: (_e = paginationLabel === null || paginationLabel === void 0 ? void 0 : paginationLabel.nextButton) !== null && _e !== void 0 ? _e : t('pagination.nextButton', 'Selanjutnya'),
879
+ gotoPageText: (_f = paginationLabel === null || paginationLabel === void 0 ? void 0 : paginationLabel.gotoPageText) !== null && _f !== void 0 ? _f : t('pagination.gotoPageText', 'Ke Halaman'),
880
+ goToPagePlaceholder: (_g = paginationLabel === null || paginationLabel === void 0 ? void 0 : paginationLabel.goToPagePlaceholder) !== null && _g !== void 0 ? _g : t('pagination.goToPagePlaceholder', 'Contoh: 10'),
881
+ btnCancelText: (_h = paginationLabel === null || paginationLabel === void 0 ? void 0 : paginationLabel.btnCancelText) !== null && _h !== void 0 ? _h : t('pagination.btnCancelText', 'Batal'),
882
+ btnSubmitText: (_j = paginationLabel === null || paginationLabel === void 0 ? void 0 : paginationLabel.btnSubmitText) !== null && _j !== void 0 ? _j : t('pagination.btnSubmitText', 'Lanjutkan'),
883
+ css: {
884
+ backgroundColor: '$bgWhite',
885
+ padding: '$spacing-04 0',
886
+ '@md': {
887
+ padding: '$spacing-06 $spacing-03'
888
+ }
766
889
  }
767
- }
768
- });
890
+ });
891
+ };
769
892
  const renderInfiniteScrollWrapper = children => jsx(ConditionalWrapper, {
770
893
  condition: isInfiniteScroll && rawData.length > 0,
771
894
  wrapper: children => jsx(InfiniteScroll, {
@@ -903,6 +1026,38 @@ function Table({
903
1026
  }))]
904
1027
  });
905
1028
  };
1029
+ const renderTableFoot = () => {
1030
+ if (!(footerData === null || footerData === void 0 ? void 0 : footerData.length)) return null;
1031
+ let footerColumns = visibleColumns.filter(column => !column.isSubRow);
1032
+ if (filteredHeader.length > 0 || filterHeader.length > 0) {
1033
+ footerColumns = footerColumns.filter(column => filteredHeader.includes(column.id) || filterHeader.includes(column.id));
1034
+ }
1035
+ return jsx(TableFoot, {
1036
+ css: {
1037
+ zIndex: '$docked'
1038
+ },
1039
+ children: footerData.map((footerRow, footerRowIndex) => {
1040
+ var _a;
1041
+ return jsx(TableFootRow, {
1042
+ children: footerColumns.map(column => jsx(TableCell, Object.assign({}, getStickyFooterProps(column, flatHeaders), {
1043
+ css: Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, cssTableCell), {
1044
+ padding: '20px 8px',
1045
+ fontWeight: '600',
1046
+ verticalAlign: cellAlign
1047
+ }), stickyPositionStyling(column)), stickyShadowStyling(column, tableScrollPosition, scrollAreaWidth)), column.footerCss),
1048
+ children: column.render('Footer', {
1049
+ footerRow,
1050
+ footerRowIndex,
1051
+ value: column.accessor ? column.accessor(footerRow, footerRowIndex, {
1052
+ subRows: [],
1053
+ depth: 0
1054
+ }) : undefined
1055
+ })
1056
+ }), column.id))
1057
+ }, (_a = footerRow[keyId]) !== null && _a !== void 0 ? _a : footerRowIndex);
1058
+ })
1059
+ });
1060
+ };
906
1061
  const handleRowClick = (row, i) => {
907
1062
  var _a, _b, _c, _d;
908
1063
  let clickable = false;
@@ -1005,6 +1160,10 @@ function Table({
1005
1160
  const tableData = isExpandableTree ? rows : page;
1006
1161
  return virtualized ? isInfiniteScroll ? virtualRows : tableData : tableData;
1007
1162
  }, [virtualized, isExpandableTree, isInfiniteScroll, rows, page, virtualRows]);
1163
+ const rowSpanColumns = useMemo(() => visibleColumns.filter(column => column.rowSpan), [visibleColumns]);
1164
+ // Row groups interleave decorator rows and dragging reorders rows, so neither merges cells.
1165
+ // Bail out before touching the rows: virtualized tables recompute this on every scroll.
1166
+ const cellRowSpans = useMemo(() => rowGroup || draggable || !rowSpanColumns.length ? null : getCellRowSpans(tableRowData.map(dataRow => virtualized && isInfiniteScroll ? page === null || page === void 0 ? void 0 : page[dataRow === null || dataRow === void 0 ? void 0 : dataRow.index] : dataRow), rowSpanColumns), [rowGroup, draggable, rowSpanColumns, tableRowData, virtualized, isInfiniteScroll, page]);
1008
1167
  const onSortEnd = ({
1009
1168
  oldIndex,
1010
1169
  newIndex
@@ -1067,13 +1226,20 @@ function Table({
1067
1226
  hiddenHeader: hideHeader,
1068
1227
  css: headerCss,
1069
1228
  isInfiniteScroll: isInfiniteScroll,
1070
- children: headerGroups.map(headerGroup => {
1071
- let visibleHeaders = headerGroup.headers.filter(column => !column.isSubRow);
1229
+ children: buildHeaderRows(headerGroups, headerRowSpan).map((headerCells, headerRowIndex) => {
1230
+ let visibleHeaders = headerCells.filter(({
1231
+ column
1232
+ }) => !column.isSubRow);
1072
1233
  if (filteredHeader.length > 0 || filterHeader.length > 0) {
1073
- visibleHeaders = visibleHeaders.filter(item => filteredHeader.includes(item.id) || filterHeader.includes(item.id));
1234
+ visibleHeaders = visibleHeaders.filter(({
1235
+ column: item
1236
+ }) => filteredHeader.includes(item.id) || filterHeader.includes(item.id));
1074
1237
  }
1075
- return jsx(TableHeadRow, Object.assign({}, headerGroup.getHeaderGroupProps(), {
1076
- children: visibleHeaders.map((column, index) => {
1238
+ return jsx(TableHeadRow, Object.assign({}, headerGroups[headerRowIndex].getHeaderGroupProps(), {
1239
+ children: visibleHeaders.map(({
1240
+ column,
1241
+ rowSpan
1242
+ }, index) => {
1077
1243
  const headerRender = column.render('Header');
1078
1244
  return jsx(TableHeadCell, Object.assign({}, column.getHeaderProps(props => [props, !column.unsortable ? column.getSortByToggleProps({
1079
1245
  title: t('sortColumnTitle', 'Urutkan') || 'Urutkan'
@@ -1086,6 +1252,7 @@ function Table({
1086
1252
  minWidth: column.colMinWidth
1087
1253
  }
1088
1254
  }]), {
1255
+ rowSpan: rowSpan > 1 ? rowSpan : undefined,
1089
1256
  css: Object.assign(Object.assign(Object.assign(Object.assign({}, stickyPositionStyling(column)), stickyShadowStyling(column, tableScrollPosition, scrollAreaWidth)), column.headerCss), {
1090
1257
  position: 'sticky',
1091
1258
  zIndex: column.sticky ? '5 !important' : 3,
@@ -1153,13 +1320,13 @@ function Table({
1153
1320
  const collId = (_b = cell === null || cell === void 0 ? void 0 : cell.column) === null || _b === void 0 ? void 0 : _b.id;
1154
1321
  const exceptionId = (_c = [].concat(additionalExceptionIds)) === null || _c === void 0 ? void 0 : _c.includes(collId);
1155
1322
  return jsx(TableCell, Object.assign({}, cell.getCellProps(addOnCellStyle(cell.column.id)), {
1156
- css: Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, cssTableCell), {
1323
+ css: Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, cssTableCell), {
1157
1324
  padding: !isContextMenu || exceptionId ? collId === 'expander' || collId === 'multiple-expander' ? '20px 4px' : '20px 8px' : '',
1158
1325
  verticalAlign: cell.column.accessor ? cellAlign : 'center',
1159
1326
  cursor: onRowClick ? 'pointer' : 'unset'
1160
1327
  }), stickyPositionStyling(cell.column)), stickyShadowStyling(cell.column, tableScrollPosition, scrollAreaWidth)), id && {
1161
1328
  paddingRight: index + 1 === _row.length ? 30 : null
1162
- }),
1329
+ }), resolveCellCss(cell)),
1163
1330
  onClick: () => {
1164
1331
  if (!exceptionId) {
1165
1332
  handleRowClick(row, i);
@@ -1268,21 +1435,24 @@ function Table({
1268
1435
  css: customStyle
1269
1436
  }, row && (row === null || row === void 0 ? void 0 : row.getRowProps) ? row === null || row === void 0 ? void 0 : row.getRowProps() : {}, {
1270
1437
  children: row.cells.filter(cell => filteredHeader.length > 0 || filterHeader.length > 0 ? filteredHeader.includes(cell.column.id) || filterHeader.includes(cell.column.id) : cell).filter(cell => !cell.column.isSubRow).map((cell, index, _row) => {
1271
- var _a, _b, _c;
1272
- let visibleHeaders = (_a = headerGroups === null || headerGroups === void 0 ? void 0 : headerGroups[0]) === null || _a === void 0 ? void 0 : _a.headers.filter(column => !column.isSubRow);
1438
+ var _a, _b, _c, _d;
1439
+ const cellRowSpan = (_a = cellRowSpans === null || cellRowSpans === void 0 ? void 0 : cellRowSpans.get(cell.column.id)) === null || _a === void 0 ? void 0 : _a.get(row.id);
1440
+ if (cellRowSpan === 0) return null;
1441
+ let visibleHeaders = (_b = headerGroups === null || headerGroups === void 0 ? void 0 : headerGroups[0]) === null || _b === void 0 ? void 0 : _b.headers.filter(column => !column.isSubRow);
1273
1442
  if (filterHeader.length > 0) {
1274
1443
  visibleHeaders = visibleHeaders.filter(item => filterHeader.includes(item.id));
1275
1444
  }
1276
- const collId = (_b = cell === null || cell === void 0 ? void 0 : cell.column) === null || _b === void 0 ? void 0 : _b.id;
1277
- const exceptionId = (_c = ['expander', 'multiple-expander', 'selection', 'menu', 'eye'].concat(additionalExceptionIds)) === null || _c === void 0 ? void 0 : _c.includes(collId);
1445
+ const collId = (_c = cell === null || cell === void 0 ? void 0 : cell.column) === null || _c === void 0 ? void 0 : _c.id;
1446
+ const exceptionId = (_d = ['expander', 'multiple-expander', 'selection', 'menu', 'eye'].concat(additionalExceptionIds)) === null || _d === void 0 ? void 0 : _d.includes(collId);
1278
1447
  return jsx(TableCell, Object.assign({}, cell.getCellProps(addOnCellStyle(cell.column.id)), {
1279
- css: Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, cssTableCell), {
1448
+ rowSpan: cellRowSpan > 1 ? cellRowSpan : undefined,
1449
+ css: Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, cssTableCell), {
1280
1450
  padding: !isContextMenu || exceptionId ? collId === 'expander' || collId === 'multiple-expander' ? '20px 4px' : '20px 8px' : '',
1281
1451
  verticalAlign: cell.column.accessor ? cellAlign : 'center',
1282
1452
  cursor: onRowClick ? 'pointer' : 'unset'
1283
1453
  }), stickyPositionStyling(cell.column)), stickyShadowStyling(cell.column, tableScrollPosition, scrollAreaWidth)), id && {
1284
1454
  paddingRight: index + 1 === _row.length ? 30 : null
1285
- }),
1455
+ }), resolveCellCss(cell)),
1286
1456
  onClick: () => {
1287
1457
  if (!exceptionId) {
1288
1458
  handleRowClick(row, i);
@@ -1364,7 +1534,7 @@ function Table({
1364
1534
  }
1365
1535
  })
1366
1536
  })]
1367
- }))]
1537
+ })), renderTableFoot()]
1368
1538
  }))
1369
1539
  }), renderContextMenu()]
1370
1540
  })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@majoo-ui/react",
3
- "version": "2.1.0",
3
+ "version": "2.1.2",
4
4
  "main": "./index.esm.js",
5
5
  "sideEffects": [
6
6
  "*.css",