@mindlogic-ai/logician-ui 4.0.0-alpha.18 → 4.0.0-alpha.19
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/components/Table/TableContext.d.ts.map +1 -1
- package/dist/components/Table/TableContext.js +27 -21
- package/dist/components/Table/TableContext.js.map +1 -1
- package/dist/components/Table/TableContext.mjs +27 -21
- package/dist/components/Table/TableContext.mjs.map +1 -1
- package/dist/components/Table/Td.d.ts.map +1 -1
- package/dist/components/Table/Td.js +9 -7
- package/dist/components/Table/Td.js.map +1 -1
- package/dist/components/Table/Td.mjs +10 -8
- package/dist/components/Table/Td.mjs.map +1 -1
- package/dist/components/Table/Th.d.ts.map +1 -1
- package/dist/components/Table/Th.js +9 -7
- package/dist/components/Table/Th.js.map +1 -1
- package/dist/components/Table/Th.mjs +10 -8
- package/dist/components/Table/Th.mjs.map +1 -1
- package/dist/components/Table/useRegisterStickyWidth.d.ts +25 -0
- package/dist/components/Table/useRegisterStickyWidth.d.ts.map +1 -0
- package/dist/components/Table/useRegisterStickyWidth.js +37 -0
- package/dist/components/Table/useRegisterStickyWidth.js.map +1 -0
- package/dist/components/Table/useRegisterStickyWidth.mjs +35 -0
- package/dist/components/Table/useRegisterStickyWidth.mjs.map +1 -0
- package/package.json +1 -1
- package/src/components/Table/Table.stories.tsx +253 -0
- package/src/components/Table/TableContext.tsx +30 -24
- package/src/components/Table/Td.tsx +10 -8
- package/src/components/Table/Th.tsx +10 -8
- package/src/components/Table/useRegisterStickyWidth.ts +45 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TableContext.d.ts","sourceRoot":"","sources":["../../../src/components/Table/TableContext.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAEZ,SAAS,EAMV,MAAM,OAAO,CAAC;AAEf,MAAM,WAAW,gBAAgB;IAC/B,aAAa,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;CACtB;
|
|
1
|
+
{"version":3,"file":"TableContext.d.ts","sourceRoot":"","sources":["../../../src/components/Table/TableContext.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAEZ,SAAS,EAMV,MAAM,OAAO,CAAC;AAEf,MAAM,WAAW,gBAAgB;IAC/B,aAAa,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;CACtB;AASD,UAAU,iBAAkB,SAAQ,gBAAgB;IAClD,eAAe,EAAE,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI,KAAK,IAAI,CAAC;IACvD,oBAAoB,EAAE,CACpB,SAAS,EAAE,MAAM,GAAG,OAAO,EAC3B,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,KACV,IAAI,CAAC;IACV,eAAe,EAAE,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACxE,kBAAkB,EAAE,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;CAC7E;AAID,eAAO,MAAM,eAAe,yBAM3B,CAAC;AAEF,UAAU,kBAAkB;IAC1B,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAgJtD,CAAC"}
|
|
@@ -19,9 +19,15 @@ const TableProvider = ({ children }) => {
|
|
|
19
19
|
isScrollEnd: false,
|
|
20
20
|
isScrolling: false,
|
|
21
21
|
});
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
// Column widths live in state (not a ref) so that a width change — a font
|
|
23
|
+
// swap, a window/sidebar resize, or the columns re-flowing when the table
|
|
24
|
+
// goes from fitting to overflowing — triggers a re-render and the sticky
|
|
25
|
+
// offsets are recomputed. Storing them in a ref (the previous approach) meant
|
|
26
|
+
// the offsets were computed once at mount and then went stale, detaching the
|
|
27
|
+
// sticky columns from their real positions.
|
|
28
|
+
const [stickyColumns, setStickyColumns] = React.useState({
|
|
29
|
+
left: {},
|
|
30
|
+
right: {},
|
|
25
31
|
});
|
|
26
32
|
// 스크롤 상태 업데이트
|
|
27
33
|
const updateScrollState = React.useCallback(() => {
|
|
@@ -52,41 +58,41 @@ const TableProvider = ({ children }) => {
|
|
|
52
58
|
updateScrollState();
|
|
53
59
|
}
|
|
54
60
|
}, [updateScrollState]);
|
|
55
|
-
// Register a sticky column with its width
|
|
61
|
+
// Register a sticky column with its (measured) width. Rounds to whole pixels
|
|
62
|
+
// and bails when unchanged so the ResizeObserver-driven callers can't
|
|
63
|
+
// ping-pong on sub-pixel differences and spin the render loop.
|
|
56
64
|
const registerStickyColumn = React.useCallback((direction, index, width) => {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
65
|
+
const rounded = Math.round(width);
|
|
66
|
+
setStickyColumns((prev) => {
|
|
67
|
+
const side = prev[direction];
|
|
68
|
+
if (side[index] === rounded)
|
|
69
|
+
return prev;
|
|
70
|
+
return { ...prev, [direction]: { ...side, [index]: rounded } };
|
|
71
|
+
});
|
|
63
72
|
}, []);
|
|
64
73
|
// Get the offset for a sticky column based on its index and direction
|
|
65
74
|
const getStickyOffset = React.useCallback((direction, index) => {
|
|
66
75
|
if (index === 0)
|
|
67
76
|
return 0;
|
|
68
|
-
const
|
|
69
|
-
? stickyColumnsRef.current.leftColumnWidths
|
|
70
|
-
: stickyColumnsRef.current.rightColumnWidths;
|
|
77
|
+
const widths = stickyColumns[direction];
|
|
71
78
|
let offset = 0;
|
|
72
79
|
for (let i = 0; i < index; i++) {
|
|
73
|
-
offset +=
|
|
80
|
+
offset += widths[i] || 0;
|
|
74
81
|
}
|
|
75
82
|
return offset;
|
|
76
|
-
}, []);
|
|
83
|
+
}, [stickyColumns]);
|
|
77
84
|
// Check if a column is the last sticky column on its side
|
|
78
85
|
const isLastStickyColumn = React.useCallback((direction, index) => {
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
: stickyColumnsRef.current.rightColumnWidths;
|
|
82
|
-
// Find the highest index in the map
|
|
86
|
+
const widths = stickyColumns[direction];
|
|
87
|
+
// Find the highest registered index on this side
|
|
83
88
|
let maxIndex = -1;
|
|
84
|
-
for (const
|
|
89
|
+
for (const key of Object.keys(widths)) {
|
|
90
|
+
const idx = Number(key);
|
|
85
91
|
if (idx > maxIndex)
|
|
86
92
|
maxIndex = idx;
|
|
87
93
|
}
|
|
88
94
|
return index === maxIndex;
|
|
89
|
-
}, []);
|
|
95
|
+
}, [stickyColumns]);
|
|
90
96
|
// 단일 useEffect에서 모든 이벤트 리스너 관리
|
|
91
97
|
React.useEffect(() => {
|
|
92
98
|
const container = containerRef.current;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TableContext.js","sources":["../../../src/components/Table/TableContext.tsx"],"sourcesContent":[null],"names":["createContext","useContext","useRef","useState","useCallback","useEffect","_jsx"],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"TableContext.js","sources":["../../../src/components/Table/TableContext.tsx"],"sourcesContent":[null],"names":["createContext","useContext","useRef","useState","useCallback","useEffect","_jsx"],"mappings":"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"}
|
|
@@ -17,9 +17,15 @@ const TableProvider = ({ children }) => {
|
|
|
17
17
|
isScrollEnd: false,
|
|
18
18
|
isScrolling: false,
|
|
19
19
|
});
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
// Column widths live in state (not a ref) so that a width change — a font
|
|
21
|
+
// swap, a window/sidebar resize, or the columns re-flowing when the table
|
|
22
|
+
// goes from fitting to overflowing — triggers a re-render and the sticky
|
|
23
|
+
// offsets are recomputed. Storing them in a ref (the previous approach) meant
|
|
24
|
+
// the offsets were computed once at mount and then went stale, detaching the
|
|
25
|
+
// sticky columns from their real positions.
|
|
26
|
+
const [stickyColumns, setStickyColumns] = useState({
|
|
27
|
+
left: {},
|
|
28
|
+
right: {},
|
|
23
29
|
});
|
|
24
30
|
// 스크롤 상태 업데이트
|
|
25
31
|
const updateScrollState = useCallback(() => {
|
|
@@ -50,41 +56,41 @@ const TableProvider = ({ children }) => {
|
|
|
50
56
|
updateScrollState();
|
|
51
57
|
}
|
|
52
58
|
}, [updateScrollState]);
|
|
53
|
-
// Register a sticky column with its width
|
|
59
|
+
// Register a sticky column with its (measured) width. Rounds to whole pixels
|
|
60
|
+
// and bails when unchanged so the ResizeObserver-driven callers can't
|
|
61
|
+
// ping-pong on sub-pixel differences and spin the render loop.
|
|
54
62
|
const registerStickyColumn = useCallback((direction, index, width) => {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
63
|
+
const rounded = Math.round(width);
|
|
64
|
+
setStickyColumns((prev) => {
|
|
65
|
+
const side = prev[direction];
|
|
66
|
+
if (side[index] === rounded)
|
|
67
|
+
return prev;
|
|
68
|
+
return { ...prev, [direction]: { ...side, [index]: rounded } };
|
|
69
|
+
});
|
|
61
70
|
}, []);
|
|
62
71
|
// Get the offset for a sticky column based on its index and direction
|
|
63
72
|
const getStickyOffset = useCallback((direction, index) => {
|
|
64
73
|
if (index === 0)
|
|
65
74
|
return 0;
|
|
66
|
-
const
|
|
67
|
-
? stickyColumnsRef.current.leftColumnWidths
|
|
68
|
-
: stickyColumnsRef.current.rightColumnWidths;
|
|
75
|
+
const widths = stickyColumns[direction];
|
|
69
76
|
let offset = 0;
|
|
70
77
|
for (let i = 0; i < index; i++) {
|
|
71
|
-
offset +=
|
|
78
|
+
offset += widths[i] || 0;
|
|
72
79
|
}
|
|
73
80
|
return offset;
|
|
74
|
-
}, []);
|
|
81
|
+
}, [stickyColumns]);
|
|
75
82
|
// Check if a column is the last sticky column on its side
|
|
76
83
|
const isLastStickyColumn = useCallback((direction, index) => {
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
: stickyColumnsRef.current.rightColumnWidths;
|
|
80
|
-
// Find the highest index in the map
|
|
84
|
+
const widths = stickyColumns[direction];
|
|
85
|
+
// Find the highest registered index on this side
|
|
81
86
|
let maxIndex = -1;
|
|
82
|
-
for (const
|
|
87
|
+
for (const key of Object.keys(widths)) {
|
|
88
|
+
const idx = Number(key);
|
|
83
89
|
if (idx > maxIndex)
|
|
84
90
|
maxIndex = idx;
|
|
85
91
|
}
|
|
86
92
|
return index === maxIndex;
|
|
87
|
-
}, []);
|
|
93
|
+
}, [stickyColumns]);
|
|
88
94
|
// 단일 useEffect에서 모든 이벤트 리스너 관리
|
|
89
95
|
useEffect(() => {
|
|
90
96
|
const container = containerRef.current;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TableContext.mjs","sources":["../../../src/components/Table/TableContext.tsx"],"sourcesContent":[null],"names":["_jsx"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"TableContext.mjs","sources":["../../../src/components/Table/TableContext.tsx"],"sourcesContent":[null],"names":["_jsx"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Td.d.ts","sourceRoot":"","sources":["../../../src/components/Table/Td.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"Td.d.ts","sourceRoot":"","sources":["../../../src/components/Table/Td.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAI/C,eAAO,MAAM,EAAE;yIAaZ,cAAc,GAAG;QAAE,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE;;CAsHrC,CAAC"}
|
|
@@ -6,6 +6,7 @@ var React = require('react');
|
|
|
6
6
|
var react = require('@chakra-ui/react');
|
|
7
7
|
var Table_styles = require('./Table.styles.js');
|
|
8
8
|
var TableContext = require('./TableContext.js');
|
|
9
|
+
var useRegisterStickyWidth = require('./useRegisterStickyWidth.js');
|
|
9
10
|
|
|
10
11
|
const Td = ({ wrap, isSticky = false, stickyDirection = 'left', stickyIndex = 0, _first, style, className, children, onClick, onMouseEnter, onMouseLeave, ...rest }) => {
|
|
11
12
|
const cellRef = React.useRef(null);
|
|
@@ -53,13 +54,14 @@ const Td = ({ wrap, isSticky = false, stickyDirection = 'left', stickyIndex = 0,
|
|
|
53
54
|
}, ...htmlProps, children: children }));
|
|
54
55
|
}
|
|
55
56
|
const { registerStickyColumn, getStickyOffset, isLastStickyColumn, ...scrollState } = tableContext;
|
|
56
|
-
//
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
57
|
+
// Keep this column's width registered so the cumulative sticky offsets stay
|
|
58
|
+
// correct across layout changes (font swap, resize, fit -> overflow).
|
|
59
|
+
useRegisterStickyWidth.useRegisterStickyWidth(cellRef, {
|
|
60
|
+
isSticky,
|
|
61
|
+
direction: stickyDirection,
|
|
62
|
+
index: stickyIndex,
|
|
63
|
+
register: registerStickyColumn,
|
|
64
|
+
});
|
|
63
65
|
// Get the sticky offset based on the column's position
|
|
64
66
|
const stickyOffset = isSticky
|
|
65
67
|
? getStickyOffset(stickyDirection, stickyIndex)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Td.js","sources":["../../../src/components/Table/Td.tsx"],"sourcesContent":[null],"names":["useRef","useTableContext","useToken","_jsx","
|
|
1
|
+
{"version":3,"file":"Td.js","sources":["../../../src/components/Table/Td.tsx"],"sourcesContent":[null],"names":["useRef","useTableContext","useToken","_jsx","useRegisterStickyWidth","getStickyStyles","Table"],"mappings":"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"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx } from 'react/jsx-runtime';
|
|
3
|
-
import { useRef
|
|
3
|
+
import { useRef } from 'react';
|
|
4
4
|
import { useToken, Table } from '@chakra-ui/react';
|
|
5
5
|
import { getStickyStyles } from './Table.styles.mjs';
|
|
6
6
|
import { useTableContext } from './TableContext.mjs';
|
|
7
|
+
import { useRegisterStickyWidth } from './useRegisterStickyWidth.mjs';
|
|
7
8
|
|
|
8
9
|
const Td = ({ wrap, isSticky = false, stickyDirection = 'left', stickyIndex = 0, _first, style, className, children, onClick, onMouseEnter, onMouseLeave, ...rest }) => {
|
|
9
10
|
const cellRef = useRef(null);
|
|
@@ -51,13 +52,14 @@ const Td = ({ wrap, isSticky = false, stickyDirection = 'left', stickyIndex = 0,
|
|
|
51
52
|
}, ...htmlProps, children: children }));
|
|
52
53
|
}
|
|
53
54
|
const { registerStickyColumn, getStickyOffset, isLastStickyColumn, ...scrollState } = tableContext;
|
|
54
|
-
//
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
55
|
+
// Keep this column's width registered so the cumulative sticky offsets stay
|
|
56
|
+
// correct across layout changes (font swap, resize, fit -> overflow).
|
|
57
|
+
useRegisterStickyWidth(cellRef, {
|
|
58
|
+
isSticky,
|
|
59
|
+
direction: stickyDirection,
|
|
60
|
+
index: stickyIndex,
|
|
61
|
+
register: registerStickyColumn,
|
|
62
|
+
});
|
|
61
63
|
// Get the sticky offset based on the column's position
|
|
62
64
|
const stickyOffset = isSticky
|
|
63
65
|
? getStickyOffset(stickyDirection, stickyIndex)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Td.mjs","sources":["../../../src/components/Table/Td.tsx"],"sourcesContent":[null],"names":["_jsx"],"mappings":"
|
|
1
|
+
{"version":3,"file":"Td.mjs","sources":["../../../src/components/Table/Td.tsx"],"sourcesContent":[null],"names":["_jsx"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Th.d.ts","sourceRoot":"","sources":["../../../src/components/Table/Th.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAY,MAAM,kBAAkB,CAAC;AAGnD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"Th.d.ts","sourceRoot":"","sources":["../../../src/components/Table/Th.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAY,MAAM,kBAAkB,CAAC;AAGnD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAI/C,eAAO,MAAM,EAAE,2IAkJd,CAAC"}
|
|
@@ -6,6 +6,7 @@ var React = require('react');
|
|
|
6
6
|
var react = require('@chakra-ui/react');
|
|
7
7
|
var Table_styles = require('./Table.styles.js');
|
|
8
8
|
var TableContext = require('./TableContext.js');
|
|
9
|
+
var useRegisterStickyWidth = require('./useRegisterStickyWidth.js');
|
|
9
10
|
|
|
10
11
|
const Th = React.forwardRef(({ isSticky = false, stickyDirection = 'left', stickyIndex = 0, style, className, children, onClick, onMouseEnter, onMouseLeave, ...rest }, forwardedRef) => {
|
|
11
12
|
const tableContext = TableContext.useTableContext();
|
|
@@ -49,13 +50,14 @@ const Th = React.forwardRef(({ isSticky = false, stickyDirection = 'left', stick
|
|
|
49
50
|
}, ...htmlProps, children: children }));
|
|
50
51
|
}
|
|
51
52
|
const { registerStickyColumn, getStickyOffset, isLastStickyColumn, ...scrollState } = tableContext;
|
|
52
|
-
//
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
53
|
+
// Keep this column's width registered so the cumulative sticky offsets stay
|
|
54
|
+
// correct across layout changes (font swap, resize, fit -> overflow).
|
|
55
|
+
useRegisterStickyWidth.useRegisterStickyWidth(measureNodeRef, {
|
|
56
|
+
isSticky,
|
|
57
|
+
direction: stickyDirection,
|
|
58
|
+
index: stickyIndex,
|
|
59
|
+
register: registerStickyColumn,
|
|
60
|
+
});
|
|
59
61
|
// Combine refs (forwarded ref and internal ref)
|
|
60
62
|
const setRefs = React.useCallback((node) => {
|
|
61
63
|
// Set internal ref
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Th.js","sources":["../../../src/components/Table/Th.tsx"],"sourcesContent":[null],"names":["forwardRef","useTableContext","useRef","useToken","useCallback","_jsx","
|
|
1
|
+
{"version":3,"file":"Th.js","sources":["../../../src/components/Table/Th.tsx"],"sourcesContent":[null],"names":["forwardRef","useTableContext","useRef","useToken","useCallback","_jsx","useRegisterStickyWidth","getStickyStyles","Table"],"mappings":"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"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx } from 'react/jsx-runtime';
|
|
3
|
-
import { forwardRef, useRef, useCallback
|
|
3
|
+
import { forwardRef, useRef, useCallback } from 'react';
|
|
4
4
|
import { useToken, Table } from '@chakra-ui/react';
|
|
5
5
|
import { getStickyStyles } from './Table.styles.mjs';
|
|
6
6
|
import { useTableContext } from './TableContext.mjs';
|
|
7
|
+
import { useRegisterStickyWidth } from './useRegisterStickyWidth.mjs';
|
|
7
8
|
|
|
8
9
|
const Th = forwardRef(({ isSticky = false, stickyDirection = 'left', stickyIndex = 0, style, className, children, onClick, onMouseEnter, onMouseLeave, ...rest }, forwardedRef) => {
|
|
9
10
|
const tableContext = useTableContext();
|
|
@@ -47,13 +48,14 @@ const Th = forwardRef(({ isSticky = false, stickyDirection = 'left', stickyIndex
|
|
|
47
48
|
}, ...htmlProps, children: children }));
|
|
48
49
|
}
|
|
49
50
|
const { registerStickyColumn, getStickyOffset, isLastStickyColumn, ...scrollState } = tableContext;
|
|
50
|
-
//
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
51
|
+
// Keep this column's width registered so the cumulative sticky offsets stay
|
|
52
|
+
// correct across layout changes (font swap, resize, fit -> overflow).
|
|
53
|
+
useRegisterStickyWidth(measureNodeRef, {
|
|
54
|
+
isSticky,
|
|
55
|
+
direction: stickyDirection,
|
|
56
|
+
index: stickyIndex,
|
|
57
|
+
register: registerStickyColumn,
|
|
58
|
+
});
|
|
57
59
|
// Combine refs (forwarded ref and internal ref)
|
|
58
60
|
const setRefs = useCallback((node) => {
|
|
59
61
|
// Set internal ref
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Th.mjs","sources":["../../../src/components/Table/Th.tsx"],"sourcesContent":[null],"names":["_jsx"],"mappings":"
|
|
1
|
+
{"version":3,"file":"Th.mjs","sources":["../../../src/components/Table/Th.tsx"],"sourcesContent":[null],"names":["_jsx"],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { RefObject } from 'react';
|
|
2
|
+
import { StickyDirection } from './Table.styles';
|
|
3
|
+
interface UseRegisterStickyWidthOptions {
|
|
4
|
+
isSticky: boolean;
|
|
5
|
+
direction: StickyDirection;
|
|
6
|
+
index: number;
|
|
7
|
+
register: (direction: StickyDirection, index: number, width: number) => void;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Keep a sticky cell's measured width registered with the table context.
|
|
11
|
+
*
|
|
12
|
+
* Unlike a mount-only measurement, this observes the cell with a
|
|
13
|
+
* `ResizeObserver`, so the width stays correct through later layout changes —
|
|
14
|
+
* a web-font swap that reflows the text, a window/sidebar resize, or the
|
|
15
|
+
* columns shrinking when the table goes from fitting its container to
|
|
16
|
+
* overflowing it. Without this, the cumulative sticky offsets are computed once
|
|
17
|
+
* from stale widths and the pinned columns visibly detach (an empty gap opens
|
|
18
|
+
* between them and neighbouring columns collapse).
|
|
19
|
+
*
|
|
20
|
+
* `getBoundingClientRect().width` is read inside the callback so the value is
|
|
21
|
+
* always the border-box width the offset maths expects.
|
|
22
|
+
*/
|
|
23
|
+
export declare function useRegisterStickyWidth(ref: RefObject<HTMLTableCellElement | null>, { isSticky, direction, index, register }: UseRegisterStickyWidthOptions): void;
|
|
24
|
+
export {};
|
|
25
|
+
//# sourceMappingURL=useRegisterStickyWidth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useRegisterStickyWidth.d.ts","sourceRoot":"","sources":["../../../src/components/Table/useRegisterStickyWidth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAa,MAAM,OAAO,CAAC;AAE7C,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjD,UAAU,6BAA6B;IACrC,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,eAAe,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,SAAS,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9E;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,SAAS,CAAC,oBAAoB,GAAG,IAAI,CAAC,EAC3C,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,6BAA6B,QAiBxE"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var React = require('react');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Keep a sticky cell's measured width registered with the table context.
|
|
8
|
+
*
|
|
9
|
+
* Unlike a mount-only measurement, this observes the cell with a
|
|
10
|
+
* `ResizeObserver`, so the width stays correct through later layout changes —
|
|
11
|
+
* a web-font swap that reflows the text, a window/sidebar resize, or the
|
|
12
|
+
* columns shrinking when the table goes from fitting its container to
|
|
13
|
+
* overflowing it. Without this, the cumulative sticky offsets are computed once
|
|
14
|
+
* from stale widths and the pinned columns visibly detach (an empty gap opens
|
|
15
|
+
* between them and neighbouring columns collapse).
|
|
16
|
+
*
|
|
17
|
+
* `getBoundingClientRect().width` is read inside the callback so the value is
|
|
18
|
+
* always the border-box width the offset maths expects.
|
|
19
|
+
*/
|
|
20
|
+
function useRegisterStickyWidth(ref, { isSticky, direction, index, register }) {
|
|
21
|
+
React.useEffect(() => {
|
|
22
|
+
const node = ref.current;
|
|
23
|
+
if (!isSticky || !node)
|
|
24
|
+
return;
|
|
25
|
+
register(direction, index, node.getBoundingClientRect().width);
|
|
26
|
+
if (typeof ResizeObserver === 'undefined')
|
|
27
|
+
return;
|
|
28
|
+
const observer = new ResizeObserver(() => {
|
|
29
|
+
register(direction, index, node.getBoundingClientRect().width);
|
|
30
|
+
});
|
|
31
|
+
observer.observe(node);
|
|
32
|
+
return () => observer.disconnect();
|
|
33
|
+
}, [ref, isSticky, direction, index, register]);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
exports.useRegisterStickyWidth = useRegisterStickyWidth;
|
|
37
|
+
//# sourceMappingURL=useRegisterStickyWidth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useRegisterStickyWidth.js","sources":["../../../src/components/Table/useRegisterStickyWidth.ts"],"sourcesContent":[null],"names":["useEffect"],"mappings":";;;;;AAWA;;;;;;;;;;;;;AAaG;AACG,SAAU,sBAAsB,CACpC,GAA2C,EAC3C,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAiC,EAAA;IAEvEA,eAAS,CAAC,MAAK;AACb,QAAA,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO;AACxB,QAAA,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI;YAAE;AAExB,QAAA,QAAQ,CAAC,SAAS,EAAE,KAAK,EAAE,IAAI,CAAC,qBAAqB,EAAE,CAAC,KAAK,CAAC;QAE9D,IAAI,OAAO,cAAc,KAAK,WAAW;YAAE;AAE3C,QAAA,MAAM,QAAQ,GAAG,IAAI,cAAc,CAAC,MAAK;AACvC,YAAA,QAAQ,CAAC,SAAS,EAAE,KAAK,EAAE,IAAI,CAAC,qBAAqB,EAAE,CAAC,KAAK,CAAC;AAChE,QAAA,CAAC,CAAC;AACF,QAAA,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC;AAEtB,QAAA,OAAO,MAAM,QAAQ,CAAC,UAAU,EAAE;AACpC,IAAA,CAAC,EAAE,CAAC,GAAG,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;AACjD;;;;"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useEffect } from 'react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Keep a sticky cell's measured width registered with the table context.
|
|
6
|
+
*
|
|
7
|
+
* Unlike a mount-only measurement, this observes the cell with a
|
|
8
|
+
* `ResizeObserver`, so the width stays correct through later layout changes —
|
|
9
|
+
* a web-font swap that reflows the text, a window/sidebar resize, or the
|
|
10
|
+
* columns shrinking when the table goes from fitting its container to
|
|
11
|
+
* overflowing it. Without this, the cumulative sticky offsets are computed once
|
|
12
|
+
* from stale widths and the pinned columns visibly detach (an empty gap opens
|
|
13
|
+
* between them and neighbouring columns collapse).
|
|
14
|
+
*
|
|
15
|
+
* `getBoundingClientRect().width` is read inside the callback so the value is
|
|
16
|
+
* always the border-box width the offset maths expects.
|
|
17
|
+
*/
|
|
18
|
+
function useRegisterStickyWidth(ref, { isSticky, direction, index, register }) {
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
const node = ref.current;
|
|
21
|
+
if (!isSticky || !node)
|
|
22
|
+
return;
|
|
23
|
+
register(direction, index, node.getBoundingClientRect().width);
|
|
24
|
+
if (typeof ResizeObserver === 'undefined')
|
|
25
|
+
return;
|
|
26
|
+
const observer = new ResizeObserver(() => {
|
|
27
|
+
register(direction, index, node.getBoundingClientRect().width);
|
|
28
|
+
});
|
|
29
|
+
observer.observe(node);
|
|
30
|
+
return () => observer.disconnect();
|
|
31
|
+
}, [ref, isSticky, direction, index, register]);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export { useRegisterStickyWidth };
|
|
35
|
+
//# sourceMappingURL=useRegisterStickyWidth.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useRegisterStickyWidth.mjs","sources":["../../../src/components/Table/useRegisterStickyWidth.ts"],"sourcesContent":[null],"names":[],"mappings":";;;AAWA;;;;;;;;;;;;;AAaG;AACG,SAAU,sBAAsB,CACpC,GAA2C,EAC3C,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAiC,EAAA;IAEvE,SAAS,CAAC,MAAK;AACb,QAAA,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO;AACxB,QAAA,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI;YAAE;AAExB,QAAA,QAAQ,CAAC,SAAS,EAAE,KAAK,EAAE,IAAI,CAAC,qBAAqB,EAAE,CAAC,KAAK,CAAC;QAE9D,IAAI,OAAO,cAAc,KAAK,WAAW;YAAE;AAE3C,QAAA,MAAM,QAAQ,GAAG,IAAI,cAAc,CAAC,MAAK;AACvC,YAAA,QAAQ,CAAC,SAAS,EAAE,KAAK,EAAE,IAAI,CAAC,qBAAqB,EAAE,CAAC,KAAK,CAAC;AAChE,QAAA,CAAC,CAAC;AACF,QAAA,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC;AAEtB,QAAA,OAAO,MAAM,QAAQ,CAAC,UAAU,EAAE;AACpC,IAAA,CAAC,EAAE,CAAC,GAAG,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;AACjD;;;;"}
|
package/package.json
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
Thead,
|
|
13
13
|
Tr,
|
|
14
14
|
} from '.';
|
|
15
|
+
import { Button } from '../Button';
|
|
15
16
|
import { IoChevronDownOutline } from '../Icon';
|
|
16
17
|
import { IconButton } from '../IconButton';
|
|
17
18
|
|
|
@@ -430,3 +431,255 @@ export const WithTwoLeftStickyColumns: Story = {
|
|
|
430
431
|
args: { width: '180%' },
|
|
431
432
|
argTypes: {},
|
|
432
433
|
};
|
|
434
|
+
|
|
435
|
+
// Three consecutive left-pinned columns + one right-pinned column — the shape of
|
|
436
|
+
// the admin 챗봇 공개 관리 / 전체 멤버 tables (checkbox · name · status pinned
|
|
437
|
+
// left, an action column pinned right, many trailing columns scrolling between).
|
|
438
|
+
const adminColumns: { key: string; label: string }[] = [
|
|
439
|
+
{ key: 'check', label: '' },
|
|
440
|
+
{ key: 'name', label: '이름' },
|
|
441
|
+
{ key: 'status', label: '상태' },
|
|
442
|
+
{ key: 'email', label: '이메일' },
|
|
443
|
+
{ key: 'phone', label: '전화번호' },
|
|
444
|
+
{ key: 'address', label: '주소' },
|
|
445
|
+
{ key: 'company', label: '회사' },
|
|
446
|
+
{ key: 'department', label: '부서' },
|
|
447
|
+
{ key: 'action', label: '' },
|
|
448
|
+
];
|
|
449
|
+
|
|
450
|
+
const LEFT_STICKY = new Set([0, 1, 2]);
|
|
451
|
+
const RIGHT_STICKY = adminColumns.length - 1;
|
|
452
|
+
|
|
453
|
+
const adminRow = (
|
|
454
|
+
i: number,
|
|
455
|
+
name: string,
|
|
456
|
+
status: string
|
|
457
|
+
): Record<string, string> => ({
|
|
458
|
+
check: `${i + 1}`,
|
|
459
|
+
name,
|
|
460
|
+
status,
|
|
461
|
+
email: `user${i + 1}@example.com`,
|
|
462
|
+
phone: '010-1234-5678',
|
|
463
|
+
address: '서울특별시 강남구 테헤란로 123',
|
|
464
|
+
company: '테크 주식회사',
|
|
465
|
+
department: '프론트엔드 팀',
|
|
466
|
+
action: '⋯',
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* Multiple left-pinned columns kept flush during horizontal scroll — the admin
|
|
471
|
+
* table layout that surfaced the offset bug. Scroll sideways: the three left
|
|
472
|
+
* columns and the right action column stay pinned and opaque, with the middle
|
|
473
|
+
* columns scrolling underneath.
|
|
474
|
+
*/
|
|
475
|
+
export const WithMultipleLeftStickyColumns: Story = {
|
|
476
|
+
render: (args) => {
|
|
477
|
+
const rows = [
|
|
478
|
+
adminRow(0, '김철수', '승인됨'),
|
|
479
|
+
adminRow(1, '이영희', '검토중'),
|
|
480
|
+
adminRow(2, '박지훈', '거절됨'),
|
|
481
|
+
];
|
|
482
|
+
return (
|
|
483
|
+
<TableContainer>
|
|
484
|
+
<Table {...args}>
|
|
485
|
+
<Thead>
|
|
486
|
+
<Tr>
|
|
487
|
+
{adminColumns.map((column, index) => (
|
|
488
|
+
<Th
|
|
489
|
+
key={column.key}
|
|
490
|
+
isSticky={LEFT_STICKY.has(index) || index === RIGHT_STICKY}
|
|
491
|
+
stickyDirection={index === RIGHT_STICKY ? 'right' : 'left'}
|
|
492
|
+
stickyIndex={index === RIGHT_STICKY ? 0 : index}
|
|
493
|
+
>
|
|
494
|
+
{column.label}
|
|
495
|
+
</Th>
|
|
496
|
+
))}
|
|
497
|
+
</Tr>
|
|
498
|
+
</Thead>
|
|
499
|
+
<Tbody>
|
|
500
|
+
{rows.map((item, i) => (
|
|
501
|
+
<Tr key={i}>
|
|
502
|
+
{adminColumns.map((column, index) => (
|
|
503
|
+
<Td
|
|
504
|
+
key={column.key}
|
|
505
|
+
isSticky={LEFT_STICKY.has(index) || index === RIGHT_STICKY}
|
|
506
|
+
stickyDirection={index === RIGHT_STICKY ? 'right' : 'left'}
|
|
507
|
+
stickyIndex={index === RIGHT_STICKY ? 0 : index}
|
|
508
|
+
>
|
|
509
|
+
{item[column.key]}
|
|
510
|
+
</Td>
|
|
511
|
+
))}
|
|
512
|
+
</Tr>
|
|
513
|
+
))}
|
|
514
|
+
</Tbody>
|
|
515
|
+
</Table>
|
|
516
|
+
</TableContainer>
|
|
517
|
+
);
|
|
518
|
+
},
|
|
519
|
+
args: { width: '220%' },
|
|
520
|
+
argTypes: {},
|
|
521
|
+
};
|
|
522
|
+
|
|
523
|
+
/**
|
|
524
|
+
* Regression coverage for the admin 챗봇 공개 관리 / 전체 멤버 breakage.
|
|
525
|
+
*
|
|
526
|
+
* The pinned columns' cumulative offsets used to be measured once at mount and
|
|
527
|
+
* then frozen, so when a column's width changed afterwards — a web-font swap, a
|
|
528
|
+
* resize, pagination swapping in wider content, or the columns reflowing as the
|
|
529
|
+
* table went from fitting to overflowing — the following pinned columns stayed
|
|
530
|
+
* at the stale offsets and visibly detached (an empty gap opened between them).
|
|
531
|
+
*
|
|
532
|
+
* Toggle the button: the second pinned column ("이름") grows/shrinks its
|
|
533
|
+
* content, so the third pinned column ("상태") must re-pin to the new edge. It
|
|
534
|
+
* has to stay flush — no empty gap, no overlap. Before the ResizeObserver fix a
|
|
535
|
+
* gap appeared here after toggling.
|
|
536
|
+
*/
|
|
537
|
+
export const StickyOffsetsTrackWidthChanges: Story = {
|
|
538
|
+
render: (args) => {
|
|
539
|
+
const [long, setLong] = useState(false);
|
|
540
|
+
const longName = '아주 아주 긴 이름 콘텐츠로 컬럼 폭을 넓힙니다';
|
|
541
|
+
const rows = [
|
|
542
|
+
adminRow(0, long ? `김철수 — ${longName}` : '김철수', '승인됨'),
|
|
543
|
+
adminRow(1, long ? `이영희 — ${longName}` : '이영희', '검토중'),
|
|
544
|
+
adminRow(2, long ? `박지훈 — ${longName}` : '박지훈', '거절됨'),
|
|
545
|
+
];
|
|
546
|
+
return (
|
|
547
|
+
<Flex direction="column" gap={3} align="start">
|
|
548
|
+
<Button onClick={() => setLong((v) => !v)}>
|
|
549
|
+
{long ? '이름 컬럼 짧게' : '이름 컬럼 길게 (폭 변경)'}
|
|
550
|
+
</Button>
|
|
551
|
+
<TableContainer>
|
|
552
|
+
<Table {...args}>
|
|
553
|
+
<Thead>
|
|
554
|
+
<Tr>
|
|
555
|
+
{adminColumns.map((column, index) => (
|
|
556
|
+
<Th
|
|
557
|
+
key={column.key}
|
|
558
|
+
isSticky={LEFT_STICKY.has(index) || index === RIGHT_STICKY}
|
|
559
|
+
stickyDirection={index === RIGHT_STICKY ? 'right' : 'left'}
|
|
560
|
+
stickyIndex={index === RIGHT_STICKY ? 0 : index}
|
|
561
|
+
>
|
|
562
|
+
{column.label}
|
|
563
|
+
</Th>
|
|
564
|
+
))}
|
|
565
|
+
</Tr>
|
|
566
|
+
</Thead>
|
|
567
|
+
<Tbody>
|
|
568
|
+
{rows.map((item, i) => (
|
|
569
|
+
<Tr key={i}>
|
|
570
|
+
{adminColumns.map((column, index) => (
|
|
571
|
+
<Td
|
|
572
|
+
key={column.key}
|
|
573
|
+
isSticky={LEFT_STICKY.has(index) || index === RIGHT_STICKY}
|
|
574
|
+
stickyDirection={index === RIGHT_STICKY ? 'right' : 'left'}
|
|
575
|
+
stickyIndex={index === RIGHT_STICKY ? 0 : index}
|
|
576
|
+
>
|
|
577
|
+
{item[column.key]}
|
|
578
|
+
</Td>
|
|
579
|
+
))}
|
|
580
|
+
</Tr>
|
|
581
|
+
))}
|
|
582
|
+
</Tbody>
|
|
583
|
+
</Table>
|
|
584
|
+
</TableContainer>
|
|
585
|
+
</Flex>
|
|
586
|
+
);
|
|
587
|
+
},
|
|
588
|
+
args: { width: '220%' },
|
|
589
|
+
argTypes: {},
|
|
590
|
+
};
|
|
591
|
+
|
|
592
|
+
// Pages whose pinned "이름" column has a different natural width each page — the
|
|
593
|
+
// real admin case, where paging swaps in rows of different content lengths.
|
|
594
|
+
const PAGES: { name: string; status: string }[][] = [
|
|
595
|
+
[
|
|
596
|
+
{ name: '김철수', status: '승인됨' },
|
|
597
|
+
{ name: '이영희', status: '검토중' },
|
|
598
|
+
{ name: '박지훈', status: '거절됨' },
|
|
599
|
+
],
|
|
600
|
+
[
|
|
601
|
+
{ name: '남궁민수 — 아주 아주 길어서 컬럼을 넓히는 이름', status: '승인됨' },
|
|
602
|
+
{ name: '황보지훈 — 아주 아주 길어서 컬럼을 넓히는 이름', status: '승인됨' },
|
|
603
|
+
{ name: '독고영희 — 아주 아주 길어서 컬럼을 넓히는 이름', status: '검토중' },
|
|
604
|
+
],
|
|
605
|
+
[
|
|
606
|
+
{ name: '최민', status: '거절됨' },
|
|
607
|
+
{ name: '한수', status: '승인됨' },
|
|
608
|
+
{ name: '오지', status: '검토중' },
|
|
609
|
+
],
|
|
610
|
+
];
|
|
611
|
+
|
|
612
|
+
/**
|
|
613
|
+
* Regression coverage for the exact admin-page symptom: **pagination didn't
|
|
614
|
+
* re-pin the sticky columns.**
|
|
615
|
+
*
|
|
616
|
+
* Paging swaps only the `<tbody>` rows while the `<thead>` (and its Th cells)
|
|
617
|
+
* stay mounted. Each page here has a different-width pinned "이름" column. The
|
|
618
|
+
* old engine measured the pinned widths once and only recalculated on a
|
|
619
|
+
* scroll/resize event — which paging doesn't fire — so pages 2/3 rendered
|
|
620
|
+
* pinned to page 1's widths and the following columns overlapped. Step through
|
|
621
|
+
* the pages: the "상태" column must stay flush against "이름" on every page.
|
|
622
|
+
*/
|
|
623
|
+
export const StickyOffsetsSurvivePagination: Story = {
|
|
624
|
+
render: (args) => {
|
|
625
|
+
const [page, setPage] = useState(0);
|
|
626
|
+
const rows = PAGES[page].map((r, i) => adminRow(i, r.name, r.status));
|
|
627
|
+
return (
|
|
628
|
+
<Flex direction="column" gap={3} align="start">
|
|
629
|
+
<Flex gap={2} align="center">
|
|
630
|
+
<Button
|
|
631
|
+
variant="outline"
|
|
632
|
+
disabled={page === 0}
|
|
633
|
+
onClick={() => setPage((p) => Math.max(0, p - 1))}
|
|
634
|
+
>
|
|
635
|
+
이전
|
|
636
|
+
</Button>
|
|
637
|
+
<span>{page + 1} / {PAGES.length} 페이지</span>
|
|
638
|
+
<Button
|
|
639
|
+
variant="outline"
|
|
640
|
+
disabled={page === PAGES.length - 1}
|
|
641
|
+
onClick={() => setPage((p) => Math.min(PAGES.length - 1, p + 1))}
|
|
642
|
+
>
|
|
643
|
+
다음
|
|
644
|
+
</Button>
|
|
645
|
+
</Flex>
|
|
646
|
+
<TableContainer>
|
|
647
|
+
<Table {...args}>
|
|
648
|
+
<Thead>
|
|
649
|
+
<Tr>
|
|
650
|
+
{adminColumns.map((column, index) => (
|
|
651
|
+
<Th
|
|
652
|
+
key={column.key}
|
|
653
|
+
isSticky={LEFT_STICKY.has(index) || index === RIGHT_STICKY}
|
|
654
|
+
stickyDirection={index === RIGHT_STICKY ? 'right' : 'left'}
|
|
655
|
+
stickyIndex={index === RIGHT_STICKY ? 0 : index}
|
|
656
|
+
>
|
|
657
|
+
{column.label}
|
|
658
|
+
</Th>
|
|
659
|
+
))}
|
|
660
|
+
</Tr>
|
|
661
|
+
</Thead>
|
|
662
|
+
<Tbody>
|
|
663
|
+
{rows.map((item, i) => (
|
|
664
|
+
<Tr key={i}>
|
|
665
|
+
{adminColumns.map((column, index) => (
|
|
666
|
+
<Td
|
|
667
|
+
key={column.key}
|
|
668
|
+
isSticky={LEFT_STICKY.has(index) || index === RIGHT_STICKY}
|
|
669
|
+
stickyDirection={index === RIGHT_STICKY ? 'right' : 'left'}
|
|
670
|
+
stickyIndex={index === RIGHT_STICKY ? 0 : index}
|
|
671
|
+
>
|
|
672
|
+
{item[column.key]}
|
|
673
|
+
</Td>
|
|
674
|
+
))}
|
|
675
|
+
</Tr>
|
|
676
|
+
))}
|
|
677
|
+
</Tbody>
|
|
678
|
+
</Table>
|
|
679
|
+
</TableContainer>
|
|
680
|
+
</Flex>
|
|
681
|
+
);
|
|
682
|
+
},
|
|
683
|
+
args: { width: '220%' },
|
|
684
|
+
argTypes: {},
|
|
685
|
+
};
|
|
@@ -14,9 +14,11 @@ export interface TableScrollState {
|
|
|
14
14
|
isScrolling: boolean;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
type ColumnWidths = Record<number, number>; // Maps index to width
|
|
18
|
+
|
|
17
19
|
interface StickyColumnInfo {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
+
left: ColumnWidths;
|
|
21
|
+
right: ColumnWidths;
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
interface TableContextValue extends TableScrollState {
|
|
@@ -52,9 +54,15 @@ export const TableProvider: React.FC<TableProviderProps> = ({ children }) => {
|
|
|
52
54
|
isScrolling: false,
|
|
53
55
|
});
|
|
54
56
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
57
|
+
// Column widths live in state (not a ref) so that a width change — a font
|
|
58
|
+
// swap, a window/sidebar resize, or the columns re-flowing when the table
|
|
59
|
+
// goes from fitting to overflowing — triggers a re-render and the sticky
|
|
60
|
+
// offsets are recomputed. Storing them in a ref (the previous approach) meant
|
|
61
|
+
// the offsets were computed once at mount and then went stale, detaching the
|
|
62
|
+
// sticky columns from their real positions.
|
|
63
|
+
const [stickyColumns, setStickyColumns] = useState<StickyColumnInfo>({
|
|
64
|
+
left: {},
|
|
65
|
+
right: {},
|
|
58
66
|
});
|
|
59
67
|
|
|
60
68
|
// 스크롤 상태 업데이트
|
|
@@ -95,14 +103,17 @@ export const TableProvider: React.FC<TableProviderProps> = ({ children }) => {
|
|
|
95
103
|
[updateScrollState]
|
|
96
104
|
);
|
|
97
105
|
|
|
98
|
-
// Register a sticky column with its width
|
|
106
|
+
// Register a sticky column with its (measured) width. Rounds to whole pixels
|
|
107
|
+
// and bails when unchanged so the ResizeObserver-driven callers can't
|
|
108
|
+
// ping-pong on sub-pixel differences and spin the render loop.
|
|
99
109
|
const registerStickyColumn = useCallback(
|
|
100
110
|
(direction: 'left' | 'right', index: number, width: number) => {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
111
|
+
const rounded = Math.round(width);
|
|
112
|
+
setStickyColumns((prev) => {
|
|
113
|
+
const side = prev[direction];
|
|
114
|
+
if (side[index] === rounded) return prev;
|
|
115
|
+
return { ...prev, [direction]: { ...side, [index]: rounded } };
|
|
116
|
+
});
|
|
106
117
|
},
|
|
107
118
|
[]
|
|
108
119
|
);
|
|
@@ -112,38 +123,33 @@ export const TableProvider: React.FC<TableProviderProps> = ({ children }) => {
|
|
|
112
123
|
(direction: 'left' | 'right', index: number) => {
|
|
113
124
|
if (index === 0) return 0;
|
|
114
125
|
|
|
115
|
-
const
|
|
116
|
-
direction === 'left'
|
|
117
|
-
? stickyColumnsRef.current.leftColumnWidths
|
|
118
|
-
: stickyColumnsRef.current.rightColumnWidths;
|
|
126
|
+
const widths = stickyColumns[direction];
|
|
119
127
|
|
|
120
128
|
let offset = 0;
|
|
121
129
|
for (let i = 0; i < index; i++) {
|
|
122
|
-
offset +=
|
|
130
|
+
offset += widths[i] || 0;
|
|
123
131
|
}
|
|
124
132
|
|
|
125
133
|
return offset;
|
|
126
134
|
},
|
|
127
|
-
[]
|
|
135
|
+
[stickyColumns]
|
|
128
136
|
);
|
|
129
137
|
|
|
130
138
|
// Check if a column is the last sticky column on its side
|
|
131
139
|
const isLastStickyColumn = useCallback(
|
|
132
140
|
(direction: 'left' | 'right', index: number) => {
|
|
133
|
-
const
|
|
134
|
-
direction === 'left'
|
|
135
|
-
? stickyColumnsRef.current.leftColumnWidths
|
|
136
|
-
: stickyColumnsRef.current.rightColumnWidths;
|
|
141
|
+
const widths = stickyColumns[direction];
|
|
137
142
|
|
|
138
|
-
// Find the highest index
|
|
143
|
+
// Find the highest registered index on this side
|
|
139
144
|
let maxIndex = -1;
|
|
140
|
-
for (const
|
|
145
|
+
for (const key of Object.keys(widths)) {
|
|
146
|
+
const idx = Number(key);
|
|
141
147
|
if (idx > maxIndex) maxIndex = idx;
|
|
142
148
|
}
|
|
143
149
|
|
|
144
150
|
return index === maxIndex;
|
|
145
151
|
},
|
|
146
|
-
[]
|
|
152
|
+
[stickyColumns]
|
|
147
153
|
);
|
|
148
154
|
|
|
149
155
|
// 단일 useEffect에서 모든 이벤트 리스너 관리
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useRef } from 'react';
|
|
2
2
|
import { Table, useToken } from '@chakra-ui/react';
|
|
3
3
|
|
|
4
4
|
import { getStickyStyles } from './Table.styles';
|
|
5
5
|
import { TableCellProps } from './Table.types';
|
|
6
6
|
import { useTableContext } from './TableContext';
|
|
7
|
+
import { useRegisterStickyWidth } from './useRegisterStickyWidth';
|
|
7
8
|
|
|
8
9
|
export const Td = ({
|
|
9
10
|
wrap,
|
|
@@ -82,13 +83,14 @@ export const Td = ({
|
|
|
82
83
|
...scrollState
|
|
83
84
|
} = tableContext;
|
|
84
85
|
|
|
85
|
-
//
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
86
|
+
// Keep this column's width registered so the cumulative sticky offsets stay
|
|
87
|
+
// correct across layout changes (font swap, resize, fit -> overflow).
|
|
88
|
+
useRegisterStickyWidth(cellRef, {
|
|
89
|
+
isSticky,
|
|
90
|
+
direction: stickyDirection,
|
|
91
|
+
index: stickyIndex,
|
|
92
|
+
register: registerStickyColumn,
|
|
93
|
+
});
|
|
92
94
|
|
|
93
95
|
// Get the sticky offset based on the column's position
|
|
94
96
|
const stickyOffset = isSticky
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { forwardRef, useCallback,
|
|
1
|
+
import { forwardRef, useCallback, useRef } from 'react';
|
|
2
2
|
import { Table, useToken } from '@chakra-ui/react';
|
|
3
3
|
|
|
4
4
|
import { getStickyStyles } from './Table.styles';
|
|
5
5
|
import { TableCellProps } from './Table.types';
|
|
6
6
|
import { useTableContext } from './TableContext';
|
|
7
|
+
import { useRegisterStickyWidth } from './useRegisterStickyWidth';
|
|
7
8
|
|
|
8
9
|
export const Th = forwardRef<
|
|
9
10
|
HTMLTableCellElement,
|
|
@@ -86,13 +87,14 @@ export const Th = forwardRef<
|
|
|
86
87
|
...scrollState
|
|
87
88
|
} = tableContext;
|
|
88
89
|
|
|
89
|
-
//
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
90
|
+
// Keep this column's width registered so the cumulative sticky offsets stay
|
|
91
|
+
// correct across layout changes (font swap, resize, fit -> overflow).
|
|
92
|
+
useRegisterStickyWidth(measureNodeRef, {
|
|
93
|
+
isSticky,
|
|
94
|
+
direction: stickyDirection,
|
|
95
|
+
index: stickyIndex,
|
|
96
|
+
register: registerStickyColumn,
|
|
97
|
+
});
|
|
96
98
|
|
|
97
99
|
// Combine refs (forwarded ref and internal ref)
|
|
98
100
|
const setRefs = useCallback(
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { RefObject, useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
import { StickyDirection } from './Table.styles';
|
|
4
|
+
|
|
5
|
+
interface UseRegisterStickyWidthOptions {
|
|
6
|
+
isSticky: boolean;
|
|
7
|
+
direction: StickyDirection;
|
|
8
|
+
index: number;
|
|
9
|
+
register: (direction: StickyDirection, index: number, width: number) => void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Keep a sticky cell's measured width registered with the table context.
|
|
14
|
+
*
|
|
15
|
+
* Unlike a mount-only measurement, this observes the cell with a
|
|
16
|
+
* `ResizeObserver`, so the width stays correct through later layout changes —
|
|
17
|
+
* a web-font swap that reflows the text, a window/sidebar resize, or the
|
|
18
|
+
* columns shrinking when the table goes from fitting its container to
|
|
19
|
+
* overflowing it. Without this, the cumulative sticky offsets are computed once
|
|
20
|
+
* from stale widths and the pinned columns visibly detach (an empty gap opens
|
|
21
|
+
* between them and neighbouring columns collapse).
|
|
22
|
+
*
|
|
23
|
+
* `getBoundingClientRect().width` is read inside the callback so the value is
|
|
24
|
+
* always the border-box width the offset maths expects.
|
|
25
|
+
*/
|
|
26
|
+
export function useRegisterStickyWidth(
|
|
27
|
+
ref: RefObject<HTMLTableCellElement | null>,
|
|
28
|
+
{ isSticky, direction, index, register }: UseRegisterStickyWidthOptions
|
|
29
|
+
) {
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
const node = ref.current;
|
|
32
|
+
if (!isSticky || !node) return;
|
|
33
|
+
|
|
34
|
+
register(direction, index, node.getBoundingClientRect().width);
|
|
35
|
+
|
|
36
|
+
if (typeof ResizeObserver === 'undefined') return;
|
|
37
|
+
|
|
38
|
+
const observer = new ResizeObserver(() => {
|
|
39
|
+
register(direction, index, node.getBoundingClientRect().width);
|
|
40
|
+
});
|
|
41
|
+
observer.observe(node);
|
|
42
|
+
|
|
43
|
+
return () => observer.disconnect();
|
|
44
|
+
}, [ref, isSticky, direction, index, register]);
|
|
45
|
+
}
|