beautiful-grid 1.0.13 → 1.0.15

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.
Files changed (50) hide show
  1. package/README.md +121 -6
  2. package/cjs/BGrid.js +388 -44
  3. package/cjs/components/CellNavigationDomSync.js +8 -0
  4. package/cjs/components/CellTextEditorGateway.js +13 -9
  5. package/cjs/components/ColResizer.js +13 -7
  6. package/cjs/components/MasterDetailCell.js +145 -0
  7. package/cjs/components/MasterDetailContext.js +42 -0
  8. package/cjs/components/Table.js +162 -52
  9. package/cjs/components/TableBody.js +7 -3
  10. package/cjs/components/TableBodyCell.js +2 -1
  11. package/cjs/components/TableSummary.js +25 -34
  12. package/cjs/components/TableSummaryFronzen.js +36 -34
  13. package/cjs/store/createAppStore.js +2 -0
  14. package/cjs/utils/cellSelectionGeometry.js +32 -6
  15. package/cjs/utils/columnVisibility.js +17 -14
  16. package/cjs/utils/index.js +1 -0
  17. package/cjs/utils/rowHeightMetrics.js +47 -6
  18. package/cjs/utils/summary.js +55 -0
  19. package/cjs/utils/useRowReorderController.js +5 -1
  20. package/esm/BGrid.js +387 -72
  21. package/esm/components/CellNavigationDomSync.js +8 -0
  22. package/esm/components/CellTextEditorGateway.js +12 -9
  23. package/esm/components/ColResizer.js +8 -2
  24. package/esm/components/MasterDetailCell.js +101 -0
  25. package/esm/components/MasterDetailContext.js +5 -0
  26. package/esm/components/Table.js +151 -42
  27. package/esm/components/TableBody.js +6 -2
  28. package/esm/components/TableBodyCell.js +2 -1
  29. package/esm/components/TableSummary.js +26 -29
  30. package/esm/components/TableSummaryFronzen.js +26 -29
  31. package/esm/store/createAppStore.js +2 -0
  32. package/esm/utils/cellSelectionGeometry.js +31 -5
  33. package/esm/utils/columnVisibility.js +21 -18
  34. package/esm/utils/index.js +1 -0
  35. package/esm/utils/rowHeightMetrics.js +46 -6
  36. package/esm/utils/summary.js +35 -0
  37. package/esm/utils/useRowReorderController.js +5 -1
  38. package/package.json +1 -1
  39. package/style.css +164 -14
  40. package/types/BGrid.d.ts +1 -1
  41. package/types/components/MasterDetailCell.d.ts +21 -0
  42. package/types/components/MasterDetailContext.d.ts +20 -0
  43. package/types/components/Table.d.ts +1 -0
  44. package/types/components/TableBody.d.ts +2 -1
  45. package/types/store/createAppStore.d.ts +1 -1
  46. package/types/types.d.ts +70 -4
  47. package/types/utils/cellSelectionGeometry.d.ts +3 -1
  48. package/types/utils/index.d.ts +1 -0
  49. package/types/utils/rowHeightMetrics.d.ts +15 -1
  50. package/types/utils/summary.d.ts +13 -0
@@ -46,12 +46,18 @@ function ColResizer({ container, columnIndex, hideHandle, bordered, frozenBounda
46
46
  targetDiv.style.top = '-9999px';
47
47
  targetDiv.innerHTML = `<table><thead>${headFrozenHTML}</thead><tbody>${bodyFrozenHTML}</tbody></table>
48
48
  <table><thead>${headHTML}</thead><tbody>${bodyHTML}</tbody></table>`;
49
- const bodyTarget = document.getElementById('root') ?? document.body;
49
+ // Measure with the grid's inherited font and real header/body padding.
50
+ targetDiv.querySelectorAll('table').forEach(table => {
51
+ table.className = 'bgrid-head-table bgrid-body-table';
52
+ table.style.tableLayout = 'auto';
53
+ table.style.width = 'max-content';
54
+ });
55
+ const bodyTarget = container.current;
50
56
  bodyTarget.append(targetDiv);
51
57
  await delay(30);
52
58
  const targetTd = targetDiv.querySelector(`tr td.bgrid-head-cell[data-column-index="${columnIndex}"]`);
53
59
  if (targetTd) {
54
- setColumnWidth(columnIndex, { width: targetTd.getBoundingClientRect().width });
60
+ setColumnWidth(columnIndex, { width: Math.ceil(targetTd.offsetWidth) + 1 });
55
61
  setColumnWidth(columnIndex, { updateColumns: true });
56
62
  }
57
63
  targetDiv.remove();
@@ -0,0 +1,101 @@
1
+ import * as React from 'react';
2
+ import { getColumnId } from '../utils';
3
+ import { useMasterDetailContext } from './MasterDetailContext';
4
+ export function MasterDetailCell({ column, item, sourceIndex, children }) {
5
+ const masterDetail = useMasterDetailContext();
6
+ if (!masterDetail || getColumnId(column) !== masterDetail.expandColumnId) {
7
+ return React.createElement(React.Fragment, null, children);
8
+ }
9
+ const rowKey = masterDetail.getRowKey(item.values);
10
+ if (rowKey === undefined || rowKey === null) {
11
+ return React.createElement(React.Fragment, null, children);
12
+ }
13
+ const isExpandable = masterDetail.hasDetail(item, sourceIndex);
14
+ const expanded = masterDetail.expandedKeysSet.has(rowKey);
15
+ const toggleId = masterDetail.getToggleElementId(rowKey);
16
+ const detailId = masterDetail.getDetailElementId(rowKey);
17
+ return (React.createElement("span", { className: 'bgrid-master-detail-cell' },
18
+ isExpandable ? (React.createElement("button", { type: 'button', id: toggleId, className: 'bgrid-master-detail-toggle', "aria-expanded": expanded, "aria-controls": expanded ? detailId : undefined, "aria-label": expanded ? masterDetail.collapseAriaLabel : masterDetail.expandAriaLabel, disabled: masterDetail.disabled, onClick: event => {
19
+ event.stopPropagation();
20
+ masterDetail.toggle(rowKey, item, sourceIndex);
21
+ }, onKeyDown: event => {
22
+ // Prevent master grid cell navigation from capturing Space or Enter on the toggle button
23
+ if (event.key === ' ' || event.key === 'Enter') {
24
+ event.stopPropagation();
25
+ }
26
+ } },
27
+ React.createElement("span", { className: 'bgrid-master-detail-icon', "aria-hidden": 'true' }, expanded ? masterDetail.icons?.expanded ?? '⌄' : masterDetail.icons?.collapsed ?? '›'))) : (React.createElement("span", { className: 'bgrid-master-detail-toggle-spacer', "aria-hidden": 'true' })),
28
+ React.createElement("span", { className: 'bgrid-master-detail-cell-content' }, children)));
29
+ }
30
+ export function MasterDetailRow({ item, sourceIndex, visibleIndex, detailHeight, isLeftRegion, viewportWidth, colSpan, frozenColumnsWidth, }) {
31
+ const masterDetail = useMasterDetailContext();
32
+ if (!masterDetail)
33
+ return null;
34
+ const rowKey = masterDetail.getRowKey(item.values);
35
+ if (rowKey === undefined || rowKey === null || !masterDetail.expandedKeysSet.has(rowKey)) {
36
+ return null;
37
+ }
38
+ const toggleId = masterDetail.getToggleElementId(rowKey);
39
+ const detailId = masterDetail.getDetailElementId(rowKey);
40
+ if (isLeftRegion) {
41
+ return (React.createElement("tr", { className: 'bgrid-detail-frozen-row', "aria-hidden": 'true', "data-detail-ri": visibleIndex, style: {
42
+ height: detailHeight,
43
+ ['--bgrid-item-cell-height']: `${detailHeight}px`,
44
+ } },
45
+ React.createElement("td", { colSpan: colSpan, style: {
46
+ height: detailHeight,
47
+ maxHeight: 'none',
48
+ padding: 0,
49
+ margin: 0,
50
+ } })));
51
+ }
52
+ return (React.createElement("tr", { className: 'bgrid-detail-row', "data-bgrid-detail-owner": 'true', "data-detail-ri": visibleIndex, style: {
53
+ height: detailHeight,
54
+ ['--bgrid-item-cell-height']: `${detailHeight}px`,
55
+ } },
56
+ React.createElement("td", { colSpan: colSpan, className: 'bgrid-detail-cell', style: {
57
+ height: detailHeight,
58
+ maxHeight: 'none',
59
+ padding: 0,
60
+ margin: 0,
61
+ verticalAlign: 'top',
62
+ } },
63
+ React.createElement(DetailPanelContent, { item: item, rowKey: rowKey, sourceIndex: sourceIndex, visibleIndex: visibleIndex, detailHeight: detailHeight, viewportWidth: viewportWidth, frozenColumnsWidth: frozenColumnsWidth, toggleId: toggleId, detailId: detailId, detailRender: masterDetail.detailRender, collapse: () => masterDetail.collapse(rowKey) })),
64
+ React.createElement("td", { "data-none": 'true' })));
65
+ }
66
+ function DetailPanelContent({ item, rowKey, sourceIndex, visibleIndex, detailHeight, viewportWidth, frozenColumnsWidth, toggleId, detailId, detailRender, collapse, }) {
67
+ const panelRef = React.useRef(null);
68
+ React.useEffect(() => {
69
+ const panel = panelRef.current;
70
+ return () => {
71
+ const active = document.activeElement;
72
+ if (active && panel && panel.contains(active)) {
73
+ const toggle = document.getElementById(toggleId);
74
+ toggle?.focus();
75
+ }
76
+ };
77
+ }, [toggleId]);
78
+ const contentHeight = Math.max(detailHeight - 1, 0);
79
+ return (React.createElement("div", { ref: panelRef, id: detailId, role: 'region', "aria-labelledby": toggleId, className: 'bgrid-master-detail-panel', "data-bgrid-detail-owner": 'true', "data-visible-index": visibleIndex, "data-source-index": sourceIndex, style: {
80
+ position: 'sticky',
81
+ left: frozenColumnsWidth ?? 0,
82
+ width: viewportWidth > 0 ? viewportWidth : undefined,
83
+ maxWidth: '100%',
84
+ height: contentHeight,
85
+ minHeight: contentHeight,
86
+ maxHeight: contentHeight,
87
+ boxSizing: 'border-box',
88
+ overflow: 'auto',
89
+ }, onPointerDown: e => {
90
+ e.stopPropagation();
91
+ }, onContextMenu: e => {
92
+ e.stopPropagation();
93
+ } }, detailRender({
94
+ item,
95
+ rowKey,
96
+ sourceIndex,
97
+ visibleIndex,
98
+ expanded: true,
99
+ collapse,
100
+ })));
101
+ }
@@ -0,0 +1,5 @@
1
+ import * as React from 'react';
2
+ export const MasterDetailContext = React.createContext(undefined);
3
+ export function useMasterDetailContext() {
4
+ return React.useContext(MasterDetailContext);
5
+ }
@@ -58,11 +58,12 @@ function Table(props) {
58
58
  itemPadding: s.itemPadding,
59
59
  })));
60
60
  // [Selector Group 2] Header, Footer, Summary - 헤더/푸터/요약
61
- const { headerHeight, footerHeight, bottomBarHeight, summaryHeight } = useAppStore(useShallow(s => ({
61
+ const { headerHeight, footerHeight, bottomBarHeight, summaryHeight, summaryRowHeight } = useAppStore(useShallow(s => ({
62
62
  headerHeight: s.headerHeight,
63
63
  footerHeight: s.footerHeight,
64
64
  bottomBarHeight: s.bottomBarHeight,
65
65
  summaryHeight: s.summaryHeight,
66
+ summaryRowHeight: s.summaryRowHeight,
66
67
  })));
67
68
  // [Selector Group 3] Scroll State - 스크롤 상태
68
69
  const { scrollLeft, scrollTop } = useAppStore(useShallow(s => ({
@@ -113,7 +114,7 @@ function Table(props) {
113
114
  cellInteractionSession: s.cellInteractionSession,
114
115
  })));
115
116
  // [Selector Group 6] State Setters - 차원 설정자
116
- const { setHeight, setWidth, setContentBodyHeight, setDisplayItemCount, setHeaderHeight, setFooterHeight, setBottomBarHeight, setSummaryHeight, setItemHeight, setItemPadding, setLoading, setSpinning, setDisabled, } = useAppStore(useShallow(s => ({
117
+ const { setHeight, setWidth, setContentBodyHeight, setDisplayItemCount, setHeaderHeight, setFooterHeight, setBottomBarHeight, setSummaryHeight, setSummaryRowHeight, setItemHeight, setItemPadding, setLoading, setSpinning, setDisabled, } = useAppStore(useShallow(s => ({
117
118
  setHeight: s.setHeight,
118
119
  setWidth: s.setWidth,
119
120
  setContentBodyHeight: s.setContentBodyHeight,
@@ -122,6 +123,7 @@ function Table(props) {
122
123
  setFooterHeight: s.setFooterHeight,
123
124
  setBottomBarHeight: s.setBottomBarHeight,
124
125
  setSummaryHeight: s.setSummaryHeight,
126
+ setSummaryRowHeight: s.setSummaryRowHeight,
125
127
  setItemHeight: s.setItemHeight,
126
128
  setItemPadding: s.setItemPadding,
127
129
  setLoading: s.setLoading,
@@ -204,20 +206,29 @@ function Table(props) {
204
206
  const variableRowOffsets = rowHeightMetrics.variable ? rowHeightMetrics.offsets : undefined;
205
207
  const scrollableBodyHeight = Math.max(contentBodyHeight - frozenRowsHeight, 0);
206
208
  const scrollOverscanRows = Math.max(KEYBOARD_NAVIGATION_ROW_WINDOW_SIZE, Math.ceil(scrollableBodyHeight / Math.max(trHeight, 1)));
207
- const mainViewportWidth = Math.max(width - (frozenColumnsWidth ?? 0), 0);
208
209
  const logicalBodyContentHeight = rowHeightMetrics.totalHeight;
210
+ const scrollContainerRef = useRef(null);
211
+ const scrollableColumnsWidth = React.useMemo(() => columns.slice(props.frozenColumnIndex ?? 0).reduce((totalWidth, column) => totalWidth + (column.width ?? 100), 0), [columns, props.frozenColumnIndex]);
212
+ const stickyTopHeight = headerHeight + (summary?.position === 'top' ? summaryHeight : 0);
213
+ const stickyBottomHeight = summary?.position === 'bottom' ? summaryHeight : 0;
214
+ const stickyFixedHeight = stickyTopHeight + stickyBottomHeight;
215
+ const scrollPlaneContentWidth = (frozenColumnsWidth ?? 0) + scrollableColumnsWidth;
216
+ const measuredScrollbarMetrics = useScrollbarMetrics(scrollContainerRef, [data.length, itemHeight, itemPadding, contentBodyHeight, width], scrollPlaneContentWidth, stickyFixedHeight);
217
+ // Native horizontal scrollbars occupy viewport space; use the measured body height for every scroll path.
218
+ const effectiveBodyHeight = scrollbar.variant === 'native'
219
+ ? measuredScrollbarMetrics.vertical.viewportSize || contentBodyHeight
220
+ : contentBodyHeight;
209
221
  const virtualScrollWindowMetrics = React.useMemo(() => getVirtualScrollWindowMetrics({
210
222
  logicalContentHeight: logicalBodyContentHeight,
211
- viewportHeight: contentBodyHeight,
223
+ viewportHeight: effectiveBodyHeight,
212
224
  enabled: scrollbar.variant !== 'native',
213
- }), [contentBodyHeight, logicalBodyContentHeight, scrollbar.variant]);
225
+ }), [effectiveBodyHeight, logicalBodyContentHeight, scrollbar.variant]);
214
226
  const [virtualScrollBase, setVirtualScrollBase] = React.useState(0);
215
227
  const virtualScrollBaseRef = useRef(0);
216
228
  const containerRef = useRef(null);
217
229
  const searchPopoverRef = useRef(null);
218
230
  const editorPortalRef = useRef(null);
219
231
  const bodyContainerRef = useRef(null);
220
- const scrollContainerRef = useRef(null);
221
232
  const logicalVerticalScrollState = React.useMemo(() => ({
222
233
  scrollTop,
223
234
  scrollHeight: virtualScrollWindowMetrics.logicalContentHeight,
@@ -275,6 +286,8 @@ function Table(props) {
275
286
  rowCount: data.length,
276
287
  rowHeight: trHeight,
277
288
  rowOffsets: variableRowOffsets,
289
+ rowHeights: rowHeightMetrics.heights,
290
+ detailHeights: rowHeightMetrics.detailHeights,
278
291
  frozenColumnCount: props.frozenColumnIndex ?? 0,
279
292
  frozenRowCount,
280
293
  frozenColumnsWidth: frozenColumnsWidth ?? 0,
@@ -285,6 +298,8 @@ function Table(props) {
285
298
  frozenColumnsWidth,
286
299
  frozenRowCount,
287
300
  props.frozenColumnIndex,
301
+ rowHeightMetrics.detailHeights,
302
+ rowHeightMetrics.heights,
288
303
  trHeight,
289
304
  variableRowOffsets,
290
305
  ]);
@@ -294,6 +309,8 @@ function Table(props) {
294
309
  rowCount: data.length,
295
310
  rowHeight: trHeight,
296
311
  rowOffsets: variableRowOffsets,
312
+ rowHeights: rowHeightMetrics.heights,
313
+ detailHeights: rowHeightMetrics.detailHeights,
297
314
  frozenColumnCount: props.frozenColumnIndex ?? 0,
298
315
  frozenRowCount,
299
316
  frozenColumnsWidth: frozenColumnsWidth ?? 0,
@@ -304,21 +321,13 @@ function Table(props) {
304
321
  frozenColumnsWidth,
305
322
  frozenRowCount,
306
323
  props.frozenColumnIndex,
324
+ rowHeightMetrics.detailHeights,
325
+ rowHeightMetrics.heights,
307
326
  trHeight,
308
327
  variableRowOffsets,
309
328
  ]);
310
329
  const activeOverlayFill = activeCellSelected;
311
330
  const activeOverlayRing = !!activeCell && !hasMultiCellSelection;
312
- const renderSelectionOverlay = (quadrant) => {
313
- const topQuadrant = quadrant === 'top-left' || quadrant === 'top-main';
314
- const leftQuadrant = quadrant === 'top-left' || quadrant === 'body-left';
315
- return (React.createElement(CellSelectionOverlay, { quadrant: quadrant, selectionFragments: selectionFragments, activeFragments: activeFragments, activeFill: activeOverlayFill, activeRing: activeOverlayRing, viewport: {
316
- left: leftQuadrant ? 0 : scrollLeft,
317
- top: topQuadrant ? 0 : scrollTop,
318
- width: leftQuadrant ? frozenColumnsWidth ?? 0 : mainViewportWidth,
319
- height: topQuadrant ? frozenRowsHeight : scrollableBodyHeight,
320
- }, offsetTop: !topQuadrant && virtualScrollWindowMetrics.enabled ? virtualScrollBase : 0 }));
321
- };
322
331
  const visibleScrollableRows = React.useMemo(() => getVisibleScrollableRowRange({
323
332
  scrollTop,
324
333
  viewportHeight: scrollableBodyHeight,
@@ -455,14 +464,9 @@ function Table(props) {
455
464
  storeRowKey,
456
465
  storeSourceIndexByVisibleIndex,
457
466
  ]);
458
- const scrollableColumnsWidth = React.useMemo(() => columns.slice(props.frozenColumnIndex ?? 0).reduce((totalWidth, column) => totalWidth + (column.width ?? 100), 0), [columns, props.frozenColumnIndex]);
459
- const stickyTopHeight = headerHeight + (summary?.position === 'top' ? summaryHeight : 0);
460
- const stickyBottomHeight = summary?.position === 'bottom' ? summaryHeight : 0;
461
- const stickyFixedHeight = stickyTopHeight + stickyBottomHeight;
462
467
  const scrollViewportHeight = contentBodyHeight + stickyFixedHeight;
463
468
  const physicalScrollableRowsHeight = Math.max(virtualScrollWindowMetrics.physicalContentHeight - frozenRowsHeight, 0);
464
469
  const scrollPlaneHeight = stickyFixedHeight + virtualScrollWindowMetrics.physicalContentHeight;
465
- const scrollPlaneContentWidth = (frozenColumnsWidth ?? 0) + scrollableColumnsWidth;
466
470
  const scrollPlaneWidth = Math.max(width, scrollPlaneContentWidth);
467
471
  const customVerticalScrollbarGutter = scrollbar.vertical.visible && scrollbar.variant === 'classic'
468
472
  ? 'var(--bgrid-scrollbar-classic-gutter-size)'
@@ -471,8 +475,9 @@ function Table(props) {
471
475
  : undefined;
472
476
  const scrollPlaneMinWidth = customVerticalScrollbarGutter
473
477
  ? `max(100%, calc(${scrollPlaneContentWidth}px + ${customVerticalScrollbarGutter}))`
474
- : scrollPlaneWidth;
475
- const measuredScrollbarMetrics = useScrollbarMetrics(scrollContainerRef, [data.length, itemHeight, itemPadding, contentBodyHeight, width], scrollPlaneContentWidth, stickyFixedHeight);
478
+ : scrollbar.variant === 'native'
479
+ ? `max(100%, ${scrollPlaneContentWidth}px)`
480
+ : scrollPlaneWidth;
476
481
  const scrollbarMetrics = React.useMemo(() => virtualScrollWindowMetrics.enabled
477
482
  ? {
478
483
  ...measuredScrollbarMetrics,
@@ -491,6 +496,25 @@ function Table(props) {
491
496
  right: (frozenColumnsWidth ?? 0) + measuredVerticalScrollbarGutter,
492
497
  bottom: stickyFixedHeight + frozenRowsHeight,
493
498
  };
499
+ const verticalScrollbarGutterWidth = scrollbar.vertical.visible && scrollbar.variant === 'classic'
500
+ ? 25
501
+ : scrollbar.vertical.visible && scrollbar.variant === 'modern'
502
+ ? 24
503
+ : 0;
504
+ const horizontalViewportSize = scrollbarMetrics.horizontal.viewportSize > 0
505
+ ? scrollbarMetrics.horizontal.viewportSize
506
+ : Math.max(width - containerBorderWidth * 2, 0);
507
+ const mainViewportWidth = Math.max(horizontalViewportSize - (frozenColumnsWidth ?? 0) - verticalScrollbarGutterWidth, 0);
508
+ const renderSelectionOverlay = (quadrant) => {
509
+ const topQuadrant = quadrant === 'top-left' || quadrant === 'top-main';
510
+ const leftQuadrant = quadrant === 'top-left' || quadrant === 'body-left';
511
+ return (React.createElement(CellSelectionOverlay, { quadrant: quadrant, selectionFragments: selectionFragments, activeFragments: activeFragments, activeFill: activeOverlayFill, activeRing: activeOverlayRing, viewport: {
512
+ left: leftQuadrant ? 0 : scrollLeft,
513
+ top: topQuadrant ? 0 : scrollTop,
514
+ width: leftQuadrant ? frozenColumnsWidth ?? 0 : mainViewportWidth,
515
+ height: topQuadrant ? frozenRowsHeight : scrollableBodyHeight,
516
+ }, offsetTop: !topQuadrant && virtualScrollWindowMetrics.enabled ? virtualScrollBase : 0 }));
517
+ };
494
518
  const showBottomBar = shouldRenderBottomBar({
495
519
  hasPage: !!page,
496
520
  hasHorizontalOverflow: scrollbarMetrics.horizontal.hasOverflow,
@@ -707,6 +731,8 @@ function Table(props) {
707
731
  return;
708
732
  hoveredRowIndexesRef.current.forEach(hoveredIndex => {
709
733
  containerRef.current?.querySelectorAll(`tr[data-ri="${hoveredIndex}"]`).forEach(el => {
734
+ if (el.closest('[role="grid"], [role="treegrid"]') !== containerRef.current)
735
+ return;
710
736
  el.classList.remove('bgrid-row-hover');
711
737
  });
712
738
  });
@@ -722,6 +748,8 @@ function Table(props) {
722
748
  clearHoveredRow();
723
749
  rowIndexes.forEach(rowIndex => {
724
750
  containerRef.current?.querySelectorAll(`tr[data-ri="${rowIndex}"]`).forEach(el => {
751
+ if (el.closest('[role="grid"], [role="treegrid"]') !== containerRef.current)
752
+ return;
725
753
  el.classList.add('bgrid-row-hover');
726
754
  });
727
755
  });
@@ -755,15 +783,25 @@ function Table(props) {
755
783
  clearHoveredRow();
756
784
  return;
757
785
  }
758
- const target = evt.target;
786
+ const target = evt.target instanceof HTMLElement ? evt.target : null;
787
+ const detailOwner = target?.closest('[data-bgrid-detail-owner]');
788
+ if (detailOwner && containerRef.current?.contains(detailOwner)) {
789
+ clearHoveredRow();
790
+ return;
791
+ }
759
792
  updateAxisSelectionByTarget(target);
760
793
  const physicalCellPosition = getCellPosition(target, containerRef.current);
761
794
  const cellPosition = physicalCellPosition ? toLogicalCellPosition(physicalCellPosition) : undefined;
762
795
  if (cellSelectionEnabled && cellSelectionDragRef.current && cellPosition) {
763
796
  setCellSelectionRanges(updateSelectionDragRange(cellSelectionDragRef.current, getRangeFromDrag(cellSelectionDragRef.current, cellPosition)));
764
797
  }
798
+ const targetGrid = target?.closest('[role="grid"], [role="treegrid"]');
799
+ if (targetGrid && targetGrid !== containerRef.current && containerRef.current?.contains(targetGrid)) {
800
+ clearHoveredRow();
801
+ return;
802
+ }
765
803
  const tr = target?.closest('tr[data-ri]');
766
- if (!tr || !containerRef.current?.contains(tr)) {
804
+ if (!tr || tr.closest('[role="grid"], [role="treegrid"]') !== containerRef.current) {
767
805
  clearHoveredRow();
768
806
  return;
769
807
  }
@@ -788,6 +826,13 @@ function Table(props) {
788
826
  const onBodyPointerDownCapture = useCallback((evt) => {
789
827
  if (disabled)
790
828
  return;
829
+ const target = evt.target instanceof Element ? evt.target : null;
830
+ const detailOwner = target?.closest('[data-bgrid-detail-owner]');
831
+ if (detailOwner && containerRef.current?.contains(detailOwner))
832
+ return;
833
+ const targetGrid = target?.closest('[role="grid"], [role="treegrid"]');
834
+ if (targetGrid && targetGrid !== containerRef.current && containerRef.current?.contains(targetGrid))
835
+ return;
791
836
  const navEnabled = cellNavigationOptions?.enabled ?? true;
792
837
  if (!cellSelectionEnabled && !navEnabled)
793
838
  return;
@@ -1314,6 +1359,8 @@ function Table(props) {
1314
1359
  setFooterHeight(props.footerHeight);
1315
1360
  if (props.summaryHeight !== undefined)
1316
1361
  setSummaryHeight(props.summaryHeight);
1362
+ if (props.summaryRowHeight !== undefined)
1363
+ setSummaryRowHeight(props.summaryRowHeight);
1317
1364
  if (props.itemHeight !== undefined)
1318
1365
  setItemHeight(props.itemHeight);
1319
1366
  if (props.itemPadding !== undefined)
@@ -1323,12 +1370,14 @@ function Table(props) {
1323
1370
  props.headerHeight,
1324
1371
  props.footerHeight,
1325
1372
  props.summaryHeight,
1373
+ props.summaryRowHeight,
1326
1374
  props.itemHeight,
1327
1375
  props.itemPadding,
1328
1376
  setWidth,
1329
1377
  setHeaderHeight,
1330
1378
  setFooterHeight,
1331
1379
  setSummaryHeight,
1380
+ setSummaryRowHeight,
1332
1381
  setItemHeight,
1333
1382
  setItemPadding,
1334
1383
  ]);
@@ -1895,6 +1944,19 @@ function Table(props) {
1895
1944
  const activeElement = document.activeElement;
1896
1945
  if (!container || (activeElement !== container && !container.contains(activeElement)))
1897
1946
  return;
1947
+ const target = evt.target instanceof Element ? evt.target : null;
1948
+ const detailOwner = target?.closest('[data-bgrid-detail-owner]');
1949
+ if (detailOwner && container.contains(detailOwner))
1950
+ return;
1951
+ const activeDetailOwner = activeElement instanceof Element ? activeElement.closest('[data-bgrid-detail-owner]') : null;
1952
+ if (activeDetailOwner && container.contains(activeDetailOwner))
1953
+ return;
1954
+ const targetGrid = target?.closest('[role="grid"], [role="treegrid"]');
1955
+ if (targetGrid && targetGrid !== container && container.contains(targetGrid))
1956
+ return;
1957
+ const activeGrid = activeElement instanceof Element ? activeElement.closest('[role="grid"], [role="treegrid"]') : null;
1958
+ if (activeGrid && activeGrid !== container && container.contains(activeGrid))
1959
+ return;
1898
1960
  if (disabled) {
1899
1961
  stopArrowRepeat();
1900
1962
  return;
@@ -1908,7 +1970,7 @@ function Table(props) {
1908
1970
  evt.stopPropagation();
1909
1971
  requestSearchOpen(true, 'shortcut');
1910
1972
  setTimeout(() => {
1911
- const input = container.querySelector('.bgrid-search-input');
1973
+ const input = Array.from(container.querySelectorAll('.bgrid-search-input')).find(el => el.closest('[role="grid"], [role="treegrid"]') === container);
1912
1974
  input?.focus({ preventScroll: true });
1913
1975
  input?.select();
1914
1976
  }, searchOpen ? 0 : 1);
@@ -1919,7 +1981,7 @@ function Table(props) {
1919
1981
  return;
1920
1982
  const isShift = evt.shiftKey;
1921
1983
  if (!cellInteractionSession && activeCell && (evt.key === 'ContextMenu' || (isShift && evt.key === 'F10'))) {
1922
- const targetCell = container.querySelector(`td[data-bgrid-cell="true"][data-row-index="${activeCell.rowIndex}"][data-column-index="${activeCell.columnIndex}"]`);
1984
+ const targetCell = Array.from(container.querySelectorAll(`td[data-bgrid-cell="true"][data-row-index="${activeCell.rowIndex}"][data-column-index="${activeCell.columnIndex}"]`)).find(el => el.closest('[role="grid"], [role="treegrid"]') === container);
1923
1985
  const rect = targetCell?.getBoundingClientRect();
1924
1986
  if (rect && openCellContextMenu(activeCell, rect.left + 8, rect.top + Math.min(rect.height, 20), true)) {
1925
1987
  evt.preventDefault();
@@ -2121,6 +2183,19 @@ function Table(props) {
2121
2183
  const activeElement = document.activeElement;
2122
2184
  if (!container || (activeElement !== container && !container.contains(activeElement)))
2123
2185
  return;
2186
+ const target = evt.target instanceof Element ? evt.target : null;
2187
+ const detailOwner = target?.closest('[data-bgrid-detail-owner]');
2188
+ if (detailOwner && container.contains(detailOwner))
2189
+ return;
2190
+ const activeDetailOwner = activeElement instanceof Element ? activeElement.closest('[data-bgrid-detail-owner]') : null;
2191
+ if (activeDetailOwner && container.contains(activeDetailOwner))
2192
+ return;
2193
+ const targetGrid = target?.closest('[role="grid"], [role="treegrid"]');
2194
+ if (targetGrid && targetGrid !== container && container.contains(targetGrid))
2195
+ return;
2196
+ const activeGrid = activeElement instanceof Element ? activeElement.closest('[role="grid"], [role="treegrid"]') : null;
2197
+ if (activeGrid && activeGrid !== container && container.contains(activeGrid))
2198
+ return;
2124
2199
  if (keyboardRuntimeRef.current.disabled)
2125
2200
  return;
2126
2201
  if (isInteractiveTarget(evt.target))
@@ -2133,6 +2208,19 @@ function Table(props) {
2133
2208
  const activeElement = document.activeElement;
2134
2209
  if (!container || (activeElement !== container && !container.contains(activeElement)))
2135
2210
  return;
2211
+ const target = evt.target instanceof Element ? evt.target : null;
2212
+ const detailOwner = target?.closest('[data-bgrid-detail-owner]');
2213
+ if (detailOwner && container.contains(detailOwner))
2214
+ return;
2215
+ const activeDetailOwner = activeElement instanceof Element ? activeElement.closest('[data-bgrid-detail-owner]') : null;
2216
+ if (activeDetailOwner && container.contains(activeDetailOwner))
2217
+ return;
2218
+ const targetGrid = target?.closest('[role="grid"], [role="treegrid"]');
2219
+ if (targetGrid && targetGrid !== container && container.contains(targetGrid))
2220
+ return;
2221
+ const activeGrid = activeElement instanceof Element ? activeElement.closest('[role="grid"], [role="treegrid"]') : null;
2222
+ if (activeGrid && activeGrid !== container && container.contains(activeGrid))
2223
+ return;
2136
2224
  if (keyboardRuntimeRef.current.disabled)
2137
2225
  return;
2138
2226
  if (keyboardRuntimeRef.current.editItemIndex !== undefined && keyboardRuntimeRef.current.editItemIndex >= 0) {
@@ -2151,13 +2239,23 @@ function Table(props) {
2151
2239
  }
2152
2240
  };
2153
2241
  const handlePointerDown = (evt) => {
2242
+ const container = containerRef.current;
2243
+ const target = evt.target;
2244
+ if (!container)
2245
+ return;
2246
+ const detailOwner = target instanceof Element ? target.closest('[data-bgrid-detail-owner]') : null;
2247
+ const targetGrid = target instanceof Element ? target.closest('[role="grid"], [role="treegrid"]') : null;
2248
+ if ((detailOwner && container.contains(detailOwner)) ||
2249
+ (targetGrid && targetGrid !== container && container.contains(targetGrid))) {
2250
+ const { clearCellSelection, endCellSelectionDrag } = keyboardRuntimeRef.current;
2251
+ endCellSelectionDrag();
2252
+ clearCellSelection();
2253
+ return;
2254
+ }
2154
2255
  const { clearCellSelection, clearCellSelectionOnOutsideClick, endCellSelectionDrag } = keyboardRuntimeRef.current;
2155
2256
  if (!clearCellSelectionOnOutsideClick)
2156
2257
  return;
2157
- const container = containerRef.current;
2158
- const target = evt.target;
2159
- if (!container ||
2160
- (target instanceof Node && container.contains(target)) ||
2258
+ if ((target instanceof Node && container.contains(target)) ||
2161
2259
  isPointInsideElement(container, evt.clientX, evt.clientY)) {
2162
2260
  return;
2163
2261
  }
@@ -2192,7 +2290,7 @@ function Table(props) {
2192
2290
  }, className: className, tabIndex: 0, "aria-disabled": disabled ? 'true' : undefined, onFocus: event => {
2193
2291
  if (event.target !== event.currentTarget)
2194
2292
  return;
2195
- const gateway = event.currentTarget.querySelector('[data-bgrid-text-editor-gateway="true"]');
2293
+ const gateway = Array.from(event.currentTarget.querySelectorAll('[data-bgrid-text-editor-gateway="true"]')).find(el => el.closest('[role="grid"], [role="treegrid"]') === event.currentTarget);
2196
2294
  if (gateway instanceof HTMLInputElement) {
2197
2295
  gateway.focus({ preventScroll: true });
2198
2296
  }
@@ -2206,9 +2304,16 @@ function Table(props) {
2206
2304
  React.createElement(ScrollContainer, { ref: scrollContainerRef, role: 'rfdg-scroll-container', "data-bgrid-scroll-plane": 'sticky', style: { height: scrollViewportHeight }, onPointerDownCapture: onBodyPointerDownCapture, onPointerOverCapture: onBodyPointerOverCapture, onPointerLeave: onBodyPointerLeave, onContextMenuCapture: event => {
2207
2305
  if (disabled)
2208
2306
  return;
2307
+ const target = event.target instanceof HTMLElement ? event.target : null;
2308
+ const detailOwner = target?.closest('[data-bgrid-detail-owner]');
2309
+ if (detailOwner && containerRef.current?.contains(detailOwner))
2310
+ return;
2311
+ const targetGrid = target?.closest('[role="grid"], [role="treegrid"]');
2312
+ if (targetGrid && targetGrid !== containerRef.current && containerRef.current?.contains(targetGrid))
2313
+ return;
2209
2314
  if (isInteractiveTarget(event.target))
2210
2315
  return;
2211
- const cell = getCellPosition(event.target, containerRef.current);
2316
+ const cell = getCellPosition(target, containerRef.current);
2212
2317
  if (!cell)
2213
2318
  return;
2214
2319
  if (openCellContextMenu(cell, event.clientX, event.clientY, false)) {
@@ -2229,8 +2334,8 @@ function Table(props) {
2229
2334
  React.createElement(TableSummary, { position: 'top' })))),
2230
2335
  React.createElement("div", { className: 'bgrid-virtual-row-backdrop', "aria-hidden": 'true', style: {
2231
2336
  top: stickyTopHeight,
2232
- height: contentBodyHeight,
2233
- marginBottom: -contentBodyHeight,
2337
+ height: effectiveBodyHeight,
2338
+ marginBottom: -effectiveBodyHeight,
2234
2339
  } }),
2235
2340
  React.createElement("div", { className: 'bgrid-body-scroll-content', style: { height: virtualScrollWindowMetrics.physicalContentHeight } },
2236
2341
  frozenRowCount > 0 && (React.createElement("div", { className: 'bgrid-frozen-rows-layer', style: { height: frozenRowsHeight, top: stickyTopHeight }, "data-bgrid-row-band": 'frozen' },
@@ -2238,7 +2343,7 @@ function Table(props) {
2238
2343
  React.createElement(TableBodyFrozen, { rowKeyRegistry: rowKeyRegistry, rowHeightMetrics: rowHeightMetrics, scrollContainerRef: scrollContainerRef, rowRange: frozenRowRange, role: 'rfdg-body-top-frozen', quadrant: 'top-left', allowRowReorder: false }),
2239
2344
  renderSelectionOverlay('top-left'))),
2240
2345
  React.createElement("div", { className: 'bgrid-frozen-rows-main', style: { left: frozenColumnsWidth }, role: 'rfdg-frozen-rows-main' },
2241
- React.createElement(TableBody, { rowKeyRegistry: rowKeyRegistry, rowHeightMetrics: rowHeightMetrics, scrollContainerRef: scrollContainerRef, rowRange: frozenRowRange, role: 'rfdg-body-top', quadrant: 'top-main', allowRowReorder: false }),
2346
+ React.createElement(TableBody, { rowKeyRegistry: rowKeyRegistry, rowHeightMetrics: rowHeightMetrics, scrollContainerRef: scrollContainerRef, rowRange: frozenRowRange, role: 'rfdg-body-top', quadrant: 'top-main', allowRowReorder: false, viewportWidth: mainViewportWidth }),
2242
2347
  renderSelectionOverlay('top-main')))),
2243
2348
  React.createElement("div", { className: 'bgrid-scrollable-rows-layer', style: { height: physicalScrollableRowsHeight }, "data-bgrid-row-band": 'scrollable' },
2244
2349
  (frozenColumnsWidth ?? 0) > 0 && (React.createElement(FrozenScrollContent, { style: {
@@ -2254,7 +2359,7 @@ function Table(props) {
2254
2359
  : visibleScrollableRows.paddingTop,
2255
2360
  height: physicalScrollableRowsHeight,
2256
2361
  } },
2257
- React.createElement(TableBody, { rowKeyRegistry: rowKeyRegistry, rowHeightMetrics: rowHeightMetrics, scrollContainerRef: scrollContainerRef, rowRange: scrollableRowRange, quadrant: 'body-main' }),
2362
+ React.createElement(TableBody, { rowKeyRegistry: rowKeyRegistry, rowHeightMetrics: rowHeightMetrics, scrollContainerRef: scrollContainerRef, rowRange: scrollableRowRange, quadrant: 'body-main', viewportWidth: mainViewportWidth }),
2258
2363
  renderSelectionOverlay('body-main')))),
2259
2364
  summary && summary.position === 'bottom' && (React.createElement(SummaryContainer, { position: 'bottom', style: { height: summaryHeight, bottom: 0 }, role: 'rfdg-summary-container' },
2260
2365
  (frozenColumnsWidth ?? 0) > 0 && (React.createElement(FrozenSummary, { style: { width: frozenColumnsWidth }, role: 'rfdg-frozen-summary' },
@@ -2275,18 +2380,20 @@ function Table(props) {
2275
2380
  React.createElement(Loading, { active: loading }))));
2276
2381
  }
2277
2382
  function getAxisSelectionTarget(target, container) {
2278
- if (!target || !container)
2383
+ if (!target || !container || !(target instanceof Element))
2279
2384
  return undefined;
2280
2385
  const lineNumberCell = target.closest('.bgrid-line-number-cell[data-row-index]');
2281
- if (lineNumberCell instanceof HTMLElement && container.contains(lineNumberCell)) {
2386
+ if (lineNumberCell instanceof HTMLElement && lineNumberCell.closest('[role="grid"], [role="treegrid"]') === container) {
2282
2387
  const rowIndex = Number(lineNumberCell.dataset.rowIndex);
2283
2388
  if (Number.isFinite(rowIndex)) {
2284
2389
  return { axis: 'row', startIndex: rowIndex, endIndex: rowIndex };
2285
2390
  }
2286
2391
  }
2287
2392
  const headerCell = target.closest('[data-header-cell-type][data-column-index][data-bgrid-axis-selectable="true"]');
2288
- if (!(headerCell instanceof HTMLTableCellElement) || !container.contains(headerCell))
2393
+ if (!(headerCell instanceof HTMLTableCellElement) ||
2394
+ headerCell.closest('[role="grid"], [role="treegrid"]') !== container) {
2289
2395
  return undefined;
2396
+ }
2290
2397
  if (target.closest('.bgrid-col-resizer, .bgrid-toolbox-trigger-btn'))
2291
2398
  return undefined;
2292
2399
  if (headerCell.classList.contains('drag-item') && target.closest('.bgrid-column-drag-handle'))
@@ -2323,8 +2430,10 @@ function updateAxisSelectionDragRange(dragState, activeRange) {
2323
2430
  return nextRanges;
2324
2431
  }
2325
2432
  function getCellPosition(target, container) {
2326
- const cell = target?.closest('td[data-bgrid-cell="true"]');
2327
- if (!(cell instanceof HTMLElement) || !container?.contains(cell))
2433
+ if (!target || !(target instanceof Element))
2434
+ return undefined;
2435
+ const cell = target.closest('td[data-bgrid-cell="true"]');
2436
+ if (!(cell instanceof HTMLElement) || cell.closest('[role="grid"], [role="treegrid"]') !== container)
2328
2437
  return undefined;
2329
2438
  const rowIndex = Number(cell.dataset.rowIndex);
2330
2439
  const columnIndex = Number(cell.dataset.columnIndex);
@@ -5,6 +5,7 @@ import TableColGroup from './TableColGroup';
5
5
  import TableColGroupFrozen from './TableColGroupFrozen';
6
6
  import { getCellValueByRowKey, getRowReorderOffset, getRowReorderRole, useBodyData, } from '../utils';
7
7
  import { TableBodyRow } from './TableBodyRow';
8
+ import { MasterDetailRow } from './MasterDetailCell';
8
9
  import { BGridDataItemStatus } from '../types';
9
10
  export function getVisibleColumnRange(columns, firstScrollableColumnIndex, scrollLeft, viewportWidth) {
10
11
  const lastColumnIndex = columns.length - 1;
@@ -102,7 +103,7 @@ function getRowReactKey(item, sourceIndex, rowKey, registry) {
102
103
  }
103
104
  return `bgrid-row-source:${sourceIndex}`;
104
105
  }
105
- function TableBody({ rowKeyRegistry, region = 'main', rowRange, style, role, quadrant, allowRowReorder = true, onRowReorderPointerDown, onRowReorderKeyDown, rowHeightMetrics, }) {
106
+ function TableBody({ rowKeyRegistry, region = 'main', rowRange, style, role, quadrant, allowRowReorder = true, onRowReorderPointerDown, onRowReorderKeyDown, rowHeightMetrics, viewportWidth, }) {
106
107
  const isLeftRegion = region === 'left';
107
108
  // [Selector Group 1] Scroll & Dimensions - 스크롤 및 차원
108
109
  const { scrollTop, scrollLeft, width, frozenColumnsWidth, itemHeight, itemPadding, displayItemCount } = useAppStore(useShallow(s => ({
@@ -225,7 +226,10 @@ function TableBody({ rowKeyRegistry, region = 'main', rowRange, style, role, qua
225
226
  const isRowEditing = cellInteractionSession?.kind === 'editor' &&
226
227
  (cellInteractionSession.cell.rowIndex === ri || cellInteractionSession.hostCell.rowIndex === ri);
227
228
  const rowReactKey = getRowReactKey(item, sourceIndex, rowKey, rowKeyRegistry);
228
- return (React.createElement(TableBodyRow, { key: rowReactKey, item: item, data: data, ri: ri, sourceIndex: sourceIndex, columns: columns, startCIdx: startCIdx, endCIdx: endCIdx, frozenColumnIndex: frozenColumnIndex, isLeftRegion: isLeftRegion, showLineNumber: showLineNumber ?? false, hasRowChecked: hasRowChecked, isRadio: Boolean(isRadio), checked: checkedAll === true || checkedIndexesMap.get(sourceIndex), rowCheckedDisabled: Boolean(disabled || rowChecked?.disabled?.(sourceIndex, item)), rowStatus: rowStatus, active: active, className: className, resolvedRowHeight: resolvedRowHeight, itemHeight: itemHeight, itemPadding: itemPadding, editable: Boolean(editable), disabled: Boolean(disabled), editTrigger: editTrigger, hasOnClick: hasOnClick, cellMergeOptions: cellMergeOptions, mergeColumns: mergeColumns, odd: !mergeColumns ? ri % 2 === 0 : undefined, variant: variant, rowReorderEnabled: rowReorderEnabled, rowReorderRole: rowReorderRole, rowReorderPhase: reorderingInfo?.phase, rowReorderDirection: rowReorderDirection, rowReorderOffset: rowReorderOffset, reorder: reorder, reorderingInfo: reorderingInfo, searchMatchTokens: searchMatchTokens, currentSearchToken: currentSearchToken, isRowEditing: isRowEditing, cellInteractionSession: isRowEditing ? cellInteractionSession : undefined, handleClick: handleClick, setEditItem: setEditItem, setItemValue: setItemValue, handleMoveEditFocus: handleMoveEditFocus, handleChangeChecked: handleChangeChecked, handleChangeCheckedRadio: handleChangeCheckedRadio, getRowSpan: getRowSpan, onRowReorderPointerDown: onRowReorderPointerDown, onRowReorderKeyDown: onRowReorderKeyDown }));
229
+ const detailHeight = rowHeightMetrics?.detailHeights?.[ri] ?? 0;
230
+ return (React.createElement(React.Fragment, { key: rowReactKey },
231
+ React.createElement(TableBodyRow, { item: item, data: data, ri: ri, sourceIndex: sourceIndex, columns: columns, startCIdx: startCIdx, endCIdx: endCIdx, frozenColumnIndex: frozenColumnIndex, isLeftRegion: isLeftRegion, showLineNumber: showLineNumber ?? false, hasRowChecked: hasRowChecked, isRadio: Boolean(isRadio), checked: checkedAll === true || checkedIndexesMap.get(sourceIndex), rowCheckedDisabled: Boolean(disabled || rowChecked?.disabled?.(sourceIndex, item)), rowStatus: rowStatus, active: active, className: className, resolvedRowHeight: resolvedRowHeight, itemHeight: itemHeight, itemPadding: itemPadding, editable: Boolean(editable), disabled: Boolean(disabled), editTrigger: editTrigger, hasOnClick: hasOnClick, cellMergeOptions: cellMergeOptions, mergeColumns: mergeColumns, odd: !mergeColumns ? ri % 2 === 0 : undefined, variant: variant, rowReorderEnabled: rowReorderEnabled, rowReorderRole: rowReorderRole, rowReorderPhase: reorderingInfo?.phase, rowReorderDirection: rowReorderDirection, rowReorderOffset: rowReorderOffset, reorder: reorder, reorderingInfo: reorderingInfo, searchMatchTokens: searchMatchTokens, currentSearchToken: currentSearchToken, isRowEditing: isRowEditing, cellInteractionSession: isRowEditing ? cellInteractionSession : undefined, handleClick: handleClick, setEditItem: setEditItem, setItemValue: setItemValue, handleMoveEditFocus: handleMoveEditFocus, handleChangeChecked: handleChangeChecked, handleChangeCheckedRadio: handleChangeCheckedRadio, getRowSpan: getRowSpan, onRowReorderPointerDown: onRowReorderPointerDown, onRowReorderKeyDown: onRowReorderKeyDown }),
232
+ detailHeight > 0 && (React.createElement(MasterDetailRow, { item: item, sourceIndex: sourceIndex, visibleIndex: ri, detailHeight: detailHeight, isLeftRegion: isLeftRegion, viewportWidth: viewportWidth ?? Math.max(width - (frozenColumnsWidth ?? 0), 0), frozenColumnsWidth: frozenColumnsWidth ?? 0, colSpan: isLeftRegion ? Math.max(frozenColumnIndex, 1) : Math.max(columns.length - frozenColumnIndex, 1) }))));
229
233
  }),
230
234
  endNumber - startIdx < 1 &&
231
235
  (isLeftRegion ? (React.createElement(NoDataTr, { itemHeight: itemHeight, itemPadding: itemPadding })) : (React.createElement(NoDataTr, { itemHeight: itemHeight, itemPadding: itemPadding }, msg?.emptyList ? (React.createElement(React.Fragment, null,
@@ -3,6 +3,7 @@ import { PluginCellEditor } from './PluginCellEditor';
3
3
  import { CellEditorIcon } from './CellEditorIcon';
4
4
  import { CheckboxCellEditor } from './CheckboxCellEditor';
5
5
  import { TreeCell } from './TreeCell';
6
+ import { MasterDetailCell } from './MasterDetailCell';
6
7
  function Cell({ index, hostIndex = index, columnIndex, column, item, valueByRowKey, handleSave, handleCancel, handleMove, editable, cellEditable, interactionEditing = false, editSession, }) {
7
8
  const isPluginEditorActive = Boolean(editable && editSession && column.editor?.type === 'plugin');
8
9
  let content;
@@ -37,7 +38,7 @@ function Cell({ index, hostIndex = index, columnIndex, column, item, valueByRowK
37
38
  content = renderSafeCellValue(valueByRowKey);
38
39
  }
39
40
  return (React.createElement("div", { className: isPluginEditorActive ? 'bgrid-cell-content bgrid-cell-content-plugin-editor' : 'bgrid-cell-content' },
40
- React.createElement("div", { className: 'bgrid-cell-value' }, column.treeCell ? (React.createElement(TreeCell, { column: column, item: item }, content)) : (content)),
41
+ React.createElement("div", { className: 'bgrid-cell-value' }, column.treeCell ? (React.createElement(TreeCell, { column: column, item: item }, content)) : column.masterDetailCell ? (React.createElement(MasterDetailCell, { column: column, item: item, sourceIndex: index }, content)) : (content)),
41
42
  column.editorIcon && column.editor?.type !== 'checkbox' && cellEditable && (React.createElement(CellEditorIcon, { hostCell: { rowIndex: hostIndex, columnIndex }, index: index, columnIndex: columnIndex, column: column, item: item, value: valueByRowKey, editing: interactionEditing }))));
42
43
  }
43
44
  function renderSafeCellValue(value, preserveRenderableArrays = false) {