@ceed/ads 1.26.0 → 1.28.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
@@ -2134,14 +2134,15 @@ function reorderColumnsByGroupingModel(columns, columnGroupingModel) {
2134
2134
  }
2135
2135
  return reorderedColumns;
2136
2136
  }
2137
- function flattenColumnGroups(items, groupPath = [], columnIndex = { current: 0 }) {
2137
+ function flattenColumnGroups(items, groupPath = [], columnIndex = { current: 0 }, visibleFields) {
2138
2138
  const result = [];
2139
2139
  for (const item of items) {
2140
2140
  if ("groupId" in item) {
2141
2141
  const newPath = [...groupPath, item.groupId];
2142
2142
  const children = Array.isArray(item.children) ? item.children : [item.children];
2143
- result.push(...flattenColumnGroups(children, newPath, columnIndex));
2143
+ result.push(...flattenColumnGroups(children, newPath, columnIndex, visibleFields));
2144
2144
  } else {
2145
+ if (visibleFields && !visibleFields.has(item.field)) continue;
2145
2146
  result.push({
2146
2147
  ...item,
2147
2148
  groupPath,
@@ -2151,9 +2152,9 @@ function flattenColumnGroups(items, groupPath = [], columnIndex = { current: 0 }
2151
2152
  }
2152
2153
  return result;
2153
2154
  }
2154
- function calculateColumnGroups(columnGroupingModel, columns) {
2155
+ function calculateColumnGroups(columnGroupingModel, columns, visibleFields) {
2155
2156
  const fieldsInGroupingModel = extractFieldsFromGroupingModel(columnGroupingModel);
2156
- const flattenedColumns = flattenColumnGroups(columnGroupingModel);
2157
+ const flattenedColumns = flattenColumnGroups(columnGroupingModel, [], { current: 0 }, visibleFields);
2157
2158
  const columnIndexMap = new Map(flattenedColumns.map((col) => [col.field, col.columnIndex]));
2158
2159
  const processedGroups = /* @__PURE__ */ new Map();
2159
2160
  const groupsByLevel = [];
@@ -2201,7 +2202,9 @@ function calculateColumnGroups(columnGroupingModel, columns) {
2201
2202
  groupsByLevel.forEach((level) => {
2202
2203
  level.sort((a, b) => a.startIndex - b.startIndex);
2203
2204
  });
2204
- return { groups: groupsByLevel, maxLevel, fieldsInGroupingModel };
2205
+ const filteredGroupsByLevel = groupsByLevel.map((level) => level.filter((g) => g.colspan > 0)).filter((level) => level.length > 0);
2206
+ const correctedMaxLevel = filteredGroupsByLevel.length > 0 ? filteredGroupsByLevel.length - 1 : -1;
2207
+ return { groups: filteredGroupsByLevel, maxLevel: correctedMaxLevel, fieldsInGroupingModel };
2205
2208
  }
2206
2209
  function getTextAlign(props) {
2207
2210
  return !props.editMode && ["number", "date", "currency"].includes(props.type || "") ? "end" : "start";
@@ -2316,6 +2319,7 @@ var StyledTd = (0, import_joy25.styled)("td")(({ theme }) => ({
2316
2319
  }));
2317
2320
  var MotionSortIcon = (0, import_framer_motion17.motion)(import_ArrowUpwardRounded.default);
2318
2321
  var DefaultLoadingOverlay = () => /* @__PURE__ */ import_react19.default.createElement(import_joy25.LinearProgress, { value: 8, variant: "plain" });
2322
+ var DefaultNoRowsOverlay = () => /* @__PURE__ */ import_react19.default.createElement(import_joy25.Typography, { level: "body-sm", textColor: "text.tertiary" }, "No rows");
2319
2323
  var Resizer = (ref, targetRef = ref) => /* @__PURE__ */ import_react19.default.createElement(
2320
2324
  Box_default,
2321
2325
  {
@@ -3365,7 +3369,9 @@ function useDataTableRenderer({
3365
3369
  getId: _getId,
3366
3370
  isTotalSelected: _isTotalSelected,
3367
3371
  isRowSelectable,
3368
- columnGroupingModel
3372
+ columnGroupingModel,
3373
+ columnVisibilityModel,
3374
+ onColumnVisibilityModelChange
3369
3375
  }) {
3370
3376
  if (pinnedColumns && columnGroupingModel) {
3371
3377
  throw new Error(
@@ -3381,12 +3387,35 @@ function useDataTableRenderer({
3381
3387
  initialState?.sorting?.sortModel ?? [],
3382
3388
  (0, import_react25.useCallback)((sortModel2) => onSortModelChange?.(sortModel2), [onSortModelChange])
3383
3389
  );
3390
+ const [visibilityModel] = useControlledState(
3391
+ columnVisibilityModel,
3392
+ initialState?.columns?.columnVisibilityModel ?? {},
3393
+ (0, import_react25.useCallback)(
3394
+ (model) => onColumnVisibilityModelChange?.(model),
3395
+ [onColumnVisibilityModelChange]
3396
+ )
3397
+ );
3384
3398
  const reorderedColumns = (0, import_react25.useMemo)(() => {
3385
3399
  if (!columnGroupingModel) return columnsProp;
3386
3400
  return reorderColumnsByGroupingModel(columnsProp, columnGroupingModel);
3387
3401
  }, [columnsProp, columnGroupingModel]);
3388
- const columnsByField = (0, import_react25.useMemo)(
3402
+ const visibleColumns = (0, import_react25.useMemo)(
3403
+ () => reorderedColumns.filter((col) => visibilityModel[col.field] !== false),
3404
+ [reorderedColumns, visibilityModel]
3405
+ );
3406
+ const visibleFieldSet = (0, import_react25.useMemo)(() => new Set(visibleColumns.map((c) => c.field)), [visibleColumns]);
3407
+ const allColumnsByField = (0, import_react25.useMemo)(
3389
3408
  () => reorderedColumns.reduce(
3409
+ (acc, curr) => ({
3410
+ ...acc,
3411
+ [curr.field]: curr
3412
+ }),
3413
+ {}
3414
+ ),
3415
+ [reorderedColumns]
3416
+ );
3417
+ const visibleColumnsByField = (0, import_react25.useMemo)(
3418
+ () => visibleColumns.reduce(
3390
3419
  (acc, curr) => ({
3391
3420
  ...acc,
3392
3421
  [curr.field]: {
@@ -3397,7 +3426,7 @@ function useDataTableRenderer({
3397
3426
  }),
3398
3427
  {}
3399
3428
  ),
3400
- [reorderedColumns]
3429
+ [visibleColumns]
3401
3430
  );
3402
3431
  const sortComparator = (0, import_react25.useCallback)(
3403
3432
  (rowA, rowB) => {
@@ -3405,7 +3434,8 @@ function useDataTableRenderer({
3405
3434
  const { field, sort: direction } = sort;
3406
3435
  const a = rowA[field];
3407
3436
  const b = rowB[field];
3408
- const column = columnsByField[field];
3437
+ const column = allColumnsByField[field];
3438
+ if (!column) continue;
3409
3439
  let comparison = 0;
3410
3440
  if (column.sortComparator) {
3411
3441
  comparison = column.sortComparator({
@@ -3425,7 +3455,7 @@ function useDataTableRenderer({
3425
3455
  }
3426
3456
  return 0;
3427
3457
  },
3428
- [sortModel, columnsByField]
3458
+ [sortModel, allColumnsByField]
3429
3459
  );
3430
3460
  const rows = (0, import_react25.useMemo)(
3431
3461
  () => sortModel.length ? [..._rows].sort(sortComparator) : _rows,
@@ -3489,44 +3519,54 @@ function useDataTableRenderer({
3489
3519
  () => _isTotalSelected ?? (selectableRowCount > 0 && (selectionModel?.length || 0) === selectableRowCount),
3490
3520
  [_isTotalSelected, selectionModel, selectableRowCount]
3491
3521
  );
3492
- const columnWidths = useColumnWidths(columnsByField);
3522
+ const columnWidths = useColumnWidths(visibleColumnsByField);
3493
3523
  const getWidth = (0, import_react25.useCallback)(
3494
- (f) => columnWidths[f] ?? columnsByField[f].width ?? // Column prop 으로 지정된 width
3495
- columnsByField[f].minWidth ?? 0,
3496
- [columnWidths, columnsByField]
3524
+ (f) => columnWidths[f] ?? allColumnsByField[f]?.width ?? // Column prop 으로 지정된 width
3525
+ allColumnsByField[f]?.minWidth ?? 0,
3526
+ [columnWidths, allColumnsByField]
3497
3527
  );
3498
3528
  const processedColumnGroups = (0, import_react25.useMemo)(() => {
3499
3529
  if (!columnGroupingModel) return null;
3500
- return calculateColumnGroups(columnGroupingModel, reorderedColumns);
3501
- }, [columnGroupingModel, reorderedColumns]);
3530
+ return calculateColumnGroups(columnGroupingModel, visibleColumns, visibleFieldSet);
3531
+ }, [columnGroupingModel, visibleColumns, visibleFieldSet]);
3532
+ const effectivePinnedLeft = (0, import_react25.useMemo)(
3533
+ () => pinnedColumns?.left?.filter((f) => visibleFieldSet.has(f)),
3534
+ [pinnedColumns?.left, visibleFieldSet]
3535
+ );
3536
+ const effectivePinnedRight = (0, import_react25.useMemo)(
3537
+ () => pinnedColumns?.right?.filter((f) => visibleFieldSet.has(f)),
3538
+ [pinnedColumns?.right, visibleFieldSet]
3539
+ );
3502
3540
  const columns = (0, import_react25.useMemo)(() => {
3503
- const baseColumns = reorderedColumns.length > 0 ? reorderedColumns : Object.keys(rows[0] || {}).map((key) => ({
3541
+ const baseColumns = visibleColumns.length > 0 ? visibleColumns : reorderedColumns.length > 0 ? [] : Object.keys(rows[0] || {}).map((key) => ({
3504
3542
  field: key
3505
3543
  }));
3506
3544
  return baseColumns.map((column) => {
3507
- const isLeftPinned = pinnedColumns?.left?.includes(column.field);
3508
- const isRightPinned = pinnedColumns?.right?.includes(column.field);
3545
+ const isLeftPinned = effectivePinnedLeft?.includes(column.field);
3546
+ const isRightPinned = effectivePinnedRight?.includes(column.field);
3509
3547
  const isPinned = isLeftPinned || isRightPinned;
3510
3548
  return {
3511
3549
  ...column,
3512
- headerRef: columnsByField[column.field].headerRef,
3513
- tableColRef: columnsByField[column.field].tableColRef,
3550
+ headerRef: visibleColumnsByField[column.field]?.headerRef,
3551
+ tableColRef: visibleColumnsByField[column.field]?.tableColRef,
3514
3552
  isCellEditable: editMode && (typeof column.isCellEditable === "function" ? column.isCellEditable : column.isCellEditable ?? true),
3515
3553
  sort: sortModel.find((sort) => sort.field === column.field)?.sort,
3516
- sortOrder: columnsByField[column.field]?.sortOrder || sortOrder,
3554
+ sortOrder: allColumnsByField[column.field]?.sortOrder || sortOrder,
3517
3555
  isPinned,
3518
- isLastStartPinnedColumn: isLeftPinned && [...pinnedColumns?.left || []].pop() === column.field,
3519
- isLastEndPinnedColumn: isRightPinned && (pinnedColumns?.right?.[0] ?? null) === column.field,
3520
- pinnedStartPosition: pinnedColumns?.left?.slice(0, isLeftPinned ? pinnedColumns.left.indexOf(column.field) : pinnedColumns.left.length).reduce((acc, curr) => acc + getWidth(curr), 0),
3521
- pinnedEndPosition: pinnedColumns?.right?.slice(isRightPinned ? pinnedColumns.right.indexOf(column.field) + 1 : 0).reduce((acc, curr) => acc + getWidth(curr), 0)
3556
+ isLastStartPinnedColumn: isLeftPinned && [...effectivePinnedLeft || []].pop() === column.field,
3557
+ isLastEndPinnedColumn: isRightPinned && (effectivePinnedRight?.[0] ?? null) === column.field,
3558
+ pinnedStartPosition: effectivePinnedLeft?.slice(0, isLeftPinned ? effectivePinnedLeft.indexOf(column.field) : effectivePinnedLeft.length).reduce((acc, curr) => acc + getWidth(curr), 0),
3559
+ pinnedEndPosition: effectivePinnedRight?.slice(isRightPinned ? effectivePinnedRight.indexOf(column.field) + 1 : 0).reduce((acc, curr) => acc + getWidth(curr), 0)
3522
3560
  };
3523
3561
  });
3524
3562
  }, [
3563
+ visibleColumns,
3525
3564
  reorderedColumns,
3526
3565
  rows,
3527
- pinnedColumns?.left,
3528
- pinnedColumns?.right,
3529
- columnsByField,
3566
+ effectivePinnedLeft,
3567
+ effectivePinnedRight,
3568
+ visibleColumnsByField,
3569
+ allColumnsByField,
3530
3570
  editMode,
3531
3571
  sortModel,
3532
3572
  sortOrder,
@@ -3542,8 +3582,8 @@ function useDataTableRenderer({
3542
3582
  const handleSortChange = (0, import_react25.useCallback)(
3543
3583
  (props) => {
3544
3584
  const { field, currentSort, multiple } = props;
3545
- const column = columnsByField[field];
3546
- const columnSortOrder = column.sortOrder || sortOrder;
3585
+ const column = allColumnsByField[field];
3586
+ const columnSortOrder = column?.sortOrder || sortOrder;
3547
3587
  if (currentSort !== void 0) {
3548
3588
  const currentOrderIndex = columnSortOrder.indexOf(currentSort);
3549
3589
  const nextSortOrderIndex = (currentOrderIndex + 1) % columnSortOrder.length;
@@ -3560,7 +3600,7 @@ function useDataTableRenderer({
3560
3600
  setSortModel(newSortModel);
3561
3601
  }
3562
3602
  },
3563
- [sortOrder, columnsByField, sortModel, setSortModel]
3603
+ [sortOrder, allColumnsByField, sortModel, setSortModel]
3564
3604
  );
3565
3605
  (0, import_react25.useEffect)(() => {
3566
3606
  if (!paginationModel) {
@@ -3986,13 +4026,23 @@ function Component(props, apiRef) {
3986
4026
  loading,
3987
4027
  columnGroupingModel: _________________,
3988
4028
  // columnGroupingModel is used in useDataTableRenderer
4029
+ columnVisibilityModel: __________________,
4030
+ // columnVisibilityModel is used in useDataTableRenderer
4031
+ onColumnVisibilityModelChange: ___________________,
4032
+ // onColumnVisibilityModelChange is used in useDataTableRenderer
3989
4033
  slots: {
3990
4034
  checkbox: RenderCheckbox = Checkbox_default,
3991
4035
  toolbar: Toolbar,
3992
4036
  footer: Footer,
3993
- loadingOverlay: LoadingOverlay = DefaultLoadingOverlay
4037
+ loadingOverlay: LoadingOverlay = DefaultLoadingOverlay,
4038
+ noRowsOverlay: NoRowsOverlay = DefaultNoRowsOverlay
4039
+ } = {},
4040
+ slotProps: {
4041
+ checkbox: checkboxProps = {},
4042
+ toolbar: toolbarProps,
4043
+ background: backgroundProps = {},
4044
+ noRowsOverlay: noRowsOverlayProps = {}
3994
4045
  } = {},
3995
- slotProps: { checkbox: checkboxProps = {}, toolbar: toolbarProps, background: backgroundProps = {} } = {},
3996
4046
  stripe,
3997
4047
  isTotalSelected: ___________,
3998
4048
  ...innerProps
@@ -4036,6 +4086,8 @@ function Component(props, apiRef) {
4036
4086
  const paginationModel = (0, import_react28.useMemo)(() => ({ page, pageSize }), [page, pageSize]);
4037
4087
  const totalSize = virtualizer.getTotalSize();
4038
4088
  const virtualizedItems = virtualizer.getVirtualItems();
4089
+ const showNoRowsOverlay = !loading && rowCount === 0;
4090
+ const totalColCount = Math.max(1, columns.length + (checkboxSelection ? 1 : 0));
4039
4091
  const getRowClickHandler = (0, import_react28.useCallback)(
4040
4092
  (row, rowId) => (e) => {
4041
4093
  onRowClick?.({ row, rowId }, e);
@@ -4225,7 +4277,7 @@ function Component(props, apiRef) {
4225
4277
  width: c.width
4226
4278
  }
4227
4279
  }
4228
- ))), /* @__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(
4280
+ ))), /* @__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(
4229
4281
  "th",
4230
4282
  {
4231
4283
  rowSpan: processedColumnGroups.maxLevel + 2,
@@ -4245,7 +4297,7 @@ function Component(props, apiRef) {
4245
4297
  ...checkboxProps
4246
4298
  }
4247
4299
  )
4248
- ), 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) => {
4300
+ ), 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) => {
4249
4301
  const nextGroup = levelGroups[groupIndex + 1];
4250
4302
  const emptyCells = nextGroup ? nextGroup.startIndex - (group.startIndex + group.colspan) : columns.length - (group.startIndex + group.colspan);
4251
4303
  const params = { groupId: group.groupId };
@@ -4263,7 +4315,7 @@ function Component(props, apiRef) {
4263
4315
  },
4264
4316
  group.headerName ?? group.groupId
4265
4317
  ), emptyCells > 0 && Array.from({ length: emptyCells }).map((_2, i) => /* @__PURE__ */ import_react28.default.createElement("th", { key: `empty-between-${level}-${groupIndex}-${i}`, colSpan: 1 })));
4266
- }))), /* @__PURE__ */ import_react28.default.createElement("tr", null, !processedColumnGroups && checkboxSelection && /* @__PURE__ */ import_react28.default.createElement(
4318
+ }))), /* @__PURE__ */ import_react28.default.createElement("tr", null, (!processedColumnGroups || processedColumnGroups.groups.length === 0) && checkboxSelection && /* @__PURE__ */ import_react28.default.createElement(
4267
4319
  "th",
4268
4320
  {
4269
4321
  style: {
@@ -4327,6 +4379,18 @@ function Component(props, apiRef) {
4327
4379
  /* @__PURE__ */ import_react28.default.createElement(LoadingOverlay, null)
4328
4380
  )
4329
4381
  )),
4382
+ showNoRowsOverlay && /* @__PURE__ */ import_react28.default.createElement("tr", null, /* @__PURE__ */ import_react28.default.createElement("td", { colSpan: totalColCount, style: { border: "none" } }, /* @__PURE__ */ import_react28.default.createElement(
4383
+ Box_default,
4384
+ {
4385
+ sx: {
4386
+ display: "flex",
4387
+ alignItems: "center",
4388
+ justifyContent: "center",
4389
+ minHeight: "150px"
4390
+ }
4391
+ },
4392
+ /* @__PURE__ */ import_react28.default.createElement(NoRowsOverlay, { ...noRowsOverlayProps })
4393
+ ))),
4330
4394
  virtualizedItems.map((virtualizedRow, index) => {
4331
4395
  const rowIndex = virtualizedRow.index;
4332
4396
  const row = dataInPage[rowIndex];
package/dist/index.js CHANGED
@@ -2000,14 +2000,15 @@ function reorderColumnsByGroupingModel(columns, columnGroupingModel) {
2000
2000
  }
2001
2001
  return reorderedColumns;
2002
2002
  }
2003
- function flattenColumnGroups(items, groupPath = [], columnIndex = { current: 0 }) {
2003
+ function flattenColumnGroups(items, groupPath = [], columnIndex = { current: 0 }, visibleFields) {
2004
2004
  const result = [];
2005
2005
  for (const item of items) {
2006
2006
  if ("groupId" in item) {
2007
2007
  const newPath = [...groupPath, item.groupId];
2008
2008
  const children = Array.isArray(item.children) ? item.children : [item.children];
2009
- result.push(...flattenColumnGroups(children, newPath, columnIndex));
2009
+ result.push(...flattenColumnGroups(children, newPath, columnIndex, visibleFields));
2010
2010
  } else {
2011
+ if (visibleFields && !visibleFields.has(item.field)) continue;
2011
2012
  result.push({
2012
2013
  ...item,
2013
2014
  groupPath,
@@ -2017,9 +2018,9 @@ function flattenColumnGroups(items, groupPath = [], columnIndex = { current: 0 }
2017
2018
  }
2018
2019
  return result;
2019
2020
  }
2020
- function calculateColumnGroups(columnGroupingModel, columns) {
2021
+ function calculateColumnGroups(columnGroupingModel, columns, visibleFields) {
2021
2022
  const fieldsInGroupingModel = extractFieldsFromGroupingModel(columnGroupingModel);
2022
- const flattenedColumns = flattenColumnGroups(columnGroupingModel);
2023
+ const flattenedColumns = flattenColumnGroups(columnGroupingModel, [], { current: 0 }, visibleFields);
2023
2024
  const columnIndexMap = new Map(flattenedColumns.map((col) => [col.field, col.columnIndex]));
2024
2025
  const processedGroups = /* @__PURE__ */ new Map();
2025
2026
  const groupsByLevel = [];
@@ -2067,7 +2068,9 @@ function calculateColumnGroups(columnGroupingModel, columns) {
2067
2068
  groupsByLevel.forEach((level) => {
2068
2069
  level.sort((a, b) => a.startIndex - b.startIndex);
2069
2070
  });
2070
- return { groups: groupsByLevel, maxLevel, fieldsInGroupingModel };
2071
+ const filteredGroupsByLevel = groupsByLevel.map((level) => level.filter((g) => g.colspan > 0)).filter((level) => level.length > 0);
2072
+ const correctedMaxLevel = filteredGroupsByLevel.length > 0 ? filteredGroupsByLevel.length - 1 : -1;
2073
+ return { groups: filteredGroupsByLevel, maxLevel: correctedMaxLevel, fieldsInGroupingModel };
2071
2074
  }
2072
2075
  function getTextAlign(props) {
2073
2076
  return !props.editMode && ["number", "date", "currency"].includes(props.type || "") ? "end" : "start";
@@ -2076,7 +2079,7 @@ var numberFormatter = (value) => "Intl" in window ? new Intl.NumberFormat().form
2076
2079
 
2077
2080
  // src/components/DataTable/styled.tsx
2078
2081
  import React17 from "react";
2079
- import { styled as styled8, LinearProgress, buttonClasses, iconButtonClasses } from "@mui/joy";
2082
+ import { styled as styled8, LinearProgress, buttonClasses, iconButtonClasses, Typography as Typography3 } from "@mui/joy";
2080
2083
  import { motion as motion17 } from "framer-motion";
2081
2084
  import SortIcon from "@mui/icons-material/ArrowUpwardRounded";
2082
2085
  var EllipsisDiv = styled8("div", {
@@ -2182,6 +2185,7 @@ var StyledTd = styled8("td")(({ theme }) => ({
2182
2185
  }));
2183
2186
  var MotionSortIcon = motion17(SortIcon);
2184
2187
  var DefaultLoadingOverlay = () => /* @__PURE__ */ React17.createElement(LinearProgress, { value: 8, variant: "plain" });
2188
+ var DefaultNoRowsOverlay = () => /* @__PURE__ */ React17.createElement(Typography3, { level: "body-sm", textColor: "text.tertiary" }, "No rows");
2185
2189
  var Resizer = (ref, targetRef = ref) => /* @__PURE__ */ React17.createElement(
2186
2190
  Box_default,
2187
2191
  {
@@ -2653,7 +2657,7 @@ var Textarea_default = Textarea;
2653
2657
 
2654
2658
  // src/components/Select/Select.tsx
2655
2659
  import React20, { useMemo as useMemo7 } from "react";
2656
- import { Select as JoySelect, Option as JoyOption, ListItemContent as ListItemContent2, Typography as Typography3 } from "@mui/joy";
2660
+ import { Select as JoySelect, Option as JoyOption, ListItemContent as ListItemContent2, Typography as Typography4 } from "@mui/joy";
2657
2661
  import { motion as motion20 } from "framer-motion";
2658
2662
  var MotionOption = motion20(JoyOption);
2659
2663
  var Option = MotionOption;
@@ -2727,7 +2731,7 @@ function Select(props) {
2727
2731
  return optionMap.get(selected.value)?.label;
2728
2732
  }
2729
2733
  },
2730
- 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))
2734
+ 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))
2731
2735
  );
2732
2736
  return /* @__PURE__ */ React20.createElement(
2733
2737
  FormControl_default,
@@ -3240,7 +3244,9 @@ function useDataTableRenderer({
3240
3244
  getId: _getId,
3241
3245
  isTotalSelected: _isTotalSelected,
3242
3246
  isRowSelectable,
3243
- columnGroupingModel
3247
+ columnGroupingModel,
3248
+ columnVisibilityModel,
3249
+ onColumnVisibilityModelChange
3244
3250
  }) {
3245
3251
  if (pinnedColumns && columnGroupingModel) {
3246
3252
  throw new Error(
@@ -3256,12 +3262,35 @@ function useDataTableRenderer({
3256
3262
  initialState?.sorting?.sortModel ?? [],
3257
3263
  useCallback10((sortModel2) => onSortModelChange?.(sortModel2), [onSortModelChange])
3258
3264
  );
3265
+ const [visibilityModel] = useControlledState(
3266
+ columnVisibilityModel,
3267
+ initialState?.columns?.columnVisibilityModel ?? {},
3268
+ useCallback10(
3269
+ (model) => onColumnVisibilityModelChange?.(model),
3270
+ [onColumnVisibilityModelChange]
3271
+ )
3272
+ );
3259
3273
  const reorderedColumns = useMemo9(() => {
3260
3274
  if (!columnGroupingModel) return columnsProp;
3261
3275
  return reorderColumnsByGroupingModel(columnsProp, columnGroupingModel);
3262
3276
  }, [columnsProp, columnGroupingModel]);
3263
- const columnsByField = useMemo9(
3277
+ const visibleColumns = useMemo9(
3278
+ () => reorderedColumns.filter((col) => visibilityModel[col.field] !== false),
3279
+ [reorderedColumns, visibilityModel]
3280
+ );
3281
+ const visibleFieldSet = useMemo9(() => new Set(visibleColumns.map((c) => c.field)), [visibleColumns]);
3282
+ const allColumnsByField = useMemo9(
3264
3283
  () => reorderedColumns.reduce(
3284
+ (acc, curr) => ({
3285
+ ...acc,
3286
+ [curr.field]: curr
3287
+ }),
3288
+ {}
3289
+ ),
3290
+ [reorderedColumns]
3291
+ );
3292
+ const visibleColumnsByField = useMemo9(
3293
+ () => visibleColumns.reduce(
3265
3294
  (acc, curr) => ({
3266
3295
  ...acc,
3267
3296
  [curr.field]: {
@@ -3272,7 +3301,7 @@ function useDataTableRenderer({
3272
3301
  }),
3273
3302
  {}
3274
3303
  ),
3275
- [reorderedColumns]
3304
+ [visibleColumns]
3276
3305
  );
3277
3306
  const sortComparator = useCallback10(
3278
3307
  (rowA, rowB) => {
@@ -3280,7 +3309,8 @@ function useDataTableRenderer({
3280
3309
  const { field, sort: direction } = sort;
3281
3310
  const a = rowA[field];
3282
3311
  const b = rowB[field];
3283
- const column = columnsByField[field];
3312
+ const column = allColumnsByField[field];
3313
+ if (!column) continue;
3284
3314
  let comparison = 0;
3285
3315
  if (column.sortComparator) {
3286
3316
  comparison = column.sortComparator({
@@ -3300,7 +3330,7 @@ function useDataTableRenderer({
3300
3330
  }
3301
3331
  return 0;
3302
3332
  },
3303
- [sortModel, columnsByField]
3333
+ [sortModel, allColumnsByField]
3304
3334
  );
3305
3335
  const rows = useMemo9(
3306
3336
  () => sortModel.length ? [..._rows].sort(sortComparator) : _rows,
@@ -3364,44 +3394,54 @@ function useDataTableRenderer({
3364
3394
  () => _isTotalSelected ?? (selectableRowCount > 0 && (selectionModel?.length || 0) === selectableRowCount),
3365
3395
  [_isTotalSelected, selectionModel, selectableRowCount]
3366
3396
  );
3367
- const columnWidths = useColumnWidths(columnsByField);
3397
+ const columnWidths = useColumnWidths(visibleColumnsByField);
3368
3398
  const getWidth = useCallback10(
3369
- (f) => columnWidths[f] ?? columnsByField[f].width ?? // Column prop 으로 지정된 width
3370
- columnsByField[f].minWidth ?? 0,
3371
- [columnWidths, columnsByField]
3399
+ (f) => columnWidths[f] ?? allColumnsByField[f]?.width ?? // Column prop 으로 지정된 width
3400
+ allColumnsByField[f]?.minWidth ?? 0,
3401
+ [columnWidths, allColumnsByField]
3372
3402
  );
3373
3403
  const processedColumnGroups = useMemo9(() => {
3374
3404
  if (!columnGroupingModel) return null;
3375
- return calculateColumnGroups(columnGroupingModel, reorderedColumns);
3376
- }, [columnGroupingModel, reorderedColumns]);
3405
+ return calculateColumnGroups(columnGroupingModel, visibleColumns, visibleFieldSet);
3406
+ }, [columnGroupingModel, visibleColumns, visibleFieldSet]);
3407
+ const effectivePinnedLeft = useMemo9(
3408
+ () => pinnedColumns?.left?.filter((f) => visibleFieldSet.has(f)),
3409
+ [pinnedColumns?.left, visibleFieldSet]
3410
+ );
3411
+ const effectivePinnedRight = useMemo9(
3412
+ () => pinnedColumns?.right?.filter((f) => visibleFieldSet.has(f)),
3413
+ [pinnedColumns?.right, visibleFieldSet]
3414
+ );
3377
3415
  const columns = useMemo9(() => {
3378
- const baseColumns = reorderedColumns.length > 0 ? reorderedColumns : Object.keys(rows[0] || {}).map((key) => ({
3416
+ const baseColumns = visibleColumns.length > 0 ? visibleColumns : reorderedColumns.length > 0 ? [] : Object.keys(rows[0] || {}).map((key) => ({
3379
3417
  field: key
3380
3418
  }));
3381
3419
  return baseColumns.map((column) => {
3382
- const isLeftPinned = pinnedColumns?.left?.includes(column.field);
3383
- const isRightPinned = pinnedColumns?.right?.includes(column.field);
3420
+ const isLeftPinned = effectivePinnedLeft?.includes(column.field);
3421
+ const isRightPinned = effectivePinnedRight?.includes(column.field);
3384
3422
  const isPinned = isLeftPinned || isRightPinned;
3385
3423
  return {
3386
3424
  ...column,
3387
- headerRef: columnsByField[column.field].headerRef,
3388
- tableColRef: columnsByField[column.field].tableColRef,
3425
+ headerRef: visibleColumnsByField[column.field]?.headerRef,
3426
+ tableColRef: visibleColumnsByField[column.field]?.tableColRef,
3389
3427
  isCellEditable: editMode && (typeof column.isCellEditable === "function" ? column.isCellEditable : column.isCellEditable ?? true),
3390
3428
  sort: sortModel.find((sort) => sort.field === column.field)?.sort,
3391
- sortOrder: columnsByField[column.field]?.sortOrder || sortOrder,
3429
+ sortOrder: allColumnsByField[column.field]?.sortOrder || sortOrder,
3392
3430
  isPinned,
3393
- isLastStartPinnedColumn: isLeftPinned && [...pinnedColumns?.left || []].pop() === column.field,
3394
- isLastEndPinnedColumn: isRightPinned && (pinnedColumns?.right?.[0] ?? null) === column.field,
3395
- pinnedStartPosition: pinnedColumns?.left?.slice(0, isLeftPinned ? pinnedColumns.left.indexOf(column.field) : pinnedColumns.left.length).reduce((acc, curr) => acc + getWidth(curr), 0),
3396
- pinnedEndPosition: pinnedColumns?.right?.slice(isRightPinned ? pinnedColumns.right.indexOf(column.field) + 1 : 0).reduce((acc, curr) => acc + getWidth(curr), 0)
3431
+ isLastStartPinnedColumn: isLeftPinned && [...effectivePinnedLeft || []].pop() === column.field,
3432
+ isLastEndPinnedColumn: isRightPinned && (effectivePinnedRight?.[0] ?? null) === column.field,
3433
+ pinnedStartPosition: effectivePinnedLeft?.slice(0, isLeftPinned ? effectivePinnedLeft.indexOf(column.field) : effectivePinnedLeft.length).reduce((acc, curr) => acc + getWidth(curr), 0),
3434
+ pinnedEndPosition: effectivePinnedRight?.slice(isRightPinned ? effectivePinnedRight.indexOf(column.field) + 1 : 0).reduce((acc, curr) => acc + getWidth(curr), 0)
3397
3435
  };
3398
3436
  });
3399
3437
  }, [
3438
+ visibleColumns,
3400
3439
  reorderedColumns,
3401
3440
  rows,
3402
- pinnedColumns?.left,
3403
- pinnedColumns?.right,
3404
- columnsByField,
3441
+ effectivePinnedLeft,
3442
+ effectivePinnedRight,
3443
+ visibleColumnsByField,
3444
+ allColumnsByField,
3405
3445
  editMode,
3406
3446
  sortModel,
3407
3447
  sortOrder,
@@ -3417,8 +3457,8 @@ function useDataTableRenderer({
3417
3457
  const handleSortChange = useCallback10(
3418
3458
  (props) => {
3419
3459
  const { field, currentSort, multiple } = props;
3420
- const column = columnsByField[field];
3421
- const columnSortOrder = column.sortOrder || sortOrder;
3460
+ const column = allColumnsByField[field];
3461
+ const columnSortOrder = column?.sortOrder || sortOrder;
3422
3462
  if (currentSort !== void 0) {
3423
3463
  const currentOrderIndex = columnSortOrder.indexOf(currentSort);
3424
3464
  const nextSortOrderIndex = (currentOrderIndex + 1) % columnSortOrder.length;
@@ -3435,7 +3475,7 @@ function useDataTableRenderer({
3435
3475
  setSortModel(newSortModel);
3436
3476
  }
3437
3477
  },
3438
- [sortOrder, columnsByField, sortModel, setSortModel]
3478
+ [sortOrder, allColumnsByField, sortModel, setSortModel]
3439
3479
  );
3440
3480
  useEffect6(() => {
3441
3481
  if (!paginationModel) {
@@ -3861,13 +3901,23 @@ function Component(props, apiRef) {
3861
3901
  loading,
3862
3902
  columnGroupingModel: _________________,
3863
3903
  // columnGroupingModel is used in useDataTableRenderer
3904
+ columnVisibilityModel: __________________,
3905
+ // columnVisibilityModel is used in useDataTableRenderer
3906
+ onColumnVisibilityModelChange: ___________________,
3907
+ // onColumnVisibilityModelChange is used in useDataTableRenderer
3864
3908
  slots: {
3865
3909
  checkbox: RenderCheckbox = Checkbox_default,
3866
3910
  toolbar: Toolbar,
3867
3911
  footer: Footer,
3868
- loadingOverlay: LoadingOverlay = DefaultLoadingOverlay
3912
+ loadingOverlay: LoadingOverlay = DefaultLoadingOverlay,
3913
+ noRowsOverlay: NoRowsOverlay = DefaultNoRowsOverlay
3914
+ } = {},
3915
+ slotProps: {
3916
+ checkbox: checkboxProps = {},
3917
+ toolbar: toolbarProps,
3918
+ background: backgroundProps = {},
3919
+ noRowsOverlay: noRowsOverlayProps = {}
3869
3920
  } = {},
3870
- slotProps: { checkbox: checkboxProps = {}, toolbar: toolbarProps, background: backgroundProps = {} } = {},
3871
3921
  stripe,
3872
3922
  isTotalSelected: ___________,
3873
3923
  ...innerProps
@@ -3911,6 +3961,8 @@ function Component(props, apiRef) {
3911
3961
  const paginationModel = useMemo10(() => ({ page, pageSize }), [page, pageSize]);
3912
3962
  const totalSize = virtualizer.getTotalSize();
3913
3963
  const virtualizedItems = virtualizer.getVirtualItems();
3964
+ const showNoRowsOverlay = !loading && rowCount === 0;
3965
+ const totalColCount = Math.max(1, columns.length + (checkboxSelection ? 1 : 0));
3914
3966
  const getRowClickHandler = useCallback12(
3915
3967
  (row, rowId) => (e) => {
3916
3968
  onRowClick?.({ row, rowId }, e);
@@ -4100,7 +4152,7 @@ function Component(props, apiRef) {
4100
4152
  width: c.width
4101
4153
  }
4102
4154
  }
4103
- ))), /* @__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(
4155
+ ))), /* @__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(
4104
4156
  "th",
4105
4157
  {
4106
4158
  rowSpan: processedColumnGroups.maxLevel + 2,
@@ -4120,7 +4172,7 @@ function Component(props, apiRef) {
4120
4172
  ...checkboxProps
4121
4173
  }
4122
4174
  )
4123
- ), level > 0 && Array.from({ length: levelGroups[0]?.startIndex || 0 }).map((_2, i) => /* @__PURE__ */ React25.createElement("th", { key: `empty-${level}-${i}` })), levelGroups.map((group, groupIndex) => {
4175
+ ), 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) => {
4124
4176
  const nextGroup = levelGroups[groupIndex + 1];
4125
4177
  const emptyCells = nextGroup ? nextGroup.startIndex - (group.startIndex + group.colspan) : columns.length - (group.startIndex + group.colspan);
4126
4178
  const params = { groupId: group.groupId };
@@ -4138,7 +4190,7 @@ function Component(props, apiRef) {
4138
4190
  },
4139
4191
  group.headerName ?? group.groupId
4140
4192
  ), emptyCells > 0 && Array.from({ length: emptyCells }).map((_2, i) => /* @__PURE__ */ React25.createElement("th", { key: `empty-between-${level}-${groupIndex}-${i}`, colSpan: 1 })));
4141
- }))), /* @__PURE__ */ React25.createElement("tr", null, !processedColumnGroups && checkboxSelection && /* @__PURE__ */ React25.createElement(
4193
+ }))), /* @__PURE__ */ React25.createElement("tr", null, (!processedColumnGroups || processedColumnGroups.groups.length === 0) && checkboxSelection && /* @__PURE__ */ React25.createElement(
4142
4194
  "th",
4143
4195
  {
4144
4196
  style: {
@@ -4202,6 +4254,18 @@ function Component(props, apiRef) {
4202
4254
  /* @__PURE__ */ React25.createElement(LoadingOverlay, null)
4203
4255
  )
4204
4256
  )),
4257
+ showNoRowsOverlay && /* @__PURE__ */ React25.createElement("tr", null, /* @__PURE__ */ React25.createElement("td", { colSpan: totalColCount, style: { border: "none" } }, /* @__PURE__ */ React25.createElement(
4258
+ Box_default,
4259
+ {
4260
+ sx: {
4261
+ display: "flex",
4262
+ alignItems: "center",
4263
+ justifyContent: "center",
4264
+ minHeight: "150px"
4265
+ }
4266
+ },
4267
+ /* @__PURE__ */ React25.createElement(NoRowsOverlay, { ...noRowsOverlayProps })
4268
+ ))),
4205
4269
  virtualizedItems.map((virtualizedRow, index) => {
4206
4270
  const rowIndex = virtualizedRow.index;
4207
4271
  const row = dataInPage[rowIndex];
@@ -5302,7 +5366,7 @@ CurrencyRange.displayName = "CurrencyRange";
5302
5366
 
5303
5367
  // src/components/FilterMenu/components/PercentageInput.tsx
5304
5368
  import React38 from "react";
5305
- import { Stack as Stack8, Typography as Typography4 } from "@mui/joy";
5369
+ import { Stack as Stack8, Typography as Typography5 } from "@mui/joy";
5306
5370
 
5307
5371
  // src/components/PercentageInput/PercentageInput.tsx
5308
5372
  import React37, { useCallback as useCallback21, useMemo as useMemo14, useState as useState13 } from "react";
@@ -5437,7 +5501,7 @@ var PercentageInput3 = ({
5437
5501
  if (hidden) {
5438
5502
  return null;
5439
5503
  }
5440
- return /* @__PURE__ */ React38.createElement(Stack8, { spacing: 3, role: "group", "aria-labelledby": id }, !!label && /* @__PURE__ */ React38.createElement(Typography4, { id, level: "title-sm", component: "label", textColor: "text.tertiary" }, label), /* @__PURE__ */ React38.createElement(
5504
+ return /* @__PURE__ */ React38.createElement(Stack8, { spacing: 3, role: "group", "aria-labelledby": id }, !!label && /* @__PURE__ */ React38.createElement(Typography5, { id, level: "title-sm", component: "label", textColor: "text.tertiary" }, label), /* @__PURE__ */ React38.createElement(
5441
5505
  PercentageInput,
5442
5506
  {
5443
5507
  value: _value,