@@ -5,6 +5,7 @@ import Table from '../src';
55import type { TableProps } from '../src/Table' ;
66
77describe ( 'Table.Hover' , ( ) => {
8+ const hoverClassName = 'rc-table-cell-row-hover' ;
89 const data = [
910 { key : 'key0' , name : 'Lucy' } ,
1011 { key : 'key1' , name : 'Jack' } ,
@@ -127,6 +128,166 @@ describe('Table.Hover', () => {
127128 expect ( container . querySelector ( '.rc-table-cell-row-hover' ) ) . toBeFalsy ( ) ;
128129 } ) ;
129130
131+ it ( 'does not let expanded row offset rowSpan affect hover range' , ( ) => {
132+ const { container } = render (
133+ < Table
134+ rowKey = "key"
135+ columns = { [
136+ {
137+ dataIndex : 'group' ,
138+ onCell : ( _ , index ) => {
139+ if ( index === 0 ) {
140+ return { rowSpan : 2 } ;
141+ }
142+ if ( index === 1 ) {
143+ return { rowSpan : 0 } ;
144+ }
145+ return { } ;
146+ } ,
147+ } ,
148+ Table . EXPAND_COLUMN ,
149+ {
150+ dataIndex : 'name' ,
151+ } ,
152+ ] }
153+ data = { [
154+ { key : 'a' , group : 'Group 1' , name : 'Alpha' } ,
155+ { key : 'b' , group : 'Group 1' , name : 'Beta' } ,
156+ { key : 'c' , group : 'Group 2' , name : 'Gamma' } ,
157+ ] }
158+ expandable = { {
159+ expandedRowOffset : 1 ,
160+ expandedRowKeys : [ 'a' ] ,
161+ expandedRowRender : record => < span > expanded { record . key } </ span > ,
162+ } }
163+ /> ,
164+ ) ;
165+
166+ const getCell = ( text : string ) => {
167+ const cell = Array . from ( container . querySelectorAll < HTMLTableCellElement > ( 'tbody td' ) ) . find (
168+ cell => cell . textContent === text ,
169+ ) ;
170+ expect ( cell ) . toBeTruthy ( ) ;
171+ return cell ! ;
172+ } ;
173+
174+ const groupCell = getCell ( 'Group 1' ) ;
175+ const betaCell = getCell ( 'Beta' ) ;
176+ const gammaCell = getCell ( 'Gamma' ) ;
177+
178+ expect ( groupCell . getAttribute ( 'rowspan' ) ) . toBe ( '3' ) ;
179+
180+ fireEvent . mouseEnter ( groupCell ) ;
181+ expect ( groupCell . classList . contains ( hoverClassName ) ) . toBe ( true ) ;
182+ expect ( betaCell . classList . contains ( hoverClassName ) ) . toBe ( true ) ;
183+ expect ( gammaCell . classList . contains ( hoverClassName ) ) . toBe ( false ) ;
184+
185+ fireEvent . mouseEnter ( gammaCell ) ;
186+ expect ( groupCell . classList . contains ( hoverClassName ) ) . toBe ( false ) ;
187+ expect ( gammaCell . classList . contains ( hoverClassName ) ) . toBe ( true ) ;
188+ } ) ;
189+
190+ it ( 'keeps legacy render rowSpan priority for hover range' , ( ) => {
191+ const { container } = render (
192+ < Table
193+ rowKey = "key"
194+ columns = { [
195+ {
196+ dataIndex : 'group' ,
197+ render : ( value , _ , index ) => ( {
198+ children : value ,
199+ props : { rowSpan : index === 0 ? 2 : 0 } ,
200+ } ) ,
201+ } ,
202+ Table . EXPAND_COLUMN ,
203+ {
204+ dataIndex : 'name' ,
205+ } ,
206+ ] }
207+ data = { [
208+ { key : 'a' , group : 'Group 1' , name : 'Alpha' } ,
209+ { key : 'b' , group : 'Group 1' , name : 'Beta' } ,
210+ { key : 'c' , group : 'Group 2' , name : 'Gamma' } ,
211+ ] }
212+ expandable = { {
213+ expandedRowOffset : 1 ,
214+ defaultExpandAllRows : true ,
215+ expandedRowRender : record => < span > expanded { record . key } </ span > ,
216+ } }
217+ /> ,
218+ ) ;
219+
220+ const getCell = ( text : string ) => {
221+ const cell = Array . from ( container . querySelectorAll < HTMLTableCellElement > ( 'tbody td' ) ) . find (
222+ item => item . textContent === text ,
223+ ) ;
224+ expect ( cell ) . toBeTruthy ( ) ;
225+ return cell ! ;
226+ } ;
227+
228+ const groupCell = getCell ( 'Group 1' ) ;
229+ const alphaCell = getCell ( 'Alpha' ) ;
230+ const betaCell = getCell ( 'Beta' ) ;
231+ const gammaCell = getCell ( 'Gamma' ) ;
232+
233+ expect ( groupCell . getAttribute ( 'rowspan' ) ) . toBe ( '2' ) ;
234+
235+ fireEvent . mouseEnter ( groupCell ) ;
236+ expect ( alphaCell . classList . contains ( hoverClassName ) ) . toBe ( true ) ;
237+ expect ( betaCell . classList . contains ( hoverClassName ) ) . toBe ( true ) ;
238+ expect ( gammaCell . classList . contains ( hoverClassName ) ) . toBe ( false ) ;
239+ } ) ;
240+
241+ it ( 'does not mutate stable onCell props across expanded row renders' , ( ) => {
242+ const rowSpanProps = [ { rowSpan : 2 } , { rowSpan : 0 } , { } ] ;
243+ const dataSource = [
244+ { key : 'a' , group : 'Group 1' , name : 'Alpha' } ,
245+ { key : 'b' , group : 'Group 1' , name : 'Beta' } ,
246+ { key : 'c' , group : 'Group 2' , name : 'Gamma' } ,
247+ ] ;
248+
249+ const createTableWithExpandedKeys = ( expandedRowKeys : React . Key [ ] ) => (
250+ < React . StrictMode >
251+ < Table
252+ rowKey = "key"
253+ columns = { [
254+ {
255+ dataIndex : 'group' ,
256+ onCell : ( _ , index ) => rowSpanProps [ index ] ,
257+ } ,
258+ Table . EXPAND_COLUMN ,
259+ {
260+ dataIndex : 'name' ,
261+ } ,
262+ ] }
263+ data = { dataSource }
264+ expandable = { {
265+ expandedRowOffset : 1 ,
266+ expandedRowKeys,
267+ expandedRowRender : record => < span > expanded { record . key } </ span > ,
268+ } }
269+ />
270+ </ React . StrictMode >
271+ ) ;
272+
273+ const { container, rerender } = render ( createTableWithExpandedKeys ( [ ] ) ) ;
274+ const getGroupCell = ( ) =>
275+ Array . from ( container . querySelectorAll < HTMLTableCellElement > ( 'tbody td' ) ) . find (
276+ cell => cell . textContent === 'Group 1' ,
277+ ) ! ;
278+
279+ expect ( rowSpanProps [ 0 ] . rowSpan ) . toBe ( 2 ) ;
280+ expect ( getGroupCell ( ) . getAttribute ( 'rowspan' ) ) . toBe ( '2' ) ;
281+
282+ rerender ( createTableWithExpandedKeys ( [ 'a' ] ) ) ;
283+ expect ( rowSpanProps [ 0 ] . rowSpan ) . toBe ( 2 ) ;
284+ expect ( getGroupCell ( ) . getAttribute ( 'rowspan' ) ) . toBe ( '3' ) ;
285+
286+ rerender ( createTableWithExpandedKeys ( [ ] ) ) ;
287+ expect ( rowSpanProps [ 0 ] . rowSpan ) . toBe ( 2 ) ;
288+ expect ( getGroupCell ( ) . getAttribute ( 'rowspan' ) ) . toBe ( '2' ) ;
289+ } ) ;
290+
130291 describe ( 'perf' , ( ) => {
131292 it ( 'legacy mode should render every time' , ( ) => {
132293 let renderTimes = 0 ;
0 commit comments