forked from sheetjs/docs.sheetjs.com
		
	
		
			
	
	
		
			83 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
		
		
			
		
	
	
			83 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| 
								 | 
							
								import { useState, useCallback, useEffect, useRef, ChangeEvent } from 'react';
							 | 
						||
| 
								 | 
							
								import { utils, read, writeFileXLSX, WorkBook } from 'xlsx';
							 | 
						||
| 
								 | 
							
								import { DataEditor, GridCellKind, GridCell, GridColumn, Item, DataEditorRef, EditableGridCell } from '@glideapps/glide-data-grid';
							 | 
						||
| 
								 | 
							
								import "@glideapps/glide-data-grid/dist/index.css";
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// this will store the raw data objects
							 | 
						||
| 
								 | 
							
								let data: any[] = [];
							 | 
						||
| 
								 | 
							
								// this will store the header names
							 | 
						||
| 
								 | 
							
								let header: string[] = [];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function App() {
							 | 
						||
| 
								 | 
							
								  const [cols, setCols] = useState<GridColumn[]>([]); // gdg column objects
							 | 
						||
| 
								 | 
							
								  const [rows, setRows] = useState<number>(0); // number of rows
							 | 
						||
| 
								 | 
							
								  const ref = useRef<DataEditorRef>(null); // gdg ref
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // read/write between gdg and the backing data store
							 | 
						||
| 
								 | 
							
								  const getContent = useCallback((cell: Item): GridCell => {
							 | 
						||
| 
								 | 
							
								    const [col, row] = cell;
							 | 
						||
| 
								 | 
							
								    return {
							 | 
						||
| 
								 | 
							
								      kind: GridCellKind.Text,
							 | 
						||
| 
								 | 
							
								      allowOverlay: true,
							 | 
						||
| 
								 | 
							
								      readonly: false,
							 | 
						||
| 
								 | 
							
								      displayData: String(data[row]?.[header[col]]??""),
							 | 
						||
| 
								 | 
							
								      data: data[row]?.[header[col]],
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								  }, []);
							 | 
						||
| 
								 | 
							
								  const onCellEdited = useCallback((cell: Item, newValue: EditableGridCell) => {
							 | 
						||
| 
								 | 
							
								    const [ col, row ] = cell;
							 | 
						||
| 
								 | 
							
								    data[row][header[col]] = newValue.data;
							 | 
						||
| 
								 | 
							
								  }, []);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // update the data store from a workbook object
							 | 
						||
| 
								 | 
							
								  const parse_wb = (wb: WorkBook) => {
							 | 
						||
| 
								 | 
							
								    const sheet = wb.Sheets[wb.SheetNames[0]];
							 | 
						||
| 
								 | 
							
								    data = utils.sheet_to_json<any>(sheet);
							 | 
						||
| 
								 | 
							
								    const range = utils.decode_range(sheet["!ref"]??"A1"); range.e.r = range.s.r;
							 | 
						||
| 
								 | 
							
								    header = utils.sheet_to_json<string[]>(sheet, {header: 1, range})[0];
							 | 
						||
| 
								 | 
							
								    setCols(header.map(h => ({title: h, id: h} as GridColumn)));
							 | 
						||
| 
								 | 
							
								    setRows(data.length);
							 | 
						||
| 
								 | 
							
								    if(data.length > 0) {
							 | 
						||
| 
								 | 
							
								      let cells = data.map(
							 | 
						||
| 
								 | 
							
								        (_,R) => Array.from({length:header.length}, (_,C) => ({cell: ([C,R] as Item)}))
							 | 
						||
| 
								 | 
							
								      ).flat();
							 | 
						||
| 
								 | 
							
								      ref.current?.updateCells(cells);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								  // file input element onchange event handler
							 | 
						||
| 
								 | 
							
								  const onChange = useCallback(async (e: ChangeEvent<HTMLInputElement>) => {
							 | 
						||
| 
								 | 
							
								    if(!e.target?.files) return;
							 | 
						||
| 
								 | 
							
								    parse_wb(read(await e.target.files[0].arrayBuffer()));
							 | 
						||
| 
								 | 
							
								  }, []);
							 | 
						||
| 
								 | 
							
								  // when the component loads, fetch and display a sample workbook
							 | 
						||
| 
								 | 
							
								  useEffect(() => {
							 | 
						||
| 
								 | 
							
								    (async() => {
							 | 
						||
| 
								 | 
							
								      parse_wb(read(await (await fetch("https://sheetjs.com/pres.numbers")).arrayBuffer()));
							 | 
						||
| 
								 | 
							
								    })();
							 | 
						||
| 
								 | 
							
								  }, []);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // export data
							 | 
						||
| 
								 | 
							
								  const exportXLSX = useCallback(() => {
							 | 
						||
| 
								 | 
							
								    // generate worksheet using data with the order specified in the columns array
							 | 
						||
| 
								 | 
							
								    const ws = utils.json_to_sheet(data, {header: cols.map(c => c.id ?? c.title)});
							 | 
						||
| 
								 | 
							
								    // rewrite header row with titles
							 | 
						||
| 
								 | 
							
								    utils.sheet_add_aoa(ws, [cols.map(c => c.title ?? c.id)], {origin: "A1"});
							 | 
						||
| 
								 | 
							
								    // create workbook
							 | 
						||
| 
								 | 
							
								    const wb = utils.book_new();
							 | 
						||
| 
								 | 
							
								    utils.book_append_sheet(wb, ws, "Export"); // replace with sheet name
							 | 
						||
| 
								 | 
							
								    // download file
							 | 
						||
| 
								 | 
							
								    writeFileXLSX(wb, "sheetjs-gdg.xlsx");
							 | 
						||
| 
								 | 
							
								  }, []);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return ( <>
							 | 
						||
| 
								 | 
							
								    <input type="file" onChange={onChange} />
							 | 
						||
| 
								 | 
							
								    <button onClick={exportXLSX}><b>Export XLSX!</b></button>
							 | 
						||
| 
								 | 
							
								    <div className="App">
							 | 
						||
| 
								 | 
							
								      <DataEditor getCellContent={getContent} columns={cols} rows={rows} onCellEdited={onCellEdited} ref={ref}/>
							 | 
						||
| 
								 | 
							
								    </div>
							 | 
						||
| 
								 | 
							
								    <div id="portal"></div>
							 | 
						||
| 
								 | 
							
								    </>
							 | 
						||
| 
								 | 
							
								  )
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								export default App;
							 |