@ceed/cds 1.8.7 → 1.9.0

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.
package/dist/index.js CHANGED
@@ -1857,7 +1857,8 @@ import React23, {
1857
1857
  useImperativeHandle as useImperativeHandle2,
1858
1858
  createElement,
1859
1859
  memo,
1860
- useLayoutEffect
1860
+ useLayoutEffect,
1861
+ Fragment as Fragment2
1861
1862
  } from "react";
1862
1863
  import { useVirtualizer as useVirtualizer2 } from "@tanstack/react-virtual";
1863
1864
  import { styled as styled12, LinearProgress, Link, useTheme, buttonClasses, iconButtonClasses } from "@mui/joy";
@@ -2628,6 +2629,118 @@ function InfoSign(props) {
2628
2629
  var InfoSign_default = InfoSign;
2629
2630
 
2630
2631
  // src/components/DataTable/DataTable.tsx
2632
+ function extractFieldsFromGroupingModel(items) {
2633
+ const fields = /* @__PURE__ */ new Set();
2634
+ for (const item of items) {
2635
+ if ("groupId" in item) {
2636
+ const children = Array.isArray(item.children) ? item.children : [item.children];
2637
+ const childFields = extractFieldsFromGroupingModel(children);
2638
+ childFields.forEach((field) => fields.add(field));
2639
+ } else {
2640
+ fields.add(item.field);
2641
+ }
2642
+ }
2643
+ return fields;
2644
+ }
2645
+ function reorderColumnsByGroupingModel(columns, columnGroupingModel) {
2646
+ const fieldsInGroupingModel = extractFieldsFromGroupingModel(columnGroupingModel);
2647
+ const orderedFields = [];
2648
+ function collectFieldsInOrder(items) {
2649
+ for (const item of items) {
2650
+ if ("groupId" in item) {
2651
+ const children = Array.isArray(item.children) ? item.children : [item.children];
2652
+ collectFieldsInOrder(children);
2653
+ } else {
2654
+ if (!orderedFields.includes(item.field)) {
2655
+ orderedFields.push(item.field);
2656
+ }
2657
+ }
2658
+ }
2659
+ }
2660
+ collectFieldsInOrder(columnGroupingModel);
2661
+ const columnMap = new Map(columns.map((col) => [col.field, col]));
2662
+ const reorderedColumns = [];
2663
+ for (const field of orderedFields) {
2664
+ const column = columnMap.get(field);
2665
+ if (column) {
2666
+ reorderedColumns.push(column);
2667
+ }
2668
+ }
2669
+ for (const column of columns) {
2670
+ if (!fieldsInGroupingModel.has(column.field)) {
2671
+ reorderedColumns.push(column);
2672
+ }
2673
+ }
2674
+ return reorderedColumns;
2675
+ }
2676
+ function flattenColumnGroups(items, groupPath = [], columnIndex = { current: 0 }) {
2677
+ const result = [];
2678
+ for (const item of items) {
2679
+ if ("groupId" in item) {
2680
+ const newPath = [...groupPath, item.groupId];
2681
+ const children = Array.isArray(item.children) ? item.children : [item.children];
2682
+ result.push(...flattenColumnGroups(children, newPath, columnIndex));
2683
+ } else {
2684
+ result.push({
2685
+ ...item,
2686
+ groupPath,
2687
+ columnIndex: columnIndex.current++
2688
+ });
2689
+ }
2690
+ }
2691
+ return result;
2692
+ }
2693
+ function calculateColumnGroups(columnGroupingModel, columns) {
2694
+ const fieldsInGroupingModel = extractFieldsFromGroupingModel(columnGroupingModel);
2695
+ const flattenedColumns = flattenColumnGroups(columnGroupingModel);
2696
+ const columnIndexMap = new Map(flattenedColumns.map((col) => [col.field, col.columnIndex]));
2697
+ const processedGroups = /* @__PURE__ */ new Map();
2698
+ const groupsByLevel = [];
2699
+ let maxLevel = 0;
2700
+ function processGroup(items, level, parentGroupId) {
2701
+ let minIndex = Infinity;
2702
+ let maxIndex = -Infinity;
2703
+ for (const item of items) {
2704
+ if ("groupId" in item) {
2705
+ const groupKey = parentGroupId ? `${parentGroupId}.${item.groupId}` : item.groupId;
2706
+ if (!processedGroups.has(groupKey)) {
2707
+ const children = Array.isArray(item.children) ? item.children : [item.children];
2708
+ const { startIndex, colspan } = processGroup(children, level + 1, groupKey);
2709
+ const group = {
2710
+ groupId: item.groupId,
2711
+ headerName: item.headerName,
2712
+ colspan,
2713
+ level,
2714
+ startIndex
2715
+ };
2716
+ processedGroups.set(groupKey, group);
2717
+ if (!groupsByLevel[level]) {
2718
+ groupsByLevel[level] = [];
2719
+ }
2720
+ groupsByLevel[level].push(group);
2721
+ maxLevel = Math.max(maxLevel, level);
2722
+ minIndex = Math.min(minIndex, startIndex);
2723
+ maxIndex = Math.max(maxIndex, startIndex + colspan - 1);
2724
+ }
2725
+ } else {
2726
+ const columnIndex = columnIndexMap.get(item.field);
2727
+ if (columnIndex !== void 0) {
2728
+ minIndex = Math.min(minIndex, columnIndex);
2729
+ maxIndex = Math.max(maxIndex, columnIndex);
2730
+ }
2731
+ }
2732
+ }
2733
+ return {
2734
+ startIndex: minIndex === Infinity ? 0 : minIndex,
2735
+ colspan: maxIndex === -Infinity ? 0 : maxIndex - minIndex + 1
2736
+ };
2737
+ }
2738
+ processGroup(columnGroupingModel, 0);
2739
+ groupsByLevel.forEach((level) => {
2740
+ level.sort((a, b) => a.startIndex - b.startIndex);
2741
+ });
2742
+ return { groups: groupsByLevel, maxLevel, fieldsInGroupingModel };
2743
+ }
2631
2744
  function getTextAlign(props) {
2632
2745
  return !props.editMode && ["number", "date", "currency"].includes(props.type || "") ? "end" : "start";
2633
2746
  }
@@ -2698,7 +2811,7 @@ var OverlayWrapper = styled12("tr", {
2698
2811
  }
2699
2812
  });
2700
2813
  var numberFormatter = (value) => "Intl" in window ? new Intl.NumberFormat().format(value) : value;
2701
- var Resizer = (ref) => /* @__PURE__ */ React23.createElement(
2814
+ var Resizer = (ref, targetRef = ref) => /* @__PURE__ */ React23.createElement(
2702
2815
  Box_default,
2703
2816
  {
2704
2817
  sx: {
@@ -2716,6 +2829,7 @@ var Resizer = (ref) => /* @__PURE__ */ React23.createElement(
2716
2829
  const onMouseMove = (e2) => {
2717
2830
  if (initialWidth && initialX) {
2718
2831
  ref.current.style.width = `${initialWidth + (e2.clientX - initialX)}px`;
2832
+ targetRef.current.style.width = `${initialWidth + (e2.clientX - initialX)}px`;
2719
2833
  }
2720
2834
  };
2721
2835
  const onMouseUp = () => {
@@ -2826,17 +2940,19 @@ var HeadCell = (props) => {
2826
2940
  isPinned,
2827
2941
  pinnedStartPosition,
2828
2942
  pinnedEndPosition,
2829
- headerRef
2943
+ headerRef,
2944
+ tableColRef
2830
2945
  } = props;
2831
2946
  const theme = useTheme();
2832
2947
  const ref = headerRef;
2948
+ const colRef = tableColRef;
2833
2949
  const [isHovered, setIsHovered] = useState6(false);
2834
2950
  const sortable = type === "actions" ? false : _sortable;
2835
2951
  const headId = useMemo8(
2836
2952
  () => `${tableId}_header_${headerName ?? field}`.trim(),
2837
2953
  [tableId, headerName, field]
2838
2954
  );
2839
- const resizer = useMemo8(() => resizable ?? true ? Resizer(ref) : null, [resizable, ref]);
2955
+ const resizer = useMemo8(() => resizable ?? true ? Resizer(ref, colRef) : null, [resizable, ref, colRef]);
2840
2956
  const style = useMemo8(
2841
2957
  () => ({
2842
2958
  width,
@@ -3171,8 +3287,15 @@ function useDataTableRenderer({
3171
3287
  editMode,
3172
3288
  getId: _getId,
3173
3289
  isTotalSelected: _isTotalSelected,
3174
- isRowSelectable
3290
+ isRowSelectable,
3291
+ columnGroupingModel
3292
+ // Add this prop
3175
3293
  }) {
3294
+ if (pinnedColumns && columnGroupingModel) {
3295
+ throw new Error(
3296
+ "You cannot use both `pinnedColumns` and `columnGroupingModel` at the same time. Please choose one of them."
3297
+ );
3298
+ }
3176
3299
  const onSelectionModelChangeRef = useRef4(onSelectionModelChange);
3177
3300
  onSelectionModelChangeRef.current = onSelectionModelChange;
3178
3301
  const [focusedRowId, setFocusedRowId] = useState6(null);
@@ -3181,18 +3304,23 @@ function useDataTableRenderer({
3181
3304
  initialState?.sorting?.sortModel ?? [],
3182
3305
  useCallback9((sortModel2) => onSortModelChange?.(sortModel2), [onSortModelChange])
3183
3306
  );
3307
+ const reorderedColumns = useMemo8(() => {
3308
+ if (!columnGroupingModel) return columnsProp;
3309
+ return reorderColumnsByGroupingModel(columnsProp, columnGroupingModel);
3310
+ }, [columnsProp, columnGroupingModel]);
3184
3311
  const columnsByField = useMemo8(
3185
- () => columnsProp.reduce(
3312
+ () => reorderedColumns.reduce(
3186
3313
  (acc, curr) => ({
3187
3314
  ...acc,
3188
3315
  [curr.field]: {
3189
3316
  ...curr,
3190
- headerRef: React23.createRef()
3317
+ headerRef: React23.createRef(),
3318
+ tableColRef: React23.createRef()
3191
3319
  }
3192
3320
  }),
3193
3321
  {}
3194
3322
  ),
3195
- [columnsProp]
3323
+ [reorderedColumns]
3196
3324
  );
3197
3325
  const sortComparator = useCallback9(
3198
3326
  (rowA, rowB) => {
@@ -3272,11 +3400,17 @@ function useDataTableRenderer({
3272
3400
  columnsByField[f].minWidth ?? 0,
3273
3401
  [columnWidths, columnsByField]
3274
3402
  );
3403
+ const processedColumnGroups = useMemo8(() => {
3404
+ if (!columnGroupingModel) return null;
3405
+ return calculateColumnGroups(columnGroupingModel, reorderedColumns);
3406
+ }, [columnGroupingModel, reorderedColumns]);
3275
3407
  const columns = useMemo8(() => {
3276
- const baseColumns = columnsProp || // fallback
3277
- Object.keys(rows[0] || {}).map((key) => ({
3278
- field: key
3279
- }));
3408
+ const baseColumns = reorderedColumns.length > 0 ? reorderedColumns : (
3409
+ // fallback
3410
+ Object.keys(rows[0] || {}).map((key) => ({
3411
+ field: key
3412
+ }))
3413
+ );
3280
3414
  return baseColumns.map((column) => {
3281
3415
  const isLeftPinned = pinnedColumns?.left?.includes(column.field);
3282
3416
  const isRightPinned = pinnedColumns?.right?.includes(column.field);
@@ -3284,6 +3418,7 @@ function useDataTableRenderer({
3284
3418
  return {
3285
3419
  ...column,
3286
3420
  headerRef: columnsByField[column.field].headerRef,
3421
+ tableColRef: columnsByField[column.field].tableColRef,
3287
3422
  isCellEditable: editMode && (typeof column.isCellEditable === "function" ? column.isCellEditable : column.isCellEditable ?? true),
3288
3423
  sort: sortModel.find((sort) => sort.field === column.field)?.sort,
3289
3424
  sortOrder: columnsByField[column.field]?.sortOrder || sortOrder,
@@ -3296,7 +3431,7 @@ function useDataTableRenderer({
3296
3431
  };
3297
3432
  });
3298
3433
  }, [
3299
- columnsProp,
3434
+ reorderedColumns,
3300
3435
  rows,
3301
3436
  pinnedColumns?.left,
3302
3437
  pinnedColumns?.right,
@@ -3392,6 +3527,7 @@ function useDataTableRenderer({
3392
3527
  [selectionModel, onSelectionModelChange, selectedModelSet]
3393
3528
  ),
3394
3529
  columns,
3530
+ processedColumnGroups,
3395
3531
  onTotalSelect: useCallback9(() => {
3396
3532
  const selectableRows = rows.filter((row, i) => {
3397
3533
  if (!isRowSelectable) return true;
@@ -3434,6 +3570,8 @@ function Component(props, apiRef) {
3434
3570
  getId: ____________,
3435
3571
  // getId is used in useDataTableRenderer
3436
3572
  loading,
3573
+ columnGroupingModel: _________________,
3574
+ // columnGroupingModel is used in useDataTableRenderer
3437
3575
  slots: {
3438
3576
  checkbox: RenderCheckbox = Checkbox_default,
3439
3577
  toolbar: Toolbar,
@@ -3450,6 +3588,7 @@ function Component(props, apiRef) {
3450
3588
  const tableBodyRef = useRef4(null);
3451
3589
  const {
3452
3590
  columns,
3591
+ processedColumnGroups,
3453
3592
  isAllSelected,
3454
3593
  isSelectedRow,
3455
3594
  isRowSelectable: isRowSelectableCheck,
@@ -3557,7 +3696,8 @@ function Component(props, apiRef) {
3557
3696
  boxShadow: "sm",
3558
3697
  borderRadius: "sm",
3559
3698
  "--DataTableSheet-width": parentRef.current?.clientWidth + "px",
3560
- backgroundColor: "white"
3699
+ backgroundColor: "white",
3700
+ "--TableCell-cornerRadius": "0px"
3561
3701
  },
3562
3702
  className: [
3563
3703
  ...(parentRef.current?.scrollLeft || 0) > 0 ? ["ScrollableRight"] : [],
@@ -3566,12 +3706,30 @@ function Component(props, apiRef) {
3566
3706
  ref: parentRef,
3567
3707
  ...backgroundProps
3568
3708
  },
3569
- /* @__PURE__ */ React23.createElement(Table, { ...innerProps }, /* @__PURE__ */ React23.createElement("thead", null, /* @__PURE__ */ React23.createElement("tr", null, checkboxSelection && /* @__PURE__ */ React23.createElement(
3709
+ /* @__PURE__ */ React23.createElement(Table, { ...innerProps }, /* @__PURE__ */ React23.createElement("colgroup", null, checkboxSelection && /* @__PURE__ */ React23.createElement(
3710
+ "col",
3711
+ {
3712
+ style: {
3713
+ width: "40px"
3714
+ }
3715
+ }
3716
+ ), columns.map((c) => /* @__PURE__ */ React23.createElement(
3717
+ "col",
3718
+ {
3719
+ ref: c.tableColRef,
3720
+ key: `${c.field.toString()}_${c.width}`,
3721
+ style: {
3722
+ width: c.width
3723
+ }
3724
+ }
3725
+ ))), /* @__PURE__ */ React23.createElement("thead", null, processedColumnGroups && processedColumnGroups.groups.map((levelGroups, level) => /* @__PURE__ */ React23.createElement("tr", { key: `group-level-${level}` }, checkboxSelection && level === 0 && /* @__PURE__ */ React23.createElement(
3570
3726
  "th",
3571
3727
  {
3728
+ rowSpan: processedColumnGroups.maxLevel + 2,
3572
3729
  style: {
3573
3730
  width: "40px",
3574
- textAlign: "center"
3731
+ textAlign: "center",
3732
+ verticalAlign: "middle"
3575
3733
  }
3576
3734
  },
3577
3735
  /* @__PURE__ */ React23.createElement(
@@ -3584,16 +3742,52 @@ function Component(props, apiRef) {
3584
3742
  ...checkboxProps
3585
3743
  }
3586
3744
  )
3587
- ), columns.map((c, i) => /* @__PURE__ */ React23.createElement(
3588
- HeadCell2,
3745
+ ), level > 0 && Array.from({ length: levelGroups[0]?.startIndex || 0 }).map((_2, i) => /* @__PURE__ */ React23.createElement("th", { key: `empty-${level}-${i}` })), levelGroups.map((group, groupIndex) => {
3746
+ const nextGroup = levelGroups[groupIndex + 1];
3747
+ const emptyCells = nextGroup ? nextGroup.startIndex - (group.startIndex + group.colspan) : columns.length - (group.startIndex + group.colspan);
3748
+ return /* @__PURE__ */ React23.createElement(Fragment2, { key: group.groupId }, /* @__PURE__ */ React23.createElement(
3749
+ "th",
3750
+ {
3751
+ colSpan: group.colspan,
3752
+ style: {
3753
+ textAlign: "center",
3754
+ fontWeight: "bold",
3755
+ verticalAlign: "middle"
3756
+ }
3757
+ },
3758
+ group.headerName ?? group.groupId
3759
+ ), emptyCells > 0 && Array.from({ length: emptyCells }).map((_2, i) => /* @__PURE__ */ React23.createElement("th", { key: `empty-between-${level}-${groupIndex}-${i}`, colSpan: 1 })));
3760
+ }))), /* @__PURE__ */ React23.createElement("tr", null, !processedColumnGroups && checkboxSelection && /* @__PURE__ */ React23.createElement(
3761
+ "th",
3589
3762
  {
3590
- tableId,
3591
- key: `${c.field.toString()}_${i}`,
3592
- stickyHeader: props.stickyHeader,
3593
- editMode: !!c.isCellEditable,
3594
- onSortChange: handleSortChange,
3595
- ...c
3596
- }
3763
+ style: {
3764
+ width: "40px",
3765
+ textAlign: "center"
3766
+ }
3767
+ },
3768
+ /* @__PURE__ */ React23.createElement(
3769
+ RenderCheckbox,
3770
+ {
3771
+ onChange: onAllCheckboxChange,
3772
+ checked: isAllSelected,
3773
+ indeterminate: (selectionModel || []).length > 0 && !isAllSelected,
3774
+ disabled: dataInPage.length > 0 && !selectableRowCount,
3775
+ ...checkboxProps
3776
+ }
3777
+ )
3778
+ ), columns.map((c, i) => (
3779
+ // @ts-ignore
3780
+ /* @__PURE__ */ React23.createElement(
3781
+ HeadCell2,
3782
+ {
3783
+ tableId,
3784
+ key: `${c.field.toString()}_${i}`,
3785
+ stickyHeader: props.stickyHeader,
3786
+ editMode: !!c.isCellEditable,
3787
+ onSortChange: handleSortChange,
3788
+ ...c
3789
+ }
3790
+ )
3597
3791
  )))), /* @__PURE__ */ React23.createElement(
3598
3792
  VirtualizedTableBody,
3599
3793
  {