7
7
} from "ag-grid-community" ;
8
8
import * as XLSX from "xlsx" ;
9
9
import * as cptable from "codepage" ;
10
+ import ReactDOM from "react-dom" ;
10
11
11
12
const theme = themeQuartz . withParams ( {
12
13
borderRadius : 6 ,
@@ -26,13 +27,6 @@ XLSX.set_cptable(cptable);
26
27
// Register all community modules for AG Grid v34+
27
28
ModuleRegistry . registerModules ( [ AllCommunityModule ] ) ;
28
29
29
- function decodeHTMLEntities ( text : string ) {
30
- if ( typeof text !== "string" ) return text ;
31
- const txt = document . createElement ( "textarea" ) ;
32
- txt . innerHTML = text ;
33
- return txt . value ;
34
- }
35
-
36
30
export function DataTable ( {
37
31
fileUrl,
38
32
cells,
@@ -49,7 +43,6 @@ export function DataTable({
49
43
const [ rowData , setRowData ] = useState < Array < any > > ( [ ] ) ;
50
44
const [ colHeaders , setColHeaders ] = useState < Array < string > > ( [ ] ) ;
51
45
const [ loading , setLoading ] = useState < boolean > ( ! ! fileUrl ) ;
52
-
53
46
useEffect ( ( ) => {
54
47
if ( cells && cells . length > 1 ) {
55
48
let rows = cells . map ( ( row : any ) =>
@@ -125,7 +118,6 @@ export function DataTable({
125
118
pinned : "left" as const ,
126
119
width : 35 ,
127
120
suppressMovable : true ,
128
- suppressMenu : true ,
129
121
suppressColumnsToolPanel : true ,
130
122
suppressFiltersToolPanel : true ,
131
123
suppressAutoSize : true ,
@@ -165,14 +157,10 @@ export function DataTable({
165
157
if ( loading ) return < div > Loading...</ div > ;
166
158
167
159
return (
168
- < div
169
- style = { { height : 300 } }
170
- // style={{ maxHeight: 300, overflow: "auto" }}
171
- >
160
+ < FullscreenOverlay >
172
161
< AgGridReact
173
162
theme = { theme }
174
163
rowData = { rowData }
175
- // domLayout="autoHeight"
176
164
autoSizeStrategy = { {
177
165
type : "fitCellContents" ,
178
166
defaultMaxWidth : 300 ,
@@ -188,10 +176,17 @@ export function DataTable({
188
176
: { }
189
177
}
190
178
/>
191
- </ div >
179
+ </ FullscreenOverlay >
192
180
) ;
193
181
}
194
182
183
+ function decodeHTMLEntities ( text : string ) {
184
+ if ( typeof text !== "string" ) return text ;
185
+ const txt = document . createElement ( "textarea" ) ;
186
+ txt . innerHTML = text ;
187
+ return txt . value ;
188
+ }
189
+
195
190
function HeaderWithSelect ( {
196
191
displayName,
197
192
headerSelect,
@@ -246,3 +241,117 @@ function HeaderWithSelect({
246
241
</ div >
247
242
) ;
248
243
}
244
+
245
+ function FullscreenOverlay ( { children } : { children : React . ReactNode } ) {
246
+ const [ fullscreen , setFullscreen ] = useState ( false ) ;
247
+
248
+ // Prevent background scroll when fullscreen is open
249
+ useEffect ( ( ) => {
250
+ if ( fullscreen ) {
251
+ const original = document . body . style . overflow ;
252
+ document . body . style . overflow = "hidden" ;
253
+ // Add ESC key handler
254
+ const handleKeyDown = ( e : KeyboardEvent ) => {
255
+ if ( e . key === "Escape" ) {
256
+ setFullscreen ( false ) ;
257
+ }
258
+ } ;
259
+ window . addEventListener ( "keydown" , handleKeyDown ) ;
260
+ return ( ) => {
261
+ document . body . style . overflow = original ;
262
+ window . removeEventListener ( "keydown" , handleKeyDown ) ;
263
+ } ;
264
+ }
265
+ } , [ fullscreen ] ) ;
266
+
267
+ if ( fullscreen ) {
268
+ let overlay = (
269
+ < div
270
+ style = { {
271
+ position : "fixed" ,
272
+ top : 0 ,
273
+ left : 0 ,
274
+ width : "100vw" ,
275
+ height : "100vh" ,
276
+ zIndex : 999999 ,
277
+ background : "rgba(255,255,255,0.85)" ,
278
+ backdropFilter : "blur(16px) saturate(180%)" ,
279
+ WebkitBackdropFilter : "blur(16px) saturate(180%)" ,
280
+ display : "flex" ,
281
+ alignItems : "center" ,
282
+ justifyContent : "center" ,
283
+ } }
284
+ >
285
+ < div
286
+ style = { {
287
+ width : "80%" ,
288
+ height : "80%" ,
289
+ position : "relative" ,
290
+ } }
291
+ >
292
+ { /* Close button */ }
293
+ < button
294
+ aria-label = "Close fullscreen table"
295
+ onClick = { ( ) => setFullscreen ( false ) }
296
+ style = { {
297
+ position : "absolute" ,
298
+ top : - 16 ,
299
+ right : - 16 ,
300
+ zIndex : 1001 ,
301
+ borderRadius : "50%" ,
302
+ width : 40 ,
303
+ height : 40 ,
304
+ background : "#fff" ,
305
+ border : "1px solid #ccc" ,
306
+ boxShadow : "0 2px 8px rgba(0,0,0,0.08)" ,
307
+ display : "flex" ,
308
+ alignItems : "center" ,
309
+ justifyContent : "center" ,
310
+ cursor : "pointer" ,
311
+ fontSize : 24 ,
312
+ } }
313
+ >
314
+ < i className = "fa fa-times" aria-hidden = "true" > </ i >
315
+ </ button >
316
+ { /* Table */ }
317
+ { children }
318
+ </ div >
319
+ </ div >
320
+ ) ;
321
+ return ReactDOM . createPortal ( overlay , document . body ) ;
322
+ } else {
323
+ return (
324
+ < div style = { { position : "relative" } } >
325
+ { /* Table */ }
326
+ < div style = { { height : 300 } } > { children } </ div >
327
+ { /* Expand button */ }
328
+ < button
329
+ aria-label = "Expand table"
330
+ onClick = { ( ) => setFullscreen ( true ) }
331
+ style = { {
332
+ position : "absolute" ,
333
+ bottom : - 10 ,
334
+ right : - 10 ,
335
+ zIndex : 2 ,
336
+ borderRadius : "50%" ,
337
+ width : 28 ,
338
+ height : 28 ,
339
+ background : "#fff" ,
340
+ border : "1px solid #ccc" ,
341
+ boxShadow : "0 2px 8px rgba(0,0,0,0.08)" ,
342
+ display : "flex" ,
343
+ alignItems : "center" ,
344
+ justifyContent : "center" ,
345
+ cursor : "pointer" ,
346
+ } }
347
+ >
348
+ { /* FontAwesome expand icon */ }
349
+ < i
350
+ className = "fa-solid fa-sm fa-up-right-and-down-left-from-center"
351
+ aria-hidden = "true"
352
+ > </ i >
353
+ </ button >
354
+ </ div >
355
+ ) ;
356
+ }
357
+ }
0 commit comments