@ceed/cds 1.40.3-next.6 → 1.40.3-next.8

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.cjs CHANGED
@@ -460,16 +460,25 @@ function useSlotRef(slotProp, ref) {
460
460
  const isFunctionForm = typeof slotProp === "function";
461
461
  const slotRef = isFunctionForm ? void 0 : slotProp?.ref;
462
462
  const mergedRef = useMergedRef(slotRef, ref);
463
+ const latestSlotRef = (0, import_react6.useRef)(null);
464
+ const stableMergedRef = (0, import_react6.useCallback)(
465
+ (value) => {
466
+ assignRef(latestSlotRef.current, value);
467
+ assignRef(ref, value);
468
+ },
469
+ [ref]
470
+ );
463
471
  return (0, import_react6.useMemo)(() => {
464
472
  if (isFunctionForm) {
465
473
  return ((ownerState) => {
466
474
  const resolved = slotProp(ownerState) ?? {};
467
- const merged = mergeRefs(resolved.ref, ref);
468
- return merged ? { ...resolved, ref: merged } : { ...resolved };
475
+ const resolvedRef = resolved.ref;
476
+ latestSlotRef.current = resolvedRef ?? null;
477
+ return resolvedRef || ref ? { ...resolved, ref: stableMergedRef } : { ...resolved };
469
478
  });
470
479
  }
471
480
  return mergedRef ? { ...slotProp, ref: mergedRef } : { ...slotProp };
472
- }, [isFunctionForm, slotProp, mergedRef, ref]);
481
+ }, [isFunctionForm, slotProp, mergedRef, ref, stableMergedRef]);
473
482
  }
474
483
 
475
484
  // src/components/Autocomplete/Autocomplete.tsx
@@ -2611,8 +2620,11 @@ function computeAutoFitWidth(params) {
2611
2620
  if (!isNaN(maxPx) && maxPx > 0) finalWidth = Math.min(finalWidth, maxPx);
2612
2621
  return finalWidth;
2613
2622
  }
2614
- function getHeaderCellId(tableId, columnId) {
2615
- return `${tableId}_header_${columnId}`.trim().replace(/\s+/g, "_");
2623
+ function getHeaderCellId(tableId, field) {
2624
+ return `${tableId}_header_${sanitizeColumnId(field)}`;
2625
+ }
2626
+ function sanitizeColumnId(field) {
2627
+ return String(field).trim().replace(/\s+/g, "_");
2616
2628
  }
2617
2629
 
2618
2630
  // src/components/DataTable/styled.tsx
@@ -3557,8 +3569,7 @@ var HeadCell = (props) => {
3557
3569
  tableColRef,
3558
3570
  headerClassName,
3559
3571
  headerLineClamp,
3560
- onAutoFit,
3561
- columnId
3572
+ onAutoFit
3562
3573
  } = props;
3563
3574
  const theme = (0, import_joy33.useTheme)();
3564
3575
  const ref = headerRef;
@@ -3569,7 +3580,7 @@ var HeadCell = (props) => {
3569
3580
  }, [ref]);
3570
3581
  const [isHovered, setIsHovered] = (0, import_react26.useState)(false);
3571
3582
  const sortable = type === "actions" ? false : _sortable;
3572
- const headId = (0, import_react26.useMemo)(() => getHeaderCellId(tableId, columnId), [tableId, columnId]);
3583
+ const headId = (0, import_react26.useMemo)(() => getHeaderCellId(tableId, field), [tableId, field]);
3573
3584
  const isResizingRef = (0, import_react26.useRef)(false);
3574
3585
  const resizer = (0, import_react26.useMemo)(
3575
3586
  () => resizable ?? true ? Resizer(
@@ -3578,9 +3589,9 @@ var HeadCell = (props) => {
3578
3589
  (isResizing) => {
3579
3590
  isResizingRef.current = isResizing;
3580
3591
  },
3581
- onAutoFit ? () => onAutoFit(columnId) : void 0
3592
+ onAutoFit ? () => onAutoFit(field) : void 0
3582
3593
  ) : null,
3583
- [resizable, ref, colRef, onAutoFit, columnId]
3594
+ [resizable, ref, colRef, onAutoFit, field]
3584
3595
  );
3585
3596
  const style = (0, import_react26.useMemo)(
3586
3597
  () => ({
@@ -3850,7 +3861,7 @@ var BodyCell = (props) => {
3850
3861
  {
3851
3862
  ref: cellRef,
3852
3863
  key: field,
3853
- headers: getHeaderCellId(tableId, props.columnId),
3864
+ headers: getHeaderCellId(tableId, field),
3854
3865
  sx: {
3855
3866
  textAlign: getTextAlign({ type }),
3856
3867
  verticalAlign: editMode ? "top" : "middle",
@@ -3916,7 +3927,7 @@ var VirtualizedTableRow = (0, import_react26.memo)(StyledTableRow2, (prevProps,
3916
3927
 
3917
3928
  // src/components/DataTable/hooks.ts
3918
3929
  var import_react27 = require("react");
3919
- function useColumnWidths(columnsById) {
3930
+ function useColumnWidths(columnsByField) {
3920
3931
  const [widths, setWidths] = (0, import_react27.useState)({});
3921
3932
  const roRef = (0, import_react27.useRef)();
3922
3933
  (0, import_react27.useLayoutEffect)(() => {
@@ -3926,11 +3937,11 @@ function useColumnWidths(columnsById) {
3926
3937
  let changed = false;
3927
3938
  const next = { ...prev };
3928
3939
  entries.forEach((entry) => {
3929
- const columnId = entry.target.dataset.hdsColumnId;
3940
+ const field = entry.target.dataset.field;
3930
3941
  const w = Math.round(entry.target.getBoundingClientRect().width);
3931
3942
  if (w === 0) return;
3932
- if (next[columnId] !== w) {
3933
- next[columnId] = w;
3943
+ if (next[field] !== w) {
3944
+ next[field] = w;
3934
3945
  changed = true;
3935
3946
  }
3936
3947
  });
@@ -3938,23 +3949,22 @@ function useColumnWidths(columnsById) {
3938
3949
  });
3939
3950
  });
3940
3951
  const measured = {};
3941
- Object.entries(columnsById).forEach(([columnId, def]) => {
3952
+ Object.entries(columnsByField).forEach(([field, def]) => {
3942
3953
  const el = def.headerRef.current;
3943
3954
  if (el) {
3944
- el.dataset.hdsColumnId = columnId;
3945
- el.dataset.field = String(def.field);
3955
+ el.dataset.field = field;
3946
3956
  const w = Math.round(el.getBoundingClientRect().width);
3947
- if (w > 0) measured[columnId] = w;
3957
+ if (w > 0) measured[field] = w;
3948
3958
  roRef.current.observe(el);
3949
3959
  }
3950
3960
  });
3951
3961
  setWidths((prev) => {
3952
3962
  const keys = Object.keys(measured);
3953
- const same = keys.length === Object.keys(prev).length && keys.every((key) => prev[key] === measured[key]);
3954
- return same ? prev : measured;
3963
+ const same = keys.every((key) => prev[key] === measured[key]);
3964
+ return same ? prev : { ...prev, ...measured };
3955
3965
  });
3956
3966
  return () => roRef.current?.disconnect();
3957
- }, [columnsById]);
3967
+ }, [columnsByField]);
3958
3968
  return widths;
3959
3969
  }
3960
3970
  function useDataTableRenderer({
@@ -3986,6 +3996,13 @@ function useDataTableRenderer({
3986
3996
  "You cannot use both `pinnedColumns` and `columnGroupingModel` at the same time. Please choose one of them."
3987
3997
  );
3988
3998
  }
3999
+ const duplicatedField = (0, import_react27.useMemo)(() => {
4000
+ const ids = columnsProp.map((column) => sanitizeColumnId(column.field));
4001
+ const index = ids.findIndex((id, i) => ids.indexOf(id) !== i);
4002
+ return index === -1 ? void 0 : columnsProp[index].field;
4003
+ }, [columnsProp]);
4004
+ if (duplicatedField !== void 0)
4005
+ throw new Error(`DataTable: column \`field\` must be unique. Duplicated: "${String(duplicatedField)}"`);
3989
4006
  const onSelectionModelChangeRef = (0, import_react27.useRef)(onSelectionModelChange);
3990
4007
  onSelectionModelChangeRef.current = onSelectionModelChange;
3991
4008
  const [focusedRowId, setFocusedRowId] = (0, import_react27.useState)(null);
@@ -4007,16 +4024,9 @@ function useDataTableRenderer({
4007
4024
  if (!columnGroupingModel) return columnsProp;
4008
4025
  return reorderColumnsByGroupingModel(columnsProp, columnGroupingModel);
4009
4026
  }, [columnsProp, columnGroupingModel]);
4010
- const visibleColumnIndexes = (0, import_react27.useMemo)(
4011
- () => reorderedColumns.reduce((acc, col, index) => {
4012
- if (visibilityModel[col.field] !== false) acc.push(index);
4013
- return acc;
4014
- }, []),
4015
- [reorderedColumns, visibilityModel]
4016
- );
4017
4027
  const visibleColumns = (0, import_react27.useMemo)(
4018
- () => visibleColumnIndexes.map((index) => reorderedColumns[index]),
4019
- [visibleColumnIndexes, reorderedColumns]
4028
+ () => reorderedColumns.filter((col) => visibilityModel[col.field] !== false),
4029
+ [reorderedColumns, visibilityModel]
4020
4030
  );
4021
4031
  const visibleFieldSet = (0, import_react27.useMemo)(() => new Set(visibleColumns.map((c) => c.field)), [visibleColumns]);
4022
4032
  const tableMinWidth = (0, import_react27.useMemo)(() => {
@@ -4037,29 +4047,10 @@ function useDataTableRenderer({
4037
4047
  ),
4038
4048
  [reorderedColumns]
4039
4049
  );
4040
- const allColumnIds = (0, import_react27.useMemo)(() => {
4041
- const taken = new Set(reorderedColumns.map((column) => String(column.field)));
4042
- const assigned = /* @__PURE__ */ new Set();
4043
- return reorderedColumns.map((column) => {
4044
- const field = String(column.field);
4045
- if (!assigned.has(field)) {
4046
- assigned.add(field);
4047
- return field;
4048
- }
4049
- let n = 2;
4050
- while (taken.has(`${field}__${n}`)) n += 1;
4051
- taken.add(`${field}__${n}`);
4052
- return `${field}__${n}`;
4053
- });
4054
- }, [reorderedColumns]);
4055
- const columnIds = (0, import_react27.useMemo)(
4056
- () => visibleColumnIndexes.map((index) => allColumnIds[index]),
4057
- [visibleColumnIndexes, allColumnIds]
4058
- );
4059
- const visibleColumnsById = (0, import_react27.useMemo)(
4050
+ const visibleColumnsByField = (0, import_react27.useMemo)(
4060
4051
  () => Object.fromEntries(
4061
- visibleColumns.map((column, index) => [
4062
- columnIds[index],
4052
+ visibleColumns.map((column) => [
4053
+ column.field,
4063
4054
  {
4064
4055
  ...column,
4065
4056
  headerRef: (0, import_react27.createRef)(),
@@ -4067,7 +4058,7 @@ function useDataTableRenderer({
4067
4058
  }
4068
4059
  ])
4069
4060
  ),
4070
- [visibleColumns, columnIds]
4061
+ [visibleColumns]
4071
4062
  );
4072
4063
  const sortComparator = (0, import_react27.useCallback)(
4073
4064
  (rowA, rowB) => {
@@ -4160,18 +4151,12 @@ function useDataTableRenderer({
4160
4151
  () => _isTotalSelected ?? (selectableRowCount > 0 && (selectionModel?.length || 0) === selectableRowCount),
4161
4152
  [_isTotalSelected, selectionModel, selectableRowCount]
4162
4153
  );
4163
- const columnWidths = useColumnWidths(visibleColumnsById);
4164
- const measuredWidthByField = (0, import_react27.useMemo)(
4165
- () => Object.fromEntries(
4166
- Object.entries(visibleColumnsById).map(([columnId, column]) => [column.field, columnWidths[columnId]])
4167
- ),
4168
- [visibleColumnsById, columnWidths]
4169
- );
4154
+ const columnWidths = useColumnWidths(visibleColumnsByField);
4170
4155
  const getWidth = (0, import_react27.useCallback)(
4171
4156
  // 반환값은 pinned offset으로 더해지므로 반드시 숫자여야 한다. width/minWidth는 '500px' 같은 문자열.
4172
- (f) => measuredWidthByField[f] ?? parsePxValue(allColumnsByField[f]?.width) ?? // Column prop 으로 지정된 width
4157
+ (f) => columnWidths[f] ?? parsePxValue(allColumnsByField[f]?.width) ?? // Column prop 으로 지정된 width
4173
4158
  parsePxValue(allColumnsByField[f]?.minWidth) ?? 0,
4174
- [measuredWidthByField, allColumnsByField]
4159
+ [columnWidths, allColumnsByField]
4175
4160
  );
4176
4161
  const processedColumnGroups = (0, import_react27.useMemo)(() => {
4177
4162
  if (!columnGroupingModel) return null;
@@ -4191,16 +4176,14 @@ function useDataTableRenderer({
4191
4176
  const baseColumns = visibleColumns.length > 0 ? visibleColumns : reorderedColumns.length > 0 ? [] : inferredFields.map((key) => ({
4192
4177
  field: key
4193
4178
  }));
4194
- return baseColumns.map((column, index) => {
4195
- const columnId = columnIds[index] ?? String(column.field);
4179
+ return baseColumns.map((column) => {
4196
4180
  const isLeftPinned = effectivePinnedLeft?.includes(column.field);
4197
4181
  const isRightPinned = effectivePinnedRight?.includes(column.field);
4198
4182
  const isPinned = isLeftPinned || isRightPinned;
4199
4183
  return {
4200
4184
  ...column,
4201
- columnId,
4202
- headerRef: visibleColumnsById[columnId]?.headerRef,
4203
- tableColRef: visibleColumnsById[columnId]?.tableColRef,
4185
+ headerRef: visibleColumnsByField[column.field]?.headerRef,
4186
+ tableColRef: visibleColumnsByField[column.field]?.tableColRef,
4204
4187
  isCellEditable: editMode && (typeof column.isCellEditable === "function" ? column.isCellEditable : column.isCellEditable ?? true),
4205
4188
  sort: sortModel.find((sort) => sort.field === column.field)?.sort,
4206
4189
  sortOrder: allColumnsByField[column.field]?.sortOrder || sortOrder,
@@ -4217,8 +4200,7 @@ function useDataTableRenderer({
4217
4200
  inferredFields,
4218
4201
  effectivePinnedLeft,
4219
4202
  effectivePinnedRight,
4220
- columnIds,
4221
- visibleColumnsById,
4203
+ visibleColumnsByField,
4222
4204
  allColumnsByField,
4223
4205
  editMode,
4224
4206
  sortModel,
@@ -4278,8 +4260,8 @@ function useDataTableRenderer({
4278
4260
  }
4279
4261
  }, [_rows]);
4280
4262
  const handleAutoFit = (0, import_react27.useCallback)(
4281
- (columnId) => {
4282
- const colDef = visibleColumnsById[columnId];
4263
+ (field) => {
4264
+ const colDef = visibleColumnsByField[field];
4283
4265
  if (!colDef?.headerRef.current) return;
4284
4266
  const columnType = "type" in colDef ? colDef.type : void 0;
4285
4267
  if (columnType === "actions") return;
@@ -4293,7 +4275,7 @@ function useDataTableRenderer({
4293
4275
  colDef.headerRef.current.style.width = widthPx;
4294
4276
  if (colDef.tableColRef.current) colDef.tableColRef.current.style.width = widthPx;
4295
4277
  },
4296
- [visibleColumnsById, dataInPage]
4278
+ [visibleColumnsByField, dataInPage]
4297
4279
  );
4298
4280
  return {
4299
4281
  rowCount,
@@ -4980,7 +4962,7 @@ function Component(props, apiRef) {
4980
4962
  "col",
4981
4963
  {
4982
4964
  ref: c.tableColRef,
4983
- key: c.columnId,
4965
+ key: c.field.toString(),
4984
4966
  style: {
4985
4967
  width: c.width,
4986
4968
  minWidth: c.minWidth ?? "50px"
@@ -5030,13 +5012,13 @@ function Component(props, apiRef) {
5030
5012
  }
5031
5013
  },
5032
5014
  headerCheckboxElement
5033
- ), columns.map((c, i) => (
5015
+ ), columns.map((c) => (
5034
5016
  // @ts-ignore
5035
5017
  /* @__PURE__ */ import_react30.default.createElement(
5036
5018
  HeadCell2,
5037
5019
  {
5038
5020
  tableId,
5039
- key: `${c.field.toString()}_${i}`,
5021
+ key: c.field.toString(),
5040
5022
  stickyHeader: props.stickyHeader,
5041
5023
  editMode: !!c.isCellEditable,
5042
5024
  onSortChange: handleSortChange,