@ceed/cds 1.25.0 → 1.27.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.cjs CHANGED
@@ -2136,14 +2136,15 @@ function reorderColumnsByGroupingModel(columns, columnGroupingModel) {
2136
2136
  }
2137
2137
  return reorderedColumns;
2138
2138
  }
2139
- function flattenColumnGroups(items, groupPath = [], columnIndex = { current: 0 }) {
2139
+ function flattenColumnGroups(items, groupPath = [], columnIndex = { current: 0 }, visibleFields) {
2140
2140
  const result = [];
2141
2141
  for (const item of items) {
2142
2142
  if ("groupId" in item) {
2143
2143
  const newPath = [...groupPath, item.groupId];
2144
2144
  const children = Array.isArray(item.children) ? item.children : [item.children];
2145
- result.push(...flattenColumnGroups(children, newPath, columnIndex));
2145
+ result.push(...flattenColumnGroups(children, newPath, columnIndex, visibleFields));
2146
2146
  } else {
2147
+ if (visibleFields && !visibleFields.has(item.field)) continue;
2147
2148
  result.push({
2148
2149
  ...item,
2149
2150
  groupPath,
@@ -2153,9 +2154,9 @@ function flattenColumnGroups(items, groupPath = [], columnIndex = { current: 0 }
2153
2154
  }
2154
2155
  return result;
2155
2156
  }
2156
- function calculateColumnGroups(columnGroupingModel, columns) {
2157
+ function calculateColumnGroups(columnGroupingModel, columns, visibleFields) {
2157
2158
  const fieldsInGroupingModel = extractFieldsFromGroupingModel(columnGroupingModel);
2158
- const flattenedColumns = flattenColumnGroups(columnGroupingModel);
2159
+ const flattenedColumns = flattenColumnGroups(columnGroupingModel, [], { current: 0 }, visibleFields);
2159
2160
  const columnIndexMap = new Map(flattenedColumns.map((col) => [col.field, col.columnIndex]));
2160
2161
  const processedGroups = /* @__PURE__ */ new Map();
2161
2162
  const groupsByLevel = [];
@@ -2203,7 +2204,9 @@ function calculateColumnGroups(columnGroupingModel, columns) {
2203
2204
  groupsByLevel.forEach((level) => {
2204
2205
  level.sort((a, b) => a.startIndex - b.startIndex);
2205
2206
  });
2206
- return { groups: groupsByLevel, maxLevel, fieldsInGroupingModel };
2207
+ const filteredGroupsByLevel = groupsByLevel.map((level) => level.filter((g) => g.colspan > 0)).filter((level) => level.length > 0);
2208
+ const correctedMaxLevel = filteredGroupsByLevel.length > 0 ? filteredGroupsByLevel.length - 1 : -1;
2209
+ return { groups: filteredGroupsByLevel, maxLevel: correctedMaxLevel, fieldsInGroupingModel };
2207
2210
  }
2208
2211
  function getTextAlign(props) {
2209
2212
  return !props.editMode && ["number", "date", "currency"].includes(props.type || "") ? "end" : "start";
@@ -2318,6 +2321,7 @@ var StyledTd = (0, import_joy25.styled)("td")(({ theme }) => ({
2318
2321
  }));
2319
2322
  var MotionSortIcon = (0, import_framer_motion17.motion)(import_ArrowUpwardRounded.default);
2320
2323
  var DefaultLoadingOverlay = () => /* @__PURE__ */ import_react19.default.createElement(import_joy25.LinearProgress, { value: 8, variant: "plain" });
2324
+ var DefaultNoRowsOverlay = () => /* @__PURE__ */ import_react19.default.createElement(import_joy25.Typography, { level: "body-sm", textColor: "text.tertiary" }, "No rows");
2321
2325
  var Resizer = (ref, targetRef = ref) => /* @__PURE__ */ import_react19.default.createElement(
2322
2326
  Box_default,
2323
2327
  {
@@ -3367,7 +3371,9 @@ function useDataTableRenderer({
3367
3371
  getId: _getId,
3368
3372
  isTotalSelected: _isTotalSelected,
3369
3373
  isRowSelectable,
3370
- columnGroupingModel
3374
+ columnGroupingModel,
3375
+ columnVisibilityModel,
3376
+ onColumnVisibilityModelChange
3371
3377
  }) {
3372
3378
  if (pinnedColumns && columnGroupingModel) {
3373
3379
  throw new Error(
@@ -3383,12 +3389,35 @@ function useDataTableRenderer({
3383
3389
  initialState?.sorting?.sortModel ?? [],
3384
3390
  (0, import_react25.useCallback)((sortModel2) => onSortModelChange?.(sortModel2), [onSortModelChange])
3385
3391
  );
3392
+ const [visibilityModel] = useControlledState(
3393
+ columnVisibilityModel,
3394
+ initialState?.columns?.columnVisibilityModel ?? {},
3395
+ (0, import_react25.useCallback)(
3396
+ (model) => onColumnVisibilityModelChange?.(model),
3397
+ [onColumnVisibilityModelChange]
3398
+ )
3399
+ );
3386
3400
  const reorderedColumns = (0, import_react25.useMemo)(() => {
3387
3401
  if (!columnGroupingModel) return columnsProp;
3388
3402
  return reorderColumnsByGroupingModel(columnsProp, columnGroupingModel);
3389
3403
  }, [columnsProp, columnGroupingModel]);
3390
- const columnsByField = (0, import_react25.useMemo)(
3404
+ const visibleColumns = (0, import_react25.useMemo)(
3405
+ () => reorderedColumns.filter((col) => visibilityModel[col.field] !== false),
3406
+ [reorderedColumns, visibilityModel]
3407
+ );
3408
+ const visibleFieldSet = (0, import_react25.useMemo)(() => new Set(visibleColumns.map((c) => c.field)), [visibleColumns]);
3409
+ const allColumnsByField = (0, import_react25.useMemo)(
3391
3410
  () => reorderedColumns.reduce(
3411
+ (acc, curr) => ({
3412
+ ...acc,
3413
+ [curr.field]: curr
3414
+ }),
3415
+ {}
3416
+ ),
3417
+ [reorderedColumns]
3418
+ );
3419
+ const visibleColumnsByField = (0, import_react25.useMemo)(
3420
+ () => visibleColumns.reduce(
3392
3421
  (acc, curr) => ({
3393
3422
  ...acc,
3394
3423
  [curr.field]: {
@@ -3399,7 +3428,7 @@ function useDataTableRenderer({
3399
3428
  }),
3400
3429
  {}
3401
3430
  ),
3402
- [reorderedColumns]
3431
+ [visibleColumns]
3403
3432
  );
3404
3433
  const sortComparator = (0, import_react25.useCallback)(
3405
3434
  (rowA, rowB) => {
@@ -3407,7 +3436,8 @@ function useDataTableRenderer({
3407
3436
  const { field, sort: direction } = sort;
3408
3437
  const a = rowA[field];
3409
3438
  const b = rowB[field];
3410
- const column = columnsByField[field];
3439
+ const column = allColumnsByField[field];
3440
+ if (!column) continue;
3411
3441
  let comparison = 0;
3412
3442
  if (column.sortComparator) {
3413
3443
  comparison = column.sortComparator({
@@ -3427,7 +3457,7 @@ function useDataTableRenderer({
3427
3457
  }
3428
3458
  return 0;
3429
3459
  },
3430
- [sortModel, columnsByField]
3460
+ [sortModel, allColumnsByField]
3431
3461
  );
3432
3462
  const rows = (0, import_react25.useMemo)(
3433
3463
  () => sortModel.length ? [..._rows].sort(sortComparator) : _rows,
@@ -3491,44 +3521,54 @@ function useDataTableRenderer({
3491
3521
  () => _isTotalSelected ?? (selectableRowCount > 0 && (selectionModel?.length || 0) === selectableRowCount),
3492
3522
  [_isTotalSelected, selectionModel, selectableRowCount]
3493
3523
  );
3494
- const columnWidths = useColumnWidths(columnsByField);
3524
+ const columnWidths = useColumnWidths(visibleColumnsByField);
3495
3525
  const getWidth = (0, import_react25.useCallback)(
3496
- (f) => columnWidths[f] ?? columnsByField[f].width ?? // Column prop 으로 지정된 width
3497
- columnsByField[f].minWidth ?? 0,
3498
- [columnWidths, columnsByField]
3526
+ (f) => columnWidths[f] ?? allColumnsByField[f]?.width ?? // Column prop 으로 지정된 width
3527
+ allColumnsByField[f]?.minWidth ?? 0,
3528
+ [columnWidths, allColumnsByField]
3499
3529
  );
3500
3530
  const processedColumnGroups = (0, import_react25.useMemo)(() => {
3501
3531
  if (!columnGroupingModel) return null;
3502
- return calculateColumnGroups(columnGroupingModel, reorderedColumns);
3503
- }, [columnGroupingModel, reorderedColumns]);
3532
+ return calculateColumnGroups(columnGroupingModel, visibleColumns, visibleFieldSet);
3533
+ }, [columnGroupingModel, visibleColumns, visibleFieldSet]);
3534
+ const effectivePinnedLeft = (0, import_react25.useMemo)(
3535
+ () => pinnedColumns?.left?.filter((f) => visibleFieldSet.has(f)),
3536
+ [pinnedColumns?.left, visibleFieldSet]
3537
+ );
3538
+ const effectivePinnedRight = (0, import_react25.useMemo)(
3539
+ () => pinnedColumns?.right?.filter((f) => visibleFieldSet.has(f)),
3540
+ [pinnedColumns?.right, visibleFieldSet]
3541
+ );
3504
3542
  const columns = (0, import_react25.useMemo)(() => {
3505
- const baseColumns = reorderedColumns.length > 0 ? reorderedColumns : Object.keys(rows[0] || {}).map((key) => ({
3543
+ const baseColumns = visibleColumns.length > 0 ? visibleColumns : reorderedColumns.length > 0 ? [] : Object.keys(rows[0] || {}).map((key) => ({
3506
3544
  field: key
3507
3545
  }));
3508
3546
  return baseColumns.map((column) => {
3509
- const isLeftPinned = pinnedColumns?.left?.includes(column.field);
3510
- const isRightPinned = pinnedColumns?.right?.includes(column.field);
3547
+ const isLeftPinned = effectivePinnedLeft?.includes(column.field);
3548
+ const isRightPinned = effectivePinnedRight?.includes(column.field);
3511
3549
  const isPinned = isLeftPinned || isRightPinned;
3512
3550
  return {
3513
3551
  ...column,
3514
- headerRef: columnsByField[column.field].headerRef,
3515
- tableColRef: columnsByField[column.field].tableColRef,
3552
+ headerRef: visibleColumnsByField[column.field]?.headerRef,
3553
+ tableColRef: visibleColumnsByField[column.field]?.tableColRef,
3516
3554
  isCellEditable: editMode && (typeof column.isCellEditable === "function" ? column.isCellEditable : column.isCellEditable ?? true),
3517
3555
  sort: sortModel.find((sort) => sort.field === column.field)?.sort,
3518
- sortOrder: columnsByField[column.field]?.sortOrder || sortOrder,
3556
+ sortOrder: allColumnsByField[column.field]?.sortOrder || sortOrder,
3519
3557
  isPinned,
3520
- isLastStartPinnedColumn: isLeftPinned && [...pinnedColumns?.left || []].pop() === column.field,
3521
- isLastEndPinnedColumn: isRightPinned && (pinnedColumns?.right?.[0] ?? null) === column.field,
3522
- pinnedStartPosition: pinnedColumns?.left?.slice(0, isLeftPinned ? pinnedColumns.left.indexOf(column.field) : pinnedColumns.left.length).reduce((acc, curr) => acc + getWidth(curr), 0),
3523
- pinnedEndPosition: pinnedColumns?.right?.slice(isRightPinned ? pinnedColumns.right.indexOf(column.field) + 1 : 0).reduce((acc, curr) => acc + getWidth(curr), 0)
3558
+ isLastStartPinnedColumn: isLeftPinned && [...effectivePinnedLeft || []].pop() === column.field,
3559
+ isLastEndPinnedColumn: isRightPinned && (effectivePinnedRight?.[0] ?? null) === column.field,
3560
+ pinnedStartPosition: effectivePinnedLeft?.slice(0, isLeftPinned ? effectivePinnedLeft.indexOf(column.field) : effectivePinnedLeft.length).reduce((acc, curr) => acc + getWidth(curr), 0),
3561
+ pinnedEndPosition: effectivePinnedRight?.slice(isRightPinned ? effectivePinnedRight.indexOf(column.field) + 1 : 0).reduce((acc, curr) => acc + getWidth(curr), 0)
3524
3562
  };
3525
3563
  });
3526
3564
  }, [
3565
+ visibleColumns,
3527
3566
  reorderedColumns,
3528
3567
  rows,
3529
- pinnedColumns?.left,
3530
- pinnedColumns?.right,
3531
- columnsByField,
3568
+ effectivePinnedLeft,
3569
+ effectivePinnedRight,
3570
+ visibleColumnsByField,
3571
+ allColumnsByField,
3532
3572
  editMode,
3533
3573
  sortModel,
3534
3574
  sortOrder,
@@ -3544,8 +3584,8 @@ function useDataTableRenderer({
3544
3584
  const handleSortChange = (0, import_react25.useCallback)(
3545
3585
  (props) => {
3546
3586
  const { field, currentSort, multiple } = props;
3547
- const column = columnsByField[field];
3548
- const columnSortOrder = column.sortOrder || sortOrder;
3587
+ const column = allColumnsByField[field];
3588
+ const columnSortOrder = column?.sortOrder || sortOrder;
3549
3589
  if (currentSort !== void 0) {
3550
3590
  const currentOrderIndex = columnSortOrder.indexOf(currentSort);
3551
3591
  const nextSortOrderIndex = (currentOrderIndex + 1) % columnSortOrder.length;
@@ -3562,7 +3602,7 @@ function useDataTableRenderer({
3562
3602
  setSortModel(newSortModel);
3563
3603
  }
3564
3604
  },
3565
- [sortOrder, columnsByField, sortModel, setSortModel]
3605
+ [sortOrder, allColumnsByField, sortModel, setSortModel]
3566
3606
  );
3567
3607
  (0, import_react25.useEffect)(() => {
3568
3608
  if (!paginationModel) {
@@ -3988,13 +4028,23 @@ function Component(props, apiRef) {
3988
4028
  loading,
3989
4029
  columnGroupingModel: _________________,
3990
4030
  // columnGroupingModel is used in useDataTableRenderer
4031
+ columnVisibilityModel: __________________,
4032
+ // columnVisibilityModel is used in useDataTableRenderer
4033
+ onColumnVisibilityModelChange: ___________________,
4034
+ // onColumnVisibilityModelChange is used in useDataTableRenderer
3991
4035
  slots: {
3992
4036
  checkbox: RenderCheckbox = Checkbox_default,
3993
4037
  toolbar: Toolbar,
3994
4038
  footer: Footer,
3995
- loadingOverlay: LoadingOverlay = DefaultLoadingOverlay
4039
+ loadingOverlay: LoadingOverlay = DefaultLoadingOverlay,
4040
+ noRowsOverlay: NoRowsOverlay = DefaultNoRowsOverlay
4041
+ } = {},
4042
+ slotProps: {
4043
+ checkbox: checkboxProps = {},
4044
+ toolbar: toolbarProps,
4045
+ background: backgroundProps = {},
4046
+ noRowsOverlay: noRowsOverlayProps = {}
3996
4047
  } = {},
3997
- slotProps: { checkbox: checkboxProps = {}, toolbar: toolbarProps, background: backgroundProps = {} } = {},
3998
4048
  stripe,
3999
4049
  isTotalSelected: ___________,
4000
4050
  ...innerProps
@@ -4038,6 +4088,8 @@ function Component(props, apiRef) {
4038
4088
  const paginationModel = (0, import_react28.useMemo)(() => ({ page, pageSize }), [page, pageSize]);
4039
4089
  const totalSize = virtualizer.getTotalSize();
4040
4090
  const virtualizedItems = virtualizer.getVirtualItems();
4091
+ const showNoRowsOverlay = !loading && rowCount === 0;
4092
+ const totalColCount = Math.max(1, columns.length + (checkboxSelection ? 1 : 0));
4041
4093
  const getRowClickHandler = (0, import_react28.useCallback)(
4042
4094
  (row, rowId) => (e) => {
4043
4095
  onRowClick?.({ row, rowId }, e);
@@ -4227,7 +4279,7 @@ function Component(props, apiRef) {
4227
4279
  width: c.width
4228
4280
  }
4229
4281
  }
4230
- ))), /* @__PURE__ */ import_react28.default.createElement("thead", null, processedColumnGroups && processedColumnGroups.groups.map((levelGroups, level) => /* @__PURE__ */ import_react28.default.createElement("tr", { key: `group-level-${level}` }, checkboxSelection && level === 0 && /* @__PURE__ */ import_react28.default.createElement(
4282
+ ))), /* @__PURE__ */ import_react28.default.createElement("thead", null, processedColumnGroups && processedColumnGroups.groups.length > 0 && processedColumnGroups.groups.map((levelGroups, level) => /* @__PURE__ */ import_react28.default.createElement("tr", { key: `group-level-${level}` }, checkboxSelection && level === 0 && /* @__PURE__ */ import_react28.default.createElement(
4231
4283
  "th",
4232
4284
  {
4233
4285
  rowSpan: processedColumnGroups.maxLevel + 2,
@@ -4247,7 +4299,7 @@ function Component(props, apiRef) {
4247
4299
  ...checkboxProps
4248
4300
  }
4249
4301
  )
4250
- ), level > 0 && Array.from({ length: levelGroups[0]?.startIndex || 0 }).map((_2, i) => /* @__PURE__ */ import_react28.default.createElement("th", { key: `empty-${level}-${i}` })), levelGroups.map((group, groupIndex) => {
4302
+ ), level > 0 && Array.from({ length: levelGroups[0]?.startIndex || 0 }).map((_2, i) => /* @__PURE__ */ import_react28.default.createElement("th", { key: `empty-${level}-${i}` })), levelGroups.filter((g) => g.colspan > 0).map((group, groupIndex) => {
4251
4303
  const nextGroup = levelGroups[groupIndex + 1];
4252
4304
  const emptyCells = nextGroup ? nextGroup.startIndex - (group.startIndex + group.colspan) : columns.length - (group.startIndex + group.colspan);
4253
4305
  const params = { groupId: group.groupId };
@@ -4265,7 +4317,7 @@ function Component(props, apiRef) {
4265
4317
  },
4266
4318
  group.headerName ?? group.groupId
4267
4319
  ), emptyCells > 0 && Array.from({ length: emptyCells }).map((_2, i) => /* @__PURE__ */ import_react28.default.createElement("th", { key: `empty-between-${level}-${groupIndex}-${i}`, colSpan: 1 })));
4268
- }))), /* @__PURE__ */ import_react28.default.createElement("tr", null, !processedColumnGroups && checkboxSelection && /* @__PURE__ */ import_react28.default.createElement(
4320
+ }))), /* @__PURE__ */ import_react28.default.createElement("tr", null, (!processedColumnGroups || processedColumnGroups.groups.length === 0) && checkboxSelection && /* @__PURE__ */ import_react28.default.createElement(
4269
4321
  "th",
4270
4322
  {
4271
4323
  style: {
@@ -4329,6 +4381,18 @@ function Component(props, apiRef) {
4329
4381
  /* @__PURE__ */ import_react28.default.createElement(LoadingOverlay, null)
4330
4382
  )
4331
4383
  )),
4384
+ showNoRowsOverlay && /* @__PURE__ */ import_react28.default.createElement("tr", null, /* @__PURE__ */ import_react28.default.createElement("td", { colSpan: totalColCount, style: { border: "none" } }, /* @__PURE__ */ import_react28.default.createElement(
4385
+ Box_default,
4386
+ {
4387
+ sx: {
4388
+ display: "flex",
4389
+ alignItems: "center",
4390
+ justifyContent: "center",
4391
+ minHeight: "150px"
4392
+ }
4393
+ },
4394
+ /* @__PURE__ */ import_react28.default.createElement(NoRowsOverlay, { ...noRowsOverlayProps })
4395
+ ))),
4332
4396
  virtualizedItems.map((virtualizedRow, index) => {
4333
4397
  const rowIndex = virtualizedRow.index;
4334
4398
  const row = dataInPage[rowIndex];
package/dist/index.js CHANGED
@@ -2010,14 +2010,15 @@ function reorderColumnsByGroupingModel(columns, columnGroupingModel) {
2010
2010
  }
2011
2011
  return reorderedColumns;
2012
2012
  }
2013
- function flattenColumnGroups(items, groupPath = [], columnIndex = { current: 0 }) {
2013
+ function flattenColumnGroups(items, groupPath = [], columnIndex = { current: 0 }, visibleFields) {
2014
2014
  const result = [];
2015
2015
  for (const item of items) {
2016
2016
  if ("groupId" in item) {
2017
2017
  const newPath = [...groupPath, item.groupId];
2018
2018
  const children = Array.isArray(item.children) ? item.children : [item.children];
2019
- result.push(...flattenColumnGroups(children, newPath, columnIndex));
2019
+ result.push(...flattenColumnGroups(children, newPath, columnIndex, visibleFields));
2020
2020
  } else {
2021
+ if (visibleFields && !visibleFields.has(item.field)) continue;
2021
2022
  result.push({
2022
2023
  ...item,
2023
2024
  groupPath,
@@ -2027,9 +2028,9 @@ function flattenColumnGroups(items, groupPath = [], columnIndex = { current: 0 }
2027
2028
  }
2028
2029
  return result;
2029
2030
  }
2030
- function calculateColumnGroups(columnGroupingModel, columns) {
2031
+ function calculateColumnGroups(columnGroupingModel, columns, visibleFields) {
2031
2032
  const fieldsInGroupingModel = extractFieldsFromGroupingModel(columnGroupingModel);
2032
- const flattenedColumns = flattenColumnGroups(columnGroupingModel);
2033
+ const flattenedColumns = flattenColumnGroups(columnGroupingModel, [], { current: 0 }, visibleFields);
2033
2034
  const columnIndexMap = new Map(flattenedColumns.map((col) => [col.field, col.columnIndex]));
2034
2035
  const processedGroups = /* @__PURE__ */ new Map();
2035
2036
  const groupsByLevel = [];
@@ -2077,7 +2078,9 @@ function calculateColumnGroups(columnGroupingModel, columns) {
2077
2078
  groupsByLevel.forEach((level) => {
2078
2079
  level.sort((a, b) => a.startIndex - b.startIndex);
2079
2080
  });
2080
- return { groups: groupsByLevel, maxLevel, fieldsInGroupingModel };
2081
+ const filteredGroupsByLevel = groupsByLevel.map((level) => level.filter((g) => g.colspan > 0)).filter((level) => level.length > 0);
2082
+ const correctedMaxLevel = filteredGroupsByLevel.length > 0 ? filteredGroupsByLevel.length - 1 : -1;
2083
+ return { groups: filteredGroupsByLevel, maxLevel: correctedMaxLevel, fieldsInGroupingModel };
2081
2084
  }
2082
2085
  function getTextAlign(props) {
2083
2086
  return !props.editMode && ["number", "date", "currency"].includes(props.type || "") ? "end" : "start";
@@ -2086,7 +2089,7 @@ var numberFormatter = (value) => "Intl" in window ? new Intl.NumberFormat().form
2086
2089
 
2087
2090
  // src/components/DataTable/styled.tsx
2088
2091
  import React17 from "react";
2089
- import { styled as styled8, LinearProgress, buttonClasses, iconButtonClasses } from "@mui/joy";
2092
+ import { styled as styled8, LinearProgress, buttonClasses, iconButtonClasses, Typography as Typography3 } from "@mui/joy";
2090
2093
  import { motion as motion17 } from "framer-motion";
2091
2094
  import SortIcon from "@mui/icons-material/ArrowUpwardRounded";
2092
2095
  var EllipsisDiv = styled8("div", {
@@ -2192,6 +2195,7 @@ var StyledTd = styled8("td")(({ theme }) => ({
2192
2195
  }));
2193
2196
  var MotionSortIcon = motion17(SortIcon);
2194
2197
  var DefaultLoadingOverlay = () => /* @__PURE__ */ React17.createElement(LinearProgress, { value: 8, variant: "plain" });
2198
+ var DefaultNoRowsOverlay = () => /* @__PURE__ */ React17.createElement(Typography3, { level: "body-sm", textColor: "text.tertiary" }, "No rows");
2195
2199
  var Resizer = (ref, targetRef = ref) => /* @__PURE__ */ React17.createElement(
2196
2200
  Box_default,
2197
2201
  {
@@ -2663,7 +2667,7 @@ var Textarea_default = Textarea;
2663
2667
 
2664
2668
  // src/components/Select/Select.tsx
2665
2669
  import React20, { useMemo as useMemo7 } from "react";
2666
- import { Select as JoySelect, Option as JoyOption, ListItemContent as ListItemContent2, Typography as Typography3 } from "@mui/joy";
2670
+ import { Select as JoySelect, Option as JoyOption, ListItemContent as ListItemContent2, Typography as Typography4 } from "@mui/joy";
2667
2671
  import { motion as motion20 } from "framer-motion";
2668
2672
  var MotionOption = motion20(JoyOption);
2669
2673
  var Option = MotionOption;
@@ -2737,7 +2741,7 @@ function Select(props) {
2737
2741
  return optionMap.get(selected.value)?.label;
2738
2742
  }
2739
2743
  },
2740
- options.map((option) => /* @__PURE__ */ React20.createElement(Option, { key: option.value, value: option.value, disabled: option.disabled }, option.secondaryText ? /* @__PURE__ */ React20.createElement(ListItemContent2, { sx: { gap: 0.5 } }, /* @__PURE__ */ React20.createElement(Typography3, { level: "inherit" }, option.label), /* @__PURE__ */ React20.createElement(Typography3, { level: secondaryTextLevelMap2[size ?? "md"], textColor: "text.tertiary" }, option.secondaryText)) : option.label))
2744
+ options.map((option) => /* @__PURE__ */ React20.createElement(Option, { key: option.value, value: option.value, disabled: option.disabled }, option.secondaryText ? /* @__PURE__ */ React20.createElement(ListItemContent2, { sx: { gap: 0.5 } }, /* @__PURE__ */ React20.createElement(Typography4, { level: "inherit" }, option.label), /* @__PURE__ */ React20.createElement(Typography4, { level: secondaryTextLevelMap2[size ?? "md"], textColor: "text.tertiary" }, option.secondaryText)) : option.label))
2741
2745
  );
2742
2746
  return /* @__PURE__ */ React20.createElement(
2743
2747
  FormControl_default,
@@ -3250,7 +3254,9 @@ function useDataTableRenderer({
3250
3254
  getId: _getId,
3251
3255
  isTotalSelected: _isTotalSelected,
3252
3256
  isRowSelectable,
3253
- columnGroupingModel
3257
+ columnGroupingModel,
3258
+ columnVisibilityModel,
3259
+ onColumnVisibilityModelChange
3254
3260
  }) {
3255
3261
  if (pinnedColumns && columnGroupingModel) {
3256
3262
  throw new Error(
@@ -3266,12 +3272,35 @@ function useDataTableRenderer({
3266
3272
  initialState?.sorting?.sortModel ?? [],
3267
3273
  useCallback10((sortModel2) => onSortModelChange?.(sortModel2), [onSortModelChange])
3268
3274
  );
3275
+ const [visibilityModel] = useControlledState(
3276
+ columnVisibilityModel,
3277
+ initialState?.columns?.columnVisibilityModel ?? {},
3278
+ useCallback10(
3279
+ (model) => onColumnVisibilityModelChange?.(model),
3280
+ [onColumnVisibilityModelChange]
3281
+ )
3282
+ );
3269
3283
  const reorderedColumns = useMemo9(() => {
3270
3284
  if (!columnGroupingModel) return columnsProp;
3271
3285
  return reorderColumnsByGroupingModel(columnsProp, columnGroupingModel);
3272
3286
  }, [columnsProp, columnGroupingModel]);
3273
- const columnsByField = useMemo9(
3287
+ const visibleColumns = useMemo9(
3288
+ () => reorderedColumns.filter((col) => visibilityModel[col.field] !== false),
3289
+ [reorderedColumns, visibilityModel]
3290
+ );
3291
+ const visibleFieldSet = useMemo9(() => new Set(visibleColumns.map((c) => c.field)), [visibleColumns]);
3292
+ const allColumnsByField = useMemo9(
3274
3293
  () => reorderedColumns.reduce(
3294
+ (acc, curr) => ({
3295
+ ...acc,
3296
+ [curr.field]: curr
3297
+ }),
3298
+ {}
3299
+ ),
3300
+ [reorderedColumns]
3301
+ );
3302
+ const visibleColumnsByField = useMemo9(
3303
+ () => visibleColumns.reduce(
3275
3304
  (acc, curr) => ({
3276
3305
  ...acc,
3277
3306
  [curr.field]: {
@@ -3282,7 +3311,7 @@ function useDataTableRenderer({
3282
3311
  }),
3283
3312
  {}
3284
3313
  ),
3285
- [reorderedColumns]
3314
+ [visibleColumns]
3286
3315
  );
3287
3316
  const sortComparator = useCallback10(
3288
3317
  (rowA, rowB) => {
@@ -3290,7 +3319,8 @@ function useDataTableRenderer({
3290
3319
  const { field, sort: direction } = sort;
3291
3320
  const a = rowA[field];
3292
3321
  const b = rowB[field];
3293
- const column = columnsByField[field];
3322
+ const column = allColumnsByField[field];
3323
+ if (!column) continue;
3294
3324
  let comparison = 0;
3295
3325
  if (column.sortComparator) {
3296
3326
  comparison = column.sortComparator({
@@ -3310,7 +3340,7 @@ function useDataTableRenderer({
3310
3340
  }
3311
3341
  return 0;
3312
3342
  },
3313
- [sortModel, columnsByField]
3343
+ [sortModel, allColumnsByField]
3314
3344
  );
3315
3345
  const rows = useMemo9(
3316
3346
  () => sortModel.length ? [..._rows].sort(sortComparator) : _rows,
@@ -3374,44 +3404,54 @@ function useDataTableRenderer({
3374
3404
  () => _isTotalSelected ?? (selectableRowCount > 0 && (selectionModel?.length || 0) === selectableRowCount),
3375
3405
  [_isTotalSelected, selectionModel, selectableRowCount]
3376
3406
  );
3377
- const columnWidths = useColumnWidths(columnsByField);
3407
+ const columnWidths = useColumnWidths(visibleColumnsByField);
3378
3408
  const getWidth = useCallback10(
3379
- (f) => columnWidths[f] ?? columnsByField[f].width ?? // Column prop 으로 지정된 width
3380
- columnsByField[f].minWidth ?? 0,
3381
- [columnWidths, columnsByField]
3409
+ (f) => columnWidths[f] ?? allColumnsByField[f]?.width ?? // Column prop 으로 지정된 width
3410
+ allColumnsByField[f]?.minWidth ?? 0,
3411
+ [columnWidths, allColumnsByField]
3382
3412
  );
3383
3413
  const processedColumnGroups = useMemo9(() => {
3384
3414
  if (!columnGroupingModel) return null;
3385
- return calculateColumnGroups(columnGroupingModel, reorderedColumns);
3386
- }, [columnGroupingModel, reorderedColumns]);
3415
+ return calculateColumnGroups(columnGroupingModel, visibleColumns, visibleFieldSet);
3416
+ }, [columnGroupingModel, visibleColumns, visibleFieldSet]);
3417
+ const effectivePinnedLeft = useMemo9(
3418
+ () => pinnedColumns?.left?.filter((f) => visibleFieldSet.has(f)),
3419
+ [pinnedColumns?.left, visibleFieldSet]
3420
+ );
3421
+ const effectivePinnedRight = useMemo9(
3422
+ () => pinnedColumns?.right?.filter((f) => visibleFieldSet.has(f)),
3423
+ [pinnedColumns?.right, visibleFieldSet]
3424
+ );
3387
3425
  const columns = useMemo9(() => {
3388
- const baseColumns = reorderedColumns.length > 0 ? reorderedColumns : Object.keys(rows[0] || {}).map((key) => ({
3426
+ const baseColumns = visibleColumns.length > 0 ? visibleColumns : reorderedColumns.length > 0 ? [] : Object.keys(rows[0] || {}).map((key) => ({
3389
3427
  field: key
3390
3428
  }));
3391
3429
  return baseColumns.map((column) => {
3392
- const isLeftPinned = pinnedColumns?.left?.includes(column.field);
3393
- const isRightPinned = pinnedColumns?.right?.includes(column.field);
3430
+ const isLeftPinned = effectivePinnedLeft?.includes(column.field);
3431
+ const isRightPinned = effectivePinnedRight?.includes(column.field);
3394
3432
  const isPinned = isLeftPinned || isRightPinned;
3395
3433
  return {
3396
3434
  ...column,
3397
- headerRef: columnsByField[column.field].headerRef,
3398
- tableColRef: columnsByField[column.field].tableColRef,
3435
+ headerRef: visibleColumnsByField[column.field]?.headerRef,
3436
+ tableColRef: visibleColumnsByField[column.field]?.tableColRef,
3399
3437
  isCellEditable: editMode && (typeof column.isCellEditable === "function" ? column.isCellEditable : column.isCellEditable ?? true),
3400
3438
  sort: sortModel.find((sort) => sort.field === column.field)?.sort,
3401
- sortOrder: columnsByField[column.field]?.sortOrder || sortOrder,
3439
+ sortOrder: allColumnsByField[column.field]?.sortOrder || sortOrder,
3402
3440
  isPinned,
3403
- isLastStartPinnedColumn: isLeftPinned && [...pinnedColumns?.left || []].pop() === column.field,
3404
- isLastEndPinnedColumn: isRightPinned && (pinnedColumns?.right?.[0] ?? null) === column.field,
3405
- pinnedStartPosition: pinnedColumns?.left?.slice(0, isLeftPinned ? pinnedColumns.left.indexOf(column.field) : pinnedColumns.left.length).reduce((acc, curr) => acc + getWidth(curr), 0),
3406
- pinnedEndPosition: pinnedColumns?.right?.slice(isRightPinned ? pinnedColumns.right.indexOf(column.field) + 1 : 0).reduce((acc, curr) => acc + getWidth(curr), 0)
3441
+ isLastStartPinnedColumn: isLeftPinned && [...effectivePinnedLeft || []].pop() === column.field,
3442
+ isLastEndPinnedColumn: isRightPinned && (effectivePinnedRight?.[0] ?? null) === column.field,
3443
+ pinnedStartPosition: effectivePinnedLeft?.slice(0, isLeftPinned ? effectivePinnedLeft.indexOf(column.field) : effectivePinnedLeft.length).reduce((acc, curr) => acc + getWidth(curr), 0),
3444
+ pinnedEndPosition: effectivePinnedRight?.slice(isRightPinned ? effectivePinnedRight.indexOf(column.field) + 1 : 0).reduce((acc, curr) => acc + getWidth(curr), 0)
3407
3445
  };
3408
3446
  });
3409
3447
  }, [
3448
+ visibleColumns,
3410
3449
  reorderedColumns,
3411
3450
  rows,
3412
- pinnedColumns?.left,
3413
- pinnedColumns?.right,
3414
- columnsByField,
3451
+ effectivePinnedLeft,
3452
+ effectivePinnedRight,
3453
+ visibleColumnsByField,
3454
+ allColumnsByField,
3415
3455
  editMode,
3416
3456
  sortModel,
3417
3457
  sortOrder,
@@ -3427,8 +3467,8 @@ function useDataTableRenderer({
3427
3467
  const handleSortChange = useCallback10(
3428
3468
  (props) => {
3429
3469
  const { field, currentSort, multiple } = props;
3430
- const column = columnsByField[field];
3431
- const columnSortOrder = column.sortOrder || sortOrder;
3470
+ const column = allColumnsByField[field];
3471
+ const columnSortOrder = column?.sortOrder || sortOrder;
3432
3472
  if (currentSort !== void 0) {
3433
3473
  const currentOrderIndex = columnSortOrder.indexOf(currentSort);
3434
3474
  const nextSortOrderIndex = (currentOrderIndex + 1) % columnSortOrder.length;
@@ -3445,7 +3485,7 @@ function useDataTableRenderer({
3445
3485
  setSortModel(newSortModel);
3446
3486
  }
3447
3487
  },
3448
- [sortOrder, columnsByField, sortModel, setSortModel]
3488
+ [sortOrder, allColumnsByField, sortModel, setSortModel]
3449
3489
  );
3450
3490
  useEffect6(() => {
3451
3491
  if (!paginationModel) {
@@ -3871,13 +3911,23 @@ function Component(props, apiRef) {
3871
3911
  loading,
3872
3912
  columnGroupingModel: _________________,
3873
3913
  // columnGroupingModel is used in useDataTableRenderer
3914
+ columnVisibilityModel: __________________,
3915
+ // columnVisibilityModel is used in useDataTableRenderer
3916
+ onColumnVisibilityModelChange: ___________________,
3917
+ // onColumnVisibilityModelChange is used in useDataTableRenderer
3874
3918
  slots: {
3875
3919
  checkbox: RenderCheckbox = Checkbox_default,
3876
3920
  toolbar: Toolbar,
3877
3921
  footer: Footer,
3878
- loadingOverlay: LoadingOverlay = DefaultLoadingOverlay
3922
+ loadingOverlay: LoadingOverlay = DefaultLoadingOverlay,
3923
+ noRowsOverlay: NoRowsOverlay = DefaultNoRowsOverlay
3924
+ } = {},
3925
+ slotProps: {
3926
+ checkbox: checkboxProps = {},
3927
+ toolbar: toolbarProps,
3928
+ background: backgroundProps = {},
3929
+ noRowsOverlay: noRowsOverlayProps = {}
3879
3930
  } = {},
3880
- slotProps: { checkbox: checkboxProps = {}, toolbar: toolbarProps, background: backgroundProps = {} } = {},
3881
3931
  stripe,
3882
3932
  isTotalSelected: ___________,
3883
3933
  ...innerProps
@@ -3921,6 +3971,8 @@ function Component(props, apiRef) {
3921
3971
  const paginationModel = useMemo10(() => ({ page, pageSize }), [page, pageSize]);
3922
3972
  const totalSize = virtualizer.getTotalSize();
3923
3973
  const virtualizedItems = virtualizer.getVirtualItems();
3974
+ const showNoRowsOverlay = !loading && rowCount === 0;
3975
+ const totalColCount = Math.max(1, columns.length + (checkboxSelection ? 1 : 0));
3924
3976
  const getRowClickHandler = useCallback12(
3925
3977
  (row, rowId) => (e) => {
3926
3978
  onRowClick?.({ row, rowId }, e);
@@ -4110,7 +4162,7 @@ function Component(props, apiRef) {
4110
4162
  width: c.width
4111
4163
  }
4112
4164
  }
4113
- ))), /* @__PURE__ */ React25.createElement("thead", null, processedColumnGroups && processedColumnGroups.groups.map((levelGroups, level) => /* @__PURE__ */ React25.createElement("tr", { key: `group-level-${level}` }, checkboxSelection && level === 0 && /* @__PURE__ */ React25.createElement(
4165
+ ))), /* @__PURE__ */ React25.createElement("thead", null, processedColumnGroups && processedColumnGroups.groups.length > 0 && processedColumnGroups.groups.map((levelGroups, level) => /* @__PURE__ */ React25.createElement("tr", { key: `group-level-${level}` }, checkboxSelection && level === 0 && /* @__PURE__ */ React25.createElement(
4114
4166
  "th",
4115
4167
  {
4116
4168
  rowSpan: processedColumnGroups.maxLevel + 2,
@@ -4130,7 +4182,7 @@ function Component(props, apiRef) {
4130
4182
  ...checkboxProps
4131
4183
  }
4132
4184
  )
4133
- ), level > 0 && Array.from({ length: levelGroups[0]?.startIndex || 0 }).map((_2, i) => /* @__PURE__ */ React25.createElement("th", { key: `empty-${level}-${i}` })), levelGroups.map((group, groupIndex) => {
4185
+ ), level > 0 && Array.from({ length: levelGroups[0]?.startIndex || 0 }).map((_2, i) => /* @__PURE__ */ React25.createElement("th", { key: `empty-${level}-${i}` })), levelGroups.filter((g) => g.colspan > 0).map((group, groupIndex) => {
4134
4186
  const nextGroup = levelGroups[groupIndex + 1];
4135
4187
  const emptyCells = nextGroup ? nextGroup.startIndex - (group.startIndex + group.colspan) : columns.length - (group.startIndex + group.colspan);
4136
4188
  const params = { groupId: group.groupId };
@@ -4148,7 +4200,7 @@ function Component(props, apiRef) {
4148
4200
  },
4149
4201
  group.headerName ?? group.groupId
4150
4202
  ), emptyCells > 0 && Array.from({ length: emptyCells }).map((_2, i) => /* @__PURE__ */ React25.createElement("th", { key: `empty-between-${level}-${groupIndex}-${i}`, colSpan: 1 })));
4151
- }))), /* @__PURE__ */ React25.createElement("tr", null, !processedColumnGroups && checkboxSelection && /* @__PURE__ */ React25.createElement(
4203
+ }))), /* @__PURE__ */ React25.createElement("tr", null, (!processedColumnGroups || processedColumnGroups.groups.length === 0) && checkboxSelection && /* @__PURE__ */ React25.createElement(
4152
4204
  "th",
4153
4205
  {
4154
4206
  style: {
@@ -4212,6 +4264,18 @@ function Component(props, apiRef) {
4212
4264
  /* @__PURE__ */ React25.createElement(LoadingOverlay, null)
4213
4265
  )
4214
4266
  )),
4267
+ showNoRowsOverlay && /* @__PURE__ */ React25.createElement("tr", null, /* @__PURE__ */ React25.createElement("td", { colSpan: totalColCount, style: { border: "none" } }, /* @__PURE__ */ React25.createElement(
4268
+ Box_default,
4269
+ {
4270
+ sx: {
4271
+ display: "flex",
4272
+ alignItems: "center",
4273
+ justifyContent: "center",
4274
+ minHeight: "150px"
4275
+ }
4276
+ },
4277
+ /* @__PURE__ */ React25.createElement(NoRowsOverlay, { ...noRowsOverlayProps })
4278
+ ))),
4215
4279
  virtualizedItems.map((virtualizedRow, index) => {
4216
4280
  const rowIndex = virtualizedRow.index;
4217
4281
  const row = dataInPage[rowIndex];