knex
This commit is contained in:
		
							parent
							
								
									e197ed24c8
								
							
						
					
					
						commit
						059a1a3783
					
				| @ -15,7 +15,7 @@ Other demos cover general React deployments, including: | ||||
| - [Static Site Generation powered by NextJS](/docs/demos/static/nextjs) | ||||
| - [iOS and Android applications powered by React Native](/docs/demos/mobile/reactnative) | ||||
| - [Desktop application powered by React Native Windows + macOS](/docs/demos/desktop/reactnative) | ||||
| - [React Data Grid UI component](/docs/demos/grid#react-data-grid) | ||||
| - [React Data Grid UI component](/docs/demos/grid/rdg) | ||||
| - [Glide Data Grid UI component](/docs/demos/grid/gdg) | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										127
									
								
								docz/docs/03-demos/02-grid/11-rdg.md
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										127
									
								
								docz/docs/03-demos/02-grid/11-rdg.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,127 @@ | ||||
| --- | ||||
| title: React Datagrid | ||||
| pagination_prev: demos/frontend/index | ||||
| pagination_next: demos/net/index | ||||
| --- | ||||
| 
 | ||||
| :::note | ||||
| 
 | ||||
| This demo was last tested on 2023 April 18 with `react-data-grid 7.0.0-beta.28`, | ||||
| `create-react-app` 5.0.1 and React 18.2.0. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| 
 | ||||
| The demo creates a site that looks like the screenshot below: | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| ## Integration Details | ||||
| 
 | ||||
| #### Rows and Columns state | ||||
| 
 | ||||
| `react-data-grid` state consists of an Array of column metadata and an Array of | ||||
| row objects. Typically both are defined in state: | ||||
| 
 | ||||
| ```jsx | ||||
| import DataGrid, { Column } from "react-data-grid"; | ||||
| 
 | ||||
| export default function App() { | ||||
|   const [rows, setRows] = useState([]); | ||||
|   const [columns, setColumns] = useState([]); | ||||
| 
 | ||||
|   return ( <DataGrid columns={columns} rows={rows} onRowsChange={setRows} /> ); | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| The most generic data representation is an array of arrays. To sate the grid, | ||||
| columns must be objects whose `key` property is the index converted to string: | ||||
| 
 | ||||
| ```ts | ||||
| import { WorkSheet, utils } from 'xlsx'; | ||||
| import { textEditor, Column } from "react-data-grid"; | ||||
| 
 | ||||
| type Row = any[]; | ||||
| type AOAColumn = Column<Row>; | ||||
| type RowCol = { rows: Row[]; columns: AOAColumn[]; }; | ||||
| 
 | ||||
| function ws_to_rdg(ws: WorkSheet): RowCol { | ||||
|   /* create an array of arrays */ | ||||
|   const rows = utils.sheet_to_json(ws, { header: 1 }); | ||||
| 
 | ||||
|   /* create column array */ | ||||
|   const range = utils.decode_range(ws["!ref"]||"A1"); | ||||
|   const columns = Array.from({ length: range.e.c + 1 }, (_, i) => ({ | ||||
|     key: String(i), // RDG will access row["0"], row["1"], etc | ||||
|     name: utils.encode_col(i), // the column labels will be A, B, etc | ||||
|     editor: textEditor // enable cell editing | ||||
|   })); | ||||
| 
 | ||||
|   return { rows, columns }; // these can be fed to setRows / setColumns | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| In the other direction, a worksheet can be generated with `aoa_to_sheet`: | ||||
| 
 | ||||
| ```ts | ||||
| import { WorkSheet, utils } from 'xlsx'; | ||||
| 
 | ||||
| type Row = any[]; | ||||
| 
 | ||||
| function rdg_to_ws(rows: Row[]): WorkSheet { | ||||
|   return utils.aoa_to_sheet(rows); | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| :::caution | ||||
| 
 | ||||
| When the demo was last refreshed, row array objects were preserved.  This was | ||||
| not the case in a later release.  The row arrays must be re-created. | ||||
| 
 | ||||
| The snippet defines a `arrayify` function that creates arrays if necessary. | ||||
| 
 | ||||
| ```ts | ||||
| import { WorkSheet, utils } from 'xlsx'; | ||||
| 
 | ||||
| type Row = any[]; | ||||
| 
 | ||||
| // highlight-start | ||||
| function arrayify(rows: any[]): Row[] { | ||||
|   return rows.map(row => { | ||||
|     var length = Object.keys(row).length; | ||||
|     for(; length > 0; --length) if(row[length-1] != null) break; | ||||
|     return Array.from({length, ...row}); | ||||
|   }); | ||||
| } | ||||
| // highlight-end | ||||
| 
 | ||||
| function rdg_to_ws(rows: Row[]): WorkSheet { | ||||
|   return utils.aoa_to_sheet(arrayify(rows)); | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| ## Demo | ||||
| 
 | ||||
| 1) Create a new TypeScript `create-react-app` app: | ||||
| 
 | ||||
| ```bash | ||||
| npx create-react-app sheetjs-rdg --template typescript | ||||
| cd sheetjs-rdg | ||||
| ``` | ||||
| 
 | ||||
| 2) Install dependencies: | ||||
| 
 | ||||
| ```bash | ||||
| npm i -S https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz react-data-grid | ||||
| ``` | ||||
| 
 | ||||
| 3) Download [`App.tsx`](pathname:///rdg/App.tsx) and replace `src/App.tsx`. | ||||
| 
 | ||||
| ```bash | ||||
| curl -L -o src/App.tsx https://docs.sheetjs.com/rdg/App.tsx | ||||
| ``` | ||||
| 
 | ||||
| 4) run `npm start`.  When you load the page in the browser, it will attempt to | ||||
|    fetch <https://sheetjs.com/pres.numbers> and load the data. | ||||
| @ -91,129 +91,7 @@ with other buttons and components on the page. | ||||
| 
 | ||||
| ### React Data Grid | ||||
| 
 | ||||
| :::note | ||||
| 
 | ||||
| This demo was tested against `react-data-grid 7.0.0-beta.15`, React 18.2.0, | ||||
| and `create-react-app` 5.0.1 on 2022 August 16. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| <!-- spellchecker-disable --> | ||||
| 
 | ||||
| #### RDG Demo | ||||
| 
 | ||||
| <!-- spellchecker-enable --> | ||||
| 
 | ||||
| <details><summary><b>Complete Example</b> (click to show)</summary> | ||||
| 
 | ||||
| 1) Create a new TypeScript `create-react-app` app: | ||||
| 
 | ||||
| ```bash | ||||
| npx create-react-app sheetjs-cra --template typescript | ||||
| cd sheetjs-cra | ||||
| ``` | ||||
| 
 | ||||
| 2) Install dependencies: | ||||
| 
 | ||||
| ```bash | ||||
| npm i -S https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz react-data-grid | ||||
| ``` | ||||
| 
 | ||||
| 3) Download [`App.tsx`](pathname:///rdg/App.tsx) and replace `src/App.tsx`. | ||||
| 
 | ||||
| 4) run `npm start`.  When you load the page in the browser, it will attempt to | ||||
|    fetch <https://sheetjs.com/pres.numbers> and load the data. | ||||
| 
 | ||||
| The following screenshot was taken from the demo: | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| #### Rows and Columns state | ||||
| 
 | ||||
| `react-data-grid` state consists of an Array of column metadata and an Array of | ||||
| row objects. Typically both are defined in state: | ||||
| 
 | ||||
| ```jsx | ||||
| import DataGrid, { Column } from "react-data-grid"; | ||||
| 
 | ||||
| export default function App() { | ||||
|   const [rows, setRows] = useState([]); | ||||
|   const [columns, setColumns] = useState([]); | ||||
| 
 | ||||
|   return ( <DataGrid columns={columns} rows={rows} onRowsChange={setRows} /> ); | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| The most generic data representation is an array of arrays. To sate the grid, | ||||
| columns must be objects whose `key` property is the index converted to string: | ||||
| 
 | ||||
| ```ts | ||||
| import { WorkSheet, utils } from 'xlsx'; | ||||
| import { textEditor, Column } from "react-data-grid"; | ||||
| 
 | ||||
| type Row = any[]; | ||||
| type AOAColumn = Column<Row>; | ||||
| type RowCol = { rows: Row[]; columns: AOAColumn[]; }; | ||||
| 
 | ||||
| function ws_to_rdg(ws: WorkSheet): RowCol { | ||||
|   /* create an array of arrays */ | ||||
|   const rows = utils.sheet_to_json(ws, { header: 1 }); | ||||
| 
 | ||||
|   /* create column array */ | ||||
|   const range = utils.decode_range(ws["!ref"]||"A1"); | ||||
|   const columns = Array.from({ length: range.e.c + 1 }, (_, i) => ({ | ||||
|     key: String(i), // RDG will access row["0"], row["1"], etc | ||||
|     name: utils.encode_col(i), // the column labels will be A, B, etc | ||||
|     editor: textEditor // enable cell editing | ||||
|   })); | ||||
| 
 | ||||
|   return { rows, columns }; // these can be fed to setRows / setColumns | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| In the other direction, a worksheet can be generated with `aoa_to_sheet`: | ||||
| 
 | ||||
| ```ts | ||||
| import { WorkSheet, utils } from 'xlsx'; | ||||
| 
 | ||||
| type Row = any[]; | ||||
| 
 | ||||
| function rdg_to_ws(rows: Row[]): WorkSheet { | ||||
|   return utils.aoa_to_sheet(rows); | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| :::caution | ||||
| 
 | ||||
| When the demo was last refreshed, row array objects were preserved.  This was | ||||
| not the case in a later release.  The row arrays must be re-created. | ||||
| 
 | ||||
| The snippet defines a `arrayify` function that creates arrays if necessary. | ||||
| 
 | ||||
| ```ts | ||||
| import { WorkSheet, utils } from 'xlsx'; | ||||
| 
 | ||||
| type Row = any[]; | ||||
| 
 | ||||
| // highlight-start | ||||
| function arrayify(rows: any[]): Row[] { | ||||
|   return rows.map(row => { | ||||
|     var length = Object.keys(row).length; | ||||
|     for(; length > 0; --length) if(row[length-1] != null) break; | ||||
|     return Array.from({length, ...row}); | ||||
|   }); | ||||
| } | ||||
| // highlight-end | ||||
| 
 | ||||
| function rdg_to_ws(rows: Row[]): WorkSheet { | ||||
|   return utils.aoa_to_sheet(arrayify(rows)); | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| **[The exposition has been moved to a separate page.](/docs/demos/grid/rdg)** | ||||
| 
 | ||||
| ### Glide Data Grid | ||||
| 
 | ||||
| @ -222,7 +100,7 @@ function rdg_to_ws(rows: Row[]): WorkSheet { | ||||
| ### Material UI Data Grid | ||||
| 
 | ||||
| Material UI Data Grid and React Data Grid share many state patterns and idioms. | ||||
| Differences from ["React Data Grid"](#react-data-grid) will be highlighted. | ||||
| Differences from ["React Data Grid"](/docs/demos/grid/rdg) will be highlighted. | ||||
| 
 | ||||
| [A complete example is included below.](#muidg-demo) | ||||
| 
 | ||||
|  | ||||
| @ -103,7 +103,7 @@ from the `"Presidents"` sheet: | ||||
| 
 | ||||
| :::note | ||||
| 
 | ||||
| This was tested against `lume v1.15.3` on 2023 March 14. | ||||
| This was tested against `lume v1.16.2` on 2023 April 18. | ||||
| 
 | ||||
| This example uses the Nunjucks template format. Lume plugins support additional | ||||
| template formats, including Markdown and JSX. | ||||
| @ -156,8 +156,16 @@ curl -L -o _data/pres.numbers https://sheetjs.com/pres.numbers | ||||
| deno task lume --serve | ||||
| ``` | ||||
| 
 | ||||
| To verify it works, access http://localhost:3000 from your web browser. | ||||
| Adding a new row and saving `pres.numbers` should refresh the data | ||||
| To verify it works, access http://localhost:3000 from your web browser. Open | ||||
| `_data/pres.numbers` and add a new row to the bottom of the sheet. The page will | ||||
| refresh and show the new contents. | ||||
| 
 | ||||
| :::caution | ||||
| 
 | ||||
| There is a known bug with Deno hot reloading.  If the page does not refresh | ||||
| automatically, upgrade with `deno upgrade` and restart the development server. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| 5) Stop the server (press `CTRL+C` in the terminal window) and run | ||||
| 
 | ||||
|  | ||||
| @ -143,66 +143,7 @@ types and other database minutiae. | ||||
| 
 | ||||
| **Knex** | ||||
| 
 | ||||
| The result of a `SELECT` statement is an array of objects: | ||||
| 
 | ||||
| ```js | ||||
| const aoo = await connection.select("*").from("DataTable"); | ||||
| const worksheet = XLSX.utils.json_to_sheet(aoa); | ||||
| ``` | ||||
| 
 | ||||
| Knex wraps primitive types when creating a table. `generate_sql` takes a `knex` | ||||
| connection object and uses the API: | ||||
| 
 | ||||
| <details><summary><b>Generating a Table</b> (click to show)</summary> | ||||
| 
 | ||||
| ```js | ||||
| // define mapping between determined types and Knex types | ||||
| const PG = { "n": "float", "s": "text", "b": "boolean" }; | ||||
| 
 | ||||
| async function generate_sql(knex, ws, wsname) { | ||||
| 
 | ||||
|   // generate an array of objects from the data | ||||
|   const aoo = XLSX.utils.sheet_to_json(ws); | ||||
| 
 | ||||
|   // types will map column headers to types, while hdr holds headers in order | ||||
|   const types = {}, hdr = []; | ||||
| 
 | ||||
|   // loop across each row object | ||||
|   aoo.forEach(row => | ||||
|     // Object.entries returns a row of [key, value] pairs.  Loop across those | ||||
|     Object.entries(row).forEach(([k,v]) => { | ||||
| 
 | ||||
|       // If this is first time seeing key, mark unknown and append header array | ||||
|       if(!types[k]) { types[k] = "?"; hdr.push(k); } | ||||
| 
 | ||||
|       // skip null and undefined | ||||
|       if(v == null) return; | ||||
| 
 | ||||
|       // check and resolve type | ||||
|       switch(typeof v) { | ||||
|         case "string": // strings are the broadest type | ||||
|           types[k] = "s"; break; | ||||
|         case "number": // if column is not string, number is the broadest type | ||||
|           if(types[k] != "s") types[k] = "n"; break; | ||||
|         case "boolean": // only mark boolean if column is unknown or boolean | ||||
|           if("?b".includes(types[k])) types[k] = "b"; break; | ||||
|         default: types[k] = "s"; break; // default to string type | ||||
|       } | ||||
|     }) | ||||
|   ); | ||||
| 
 | ||||
|   await knex.schema.dropTableIfExists(wsname); | ||||
|   await knex.schema.createTable(wsname, (table) => { hdr.forEach(h => { table[PG[types[h]] || "text"](h); }); }); | ||||
|   for(let i = 0; i < aoo.length; ++i) { | ||||
|     if(!aoo[i] || !Object.keys(aoo[i]).length) continue; | ||||
|     try { await knex.insert(aoo[i]).into(wsname); } catch(e) {} | ||||
|   } | ||||
|   return knex; | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| **[The exposition has been moved to a separate page.](/docs/demos/data/knex)** | ||||
| 
 | ||||
| ### Other SQL Databases | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										170
									
								
								docz/docs/03-demos/07-data/14-knex.md
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										170
									
								
								docz/docs/03-demos/07-data/14-knex.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,170 @@ | ||||
| --- | ||||
| title: Knex SQL Builder | ||||
| pagination_prev: demos/desktop/index | ||||
| pagination_next: demos/local/index | ||||
| sidebar_custom_props: | ||||
|   sql: true | ||||
| --- | ||||
| 
 | ||||
| :::note | ||||
| 
 | ||||
| This demo was last tested on 2023 April 19 with Knex 2.4.2 and `better-sqlite`. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| ## Integration Details | ||||
| 
 | ||||
| #### Importing Data | ||||
| 
 | ||||
| `sheet_to_json` generates an array of objects. An `INSERT` statement can be | ||||
| generated from each row object using `knex.insert`: | ||||
| 
 | ||||
| ```js | ||||
| const aoo = XLSX.utils.sheet_to_json(ws); | ||||
| for(let i = 0; i < aoo.length; ++i) await knex.insert(aoo[i]).into(table_name); | ||||
| ``` | ||||
| 
 | ||||
| #### Exporting Data | ||||
| 
 | ||||
| The result of a `SELECT` statement is an array of objects: | ||||
| 
 | ||||
| ```js | ||||
| const aoo = await knex.select("*").from(table_name); | ||||
| const worksheet = XLSX.utils.json_to_sheet(aoo); | ||||
| ``` | ||||
| 
 | ||||
| ## Complete Example | ||||
| 
 | ||||
| 1) Install dependencies: | ||||
| 
 | ||||
| ```bash | ||||
| npm i --save https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz knex better-sqlite3 | ||||
| ``` | ||||
| 
 | ||||
| 2) Download the [test file](https://sheetjs.com/pres.numbers) | ||||
| 
 | ||||
| ```bash | ||||
| curl -LO https://sheetjs.com/pres.numbers | ||||
| ``` | ||||
| 
 | ||||
| 3) Save the following utility script to `sheetjsknex.js`: | ||||
| 
 | ||||
| ```js title="sheetjsknex.js" | ||||
| const XLSX = require("xlsx"); | ||||
| 
 | ||||
| // define mapping between determined types and Knex types | ||||
| const PG = { "n": "float", "s": "text", "b": "boolean" }; | ||||
| 
 | ||||
| async function ws_to_knex(knex, ws, table_name) { | ||||
| 
 | ||||
|   // generate an array of objects from the data | ||||
|   const aoo = XLSX.utils.sheet_to_json(ws); | ||||
| 
 | ||||
|   // types will map column headers to types, while hdr holds headers in order | ||||
|   const types = {}, hdr = []; | ||||
| 
 | ||||
|   // loop across each row object | ||||
|   aoo.forEach(row => | ||||
|     // Object.entries returns a row of [key, value] pairs.  Loop across those | ||||
|     Object.entries(row).forEach(([k,v]) => { | ||||
| 
 | ||||
|       // If this is first time seeing key, mark unknown and append header array | ||||
|       if(!types[k]) { types[k] = "?"; hdr.push(k); } | ||||
| 
 | ||||
|       // skip null and undefined | ||||
|       if(v == null) return; | ||||
| 
 | ||||
|       // check and resolve type | ||||
|       switch(typeof v) { | ||||
|         case "string": // strings are the broadest type | ||||
|           types[k] = "s"; break; | ||||
|         case "number": // if column is not string, number is the broadest type | ||||
|           if(types[k] != "s") types[k] = "n"; break; | ||||
|         case "boolean": // only mark boolean if column is unknown or boolean | ||||
|           if("?b".includes(types[k])) types[k] = "b"; break; | ||||
|         default: types[k] = "s"; break; // default to string type | ||||
|       } | ||||
|     }) | ||||
|   ); | ||||
| 
 | ||||
|   await knex.schema.dropTableIfExists(table_name); | ||||
| 
 | ||||
|   // use column type info to create table | ||||
|   await knex.schema.createTable(table_name, (table) => { hdr.forEach(h => { table[PG[types[h]] || "text"](h); }); }); | ||||
| 
 | ||||
|   // insert each non-empty row object | ||||
|   for(let i = 0; i < aoo.length; ++i) { | ||||
|     if(!aoo[i] || !Object.keys(aoo[i]).length) continue; | ||||
|     try { await knex.insert(aoo[i]).into(table_name); } catch(e) {} | ||||
|   } | ||||
|   return knex; | ||||
| } | ||||
| 
 | ||||
| async function knex_to_ws(knex, table_name) { | ||||
|   const aoo = await knex.select("*").from(table_name); | ||||
|   return XLSX.utils.json_to_sheet(aoo); | ||||
| } | ||||
| 
 | ||||
| module.exports = { ws_to_knex, knex_to_ws }; | ||||
| ``` | ||||
| 
 | ||||
| 4) Save the following to `SheetJSKnexTest.js`: | ||||
| 
 | ||||
| ```js title="SheetJSKnexTest.js" | ||||
| const { ws_to_knex, knex_to_ws } = require("./sheetjsknex"); | ||||
| const Knex = require('knex'); | ||||
| 
 | ||||
| /* read file and get first worksheet */ | ||||
| const XLSX = require("xlsx"); | ||||
| const oldwb = XLSX.readFile("pres.numbers"); | ||||
| const wsname = oldwb.SheetNames[0]; | ||||
| const oldws = oldwb.Sheets[wsname]; | ||||
| 
 | ||||
| (async() => { | ||||
|   /* open connection to SheetJSKnex.db */ | ||||
|   let knex = Knex({ client: 'better-sqlite3', connection: { filename: "SheetJSKnex.db" } }); | ||||
|   try { | ||||
|     /* load data into database and close connection */ | ||||
|     await ws_to_knex(knex, oldws, "Test_Table"); | ||||
|   } finally { knex.destroy(); } | ||||
| 
 | ||||
|   /* reconnect to SheetJSKnex.db */ | ||||
|   knex = Knex({ client: 'better-sqlite3', connection: { filename: "SheetJSKnex.db" } }); | ||||
|   try { | ||||
|     /* get data from db */ | ||||
|     const aoo = await knex.select("*").from("Test_Table"); | ||||
| 
 | ||||
|     /* export to file */ | ||||
|     const newws = await knex_to_ws(knex, "Test_Table"); | ||||
|     const newwb = XLSX.utils.book_new(); | ||||
|     XLSX.utils.book_append_sheet(newwb, newws, "Export"); | ||||
|     XLSX.writeFile(newwb, "SheetJSKnex.xlsx"); | ||||
|   } finally { knex.destroy(); } | ||||
| })(); | ||||
| ``` | ||||
| 
 | ||||
| This script will read `pres.numbers` and load data into a table `Test_Table`. | ||||
| The SQLite database will be saved to `SheetJSKnex.db`. | ||||
| 
 | ||||
| After closing the connection, the script will make a new connection and export | ||||
| data to `SheetJSKnex.xlsx`. | ||||
| 
 | ||||
| 5) Run the script: | ||||
| 
 | ||||
| ```bash | ||||
| node SheetJSKnexTest.js | ||||
| ``` | ||||
| 
 | ||||
| The script will generate two artifacts: | ||||
| 
 | ||||
| `SheetJSKnex.xlsx` can be opened in a spreadsheet app or tested in the terminal: | ||||
| 
 | ||||
| ```bash | ||||
| npx xlsx-cli SheetJSKnex.xlsx | ||||
| ``` | ||||
| 
 | ||||
| `SheetJSKnex.db` can be verified with the `sqlite3` command line tool: | ||||
| 
 | ||||
| ```bash | ||||
| sqlite3 SheetJSKnex.db 'select * from Test_Table' | ||||
| ``` | ||||
| @ -258,7 +258,7 @@ console.log(utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]])); | ||||
| 
 | ||||
| ```js title="SheetJSWriteToAzure.mjs" | ||||
| import { BlobServiceClient } from "@azure/storage-blob"; | ||||
| import { read, utils } from "xlsx"; | ||||
| import { write, utils } from "xlsx"; | ||||
| 
 | ||||
| /* replace these constants */ | ||||
| const connStr = "<REPLACE WITH CONNECTION STRING>"; | ||||
|  | ||||
| @ -15,7 +15,7 @@ available as a global. A JS stub can expose methods from AppleScript scripts. | ||||
| 
 | ||||
| :::note | ||||
| 
 | ||||
| This demo was last tested on 2022 April 18 in macOS Monterey. | ||||
| This demo was last tested on 2023 April 18 in macOS Monterey. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| @ -218,7 +218,7 @@ extractResult(res) | ||||
| 
 | ||||
| on getContext() | ||||
|   set UnixPath to POSIX path of ((path to me as text) & "::") | ||||
|   set libpath to POSIX path of (UnixPath & "xlsx.shim.js") | ||||
|   set libpath to POSIX path of (UnixPath & "xlsx.stub.js") | ||||
|   set {src, err} to current application's NSString's stringWithContentsOfFile:libpath encoding:(current application's NSISOLatin1StringEncoding) |error|:(reference) | ||||
| 
 | ||||
|   set lang to current application's OSALanguage's languageForName:"JavaScript" | ||||
|  | ||||
| @ -34,7 +34,7 @@ run in the web browser, demos will include interactive examples. | ||||
| 
 | ||||
| - [`canvas-datagrid`](/docs/demos/grid/cdg) | ||||
| - [`x-spreadsheet`](/docs/demos/grid/xs) | ||||
| - [`react-data-grid`](/docs/demos/grid#react-data-grid) | ||||
| - [`react-data-grid`](/docs/demos/grid/rdg) | ||||
| - [`glide-data-grid`](/docs/demos/grid/gdg) | ||||
| - [`vue3-table-lite`](/docs/demos/grid#vue3-table-lite) | ||||
| - [`angular-ui-grid`](/docs/demos/grid#angular-ui-grid) | ||||
| @ -70,6 +70,8 @@ run in the web browser, demos will include interactive examples. | ||||
| - [`Excel JavaScript API`](/docs/demos/extensions/excelapi) | ||||
| - [`ExtendScript for Adobe Apps`](/docs/demos/extensions/extendscript) | ||||
| - [`Chrome and Chromium Extensions`](/docs/demos/extensions/chromium) | ||||
| - [`Google Sheets + Apps Script`](/docs/demos/extensions/gsheet) | ||||
| - [`AppleScript and OSA`](/docs/demos/extensions/osa) | ||||
| 
 | ||||
| ### Cloud Platforms | ||||
| 
 | ||||
| @ -116,10 +118,13 @@ run in the web browser, demos will include interactive examples. | ||||
| ### Other Programming Languages | ||||
| 
 | ||||
| - [`JavaScript Engines`](/docs/demos/engines) | ||||
| - [`Duktape (C)`](/docs/demos/engines/duktape) | ||||
| - [`Duktape (C / Perl)`](/docs/demos/engines/duktape) | ||||
| - [`JavaScriptCore (Swift)`](/docs/demos/engines/jsc) | ||||
| - [`Rhino (Java)`](/docs/demos/engines/rhino) | ||||
| - [`Nashorn (Java)`](/docs/demos/engines/nashorn) | ||||
| - [`Goja (Go)`](/docs/demos/engines/goja) | ||||
| - [`ChakraCore (C++)`](/docs/demos/engines/chakra) | ||||
| - [`QuickJS (C)`](/docs/demos/engines/quickjs) | ||||
| - [`ExecJS (Ruby)`](/docs/demos/engines/rb) | ||||
| - [`JavaScript::Engine (Perl)`](/docs/demos/engines/perl) | ||||
| 
 | ||||
|  | ||||
| @ -605,7 +605,7 @@ previewing and modifying structured data in the web browser. | ||||
|   </TabItem> | ||||
|   <TabItem value="react" label="React"> | ||||
| 
 | ||||
| [`react-data-grid`](/docs/demos/grid#react-data-grid) is a data grid built for | ||||
| [`react-data-grid`](/docs/demos/grid/rdg) is a data grid built for | ||||
| React. It uses two properties: `rows` of data objects and `columns` which | ||||
| describe the columns.  The grid API can play nice with an array of arrays. | ||||
| 
 | ||||
| @ -616,6 +616,8 @@ import { useEffect, useState } from "react"; | ||||
| import DataGrid from "react-data-grid"; | ||||
| import { read, utils } from "xlsx"; | ||||
| 
 | ||||
| import 'react-data-grid/lib/styles.css'; | ||||
| 
 | ||||
| const url = "https://oss.sheetjs.com/test_files/RkNumber.xls"; | ||||
| 
 | ||||
| export default function App() { | ||||
|  | ||||
| @ -2,6 +2,7 @@ import React, { useEffect, useState, ChangeEvent } from "react"; | ||||
| import DataGrid, { textEditor, Column } from "react-data-grid"; | ||||
| import { read, utils, WorkSheet, writeFile } from "xlsx"; | ||||
| 
 | ||||
| import 'react-data-grid/lib/styles.css'; | ||||
| import './App.css'; | ||||
| 
 | ||||
| type DataSet = { [index: string]: WorkSheet; }; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user