forked from sheetjs/docs.sheetjs.com
		
	Demo refresh
This commit is contained in:
		
							parent
							
								
									50c4139bb4
								
							
						
					
					
						commit
						19b9f5b122
					
				| @ -292,8 +292,8 @@ | ||||
|     <Cell><Data ss:Type="String">Python</Data></Cell> | ||||
|     <Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell> | ||||
|     <Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell> | ||||
|     <Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell> | ||||
|     <Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell> | ||||
|     <Cell ss:StyleID="s16"/> | ||||
|     <Cell ss:StyleID="s16"/> | ||||
|     <Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell> | ||||
|     <Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell> | ||||
|    </Row> | ||||
|  | ||||
| @ -122,7 +122,7 @@ This demo was last tested in the following deployments: | ||||
| | Architecture | BunJS    | Date       | | ||||
| |:-------------|:---------|:-----------| | ||||
| | `darwin-x64` | `1.1.39` | 2024-12-17 | | ||||
| | `darwin-arm` | `1.2.2`  | 2025-02-16 | | ||||
| | `darwin-arm` | `1.2.7`  | 2025-03-30 | | ||||
| | `win11-x64`  | `1.1.42` | 2024-12-22 | | ||||
| | `win11-arm`  | `1.2.3`  | 2025-02-23 | | ||||
| | `linux-x64`  | `1.1.40` | 2024-12-19 | | ||||
|  | ||||
| @ -40,8 +40,8 @@ This browser demo was tested in the following environments: | ||||
| 
 | ||||
| | Browser     | Date       | | ||||
| |:------------|:-----------| | ||||
| | Chrome 126  | 2024-06-21 | | ||||
| | Safari 17.4 | 2024-06-20 | | ||||
| | Chrome 133  | 2025-03-30 | | ||||
| | Safari 18.3 | 2025-03-30 | | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
|  | ||||
| @ -41,7 +41,7 @@ This demo was tested in the following deployments: | ||||
| | Architecture | JS Engine       | Pandas | Python | Date       | | ||||
| |:-------------|:----------------|:-------|:-------|:-----------| | ||||
| | `darwin-x64` | Duktape `2.7.0` | 2.2.3  | 3.13.1 | 2024-12-31 | | ||||
| | `darwin-arm` | Duktape `2.7.0` | 2.2.2  | 3.12.3 | 2024-06-30 | | ||||
| | `darwin-arm` | Duktape `2.7.0` | 2.2.3  | 3.13.2 | 2025-03-30 | | ||||
| | `win11-x64`  | Duktape `2.7.0` | 2.2.3  | 3.11.8 | 2024-12-21 | | ||||
| | `win11-arm`  | Duktape `2.7.0` | 2.2.3  | 3.13.2 | 2025-02-23 | | ||||
| | `linux-x64`  | Duktape `2.7.0` | 1.5.3  | 3.11.7 | 2025-01-01 | | ||||
| @ -528,7 +528,7 @@ This demo was tested in the following deployments: | ||||
| | Architecture | JS Engine       | Polars  | Python | Date       | | ||||
| |:-------------|:----------------|:--------|:-------|:-----------| | ||||
| | `darwin-x64` | Duktape `2.7.0` | 1.18.0  | 3.13.1 | 2024-12-31 | | ||||
| | `darwin-arm` | Duktape `2.7.0` | 0.20.31 | 3.12.3 | 2024-06-30 | | ||||
| | `darwin-arm` | Duktape `2.7.0` | 1.26.0  | 3.13.2 | 2025-03-30 | | ||||
| | `win11-x64`  | Duktape `2.7.0` | 1.17.1  | 3.11.8 | 2024-12-21 | | ||||
| | `win11-arm`  | Duktape `2.7.0` | 1.23.0  | 3.13.2 | 2025-02-23 | | ||||
| | `linux-x64`  | Duktape `2.7.0` | 1.18.0  | 3.11.7 | 2025-01-01 | | ||||
|  | ||||
| @ -128,9 +128,9 @@ function exportFile() { | ||||
|     <td>{p.Index}</td> | ||||
|   </tr>{/each} | ||||
|   <!-- highlight-end --> | ||||
|   </tbody><tfoot><td colSpan={2}> | ||||
|   </tbody><tfoot><tr><td colSpan={2}> | ||||
|   <button on:click={exportFile}>Export XLSX</button> | ||||
|   </td></tfoot></table> | ||||
|   </td></tfoot></tr></table> | ||||
| </main> | ||||
| ``` | ||||
| 
 | ||||
| @ -143,7 +143,7 @@ This demo was tested in the following environments: | ||||
| 
 | ||||
| | SvelteJS | ViteJS   | Date       | | ||||
| |:---------|:---------|:-----------| | ||||
| | `4.2.18` | `5.2.13` | 2024-06-07 | | ||||
| | `5.25.3` | `6.2.3`  | 2025-03-30 | | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| @ -170,7 +170,9 @@ The page will refresh and show a table with an Export button.  Click the button | ||||
| and the page will attempt to download `SheetJSSvelteAoA.xlsx`. There may be a | ||||
| delay since Vite will try to optimize the SheetJS library on the fly. | ||||
| 
 | ||||
| 5) Build the site: | ||||
| 5) Stop the server (press <kbd>CTRL</kbd>+<kbd>C</kbd> in the terminal window). | ||||
| 
 | ||||
| 6) Build the site: | ||||
| 
 | ||||
| ```bash | ||||
| npm run build | ||||
| @ -178,10 +180,10 @@ npm run build | ||||
| 
 | ||||
| The generated site will be placed in the `dist` folder. | ||||
| 
 | ||||
| 6) Start a local web server: | ||||
| 7) Start a local web server: | ||||
| 
 | ||||
| ```bash | ||||
| npx http-server dist | ||||
| npx -y http-server dist | ||||
| ``` | ||||
| 
 | ||||
| Access the displayed URL (typically `http://localhost:8080`) with a web browser | ||||
| @ -243,7 +245,7 @@ This demo was tested in the following environments: | ||||
| 
 | ||||
| | SvelteJS | ViteJS   | Date       | | ||||
| |:---------|:---------|:-----------| | ||||
| | `4.2.18` | `5.2.13` | 2024-06-07 | | ||||
| | `5.25.3` | `6.2.3`  | 2025-03-30 | | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| @ -270,7 +272,9 @@ The page will refresh and show a table with an Export button.  Click the button | ||||
| and the page will attempt to download `SheetJSSvelteHTML.xlsx`. There may be a | ||||
| delay since Vite will try to optimize the SheetJS library on the fly. | ||||
| 
 | ||||
| 5) Build the site: | ||||
| 5) Stop the server (press <kbd>CTRL</kbd>+<kbd>C</kbd> in the terminal window). | ||||
| 
 | ||||
| 6) Build the site: | ||||
| 
 | ||||
| ```bash | ||||
| npm run build | ||||
| @ -278,10 +282,10 @@ npm run build | ||||
| 
 | ||||
| The generated site will be placed in the `dist` folder. | ||||
| 
 | ||||
| 6) Start a local web server: | ||||
| 7) Start a local web server: | ||||
| 
 | ||||
| ```bash | ||||
| npx http-server dist | ||||
| npx -y http-server dist | ||||
| ``` | ||||
| 
 | ||||
| Access the displayed URL (typically `http://localhost:8080`) with a web browser | ||||
|  | ||||
| @ -36,8 +36,8 @@ This demo was tested in the following environments: | ||||
| 
 | ||||
| | Browser      | Version           | Date       | | ||||
| |:-------------|:------------------|:-----------| | ||||
| | Chromium 125 | `1.8.2`  (latest) | 2024-06-09 | | ||||
| | Chromium 125 | `1.2.32` (legacy) | 2024-06-09 | | ||||
| | Chromium 133 | `1.8.2`  (latest) | 2025-03-30 | | ||||
| | Chromium 133 | `1.2.32` (legacy) | 2025-03-30 | | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| @ -288,8 +288,13 @@ app.controller('sheetjs', function($scope, $http) { | ||||
| </html>`} | ||||
| </CodeBlock> | ||||
| 
 | ||||
| 2) Start a local web server with `npx http-server .` and access the displayed | ||||
| URL with a web browser (typically `http://localhost:8080`) | ||||
| 2) Start a local web server: | ||||
| 
 | ||||
| ```bash | ||||
| npx -y http-server . | ||||
| ``` | ||||
| 
 | ||||
| Access the displayed URL with a web browser (typically `http://localhost:8080`) | ||||
| 
 | ||||
| When the page loads, the app will fetch https://docs.sheetjs.com/pres.xlsx and | ||||
| store an array of objects in state. When the "Export Table" button is clicked, | ||||
| @ -387,8 +392,13 @@ app.controller('sheetjs', function($scope, $http) { | ||||
| </html>`} | ||||
| </CodeBlock> | ||||
| 
 | ||||
| 2) Start a local web server with `npx http-server .` and access the displayed | ||||
| URL with a web browser (typically `http://localhost:8080`) | ||||
| 2) Start a local web server: | ||||
| 
 | ||||
| ```bash | ||||
| npx -y http-server . | ||||
| ``` | ||||
| 
 | ||||
| Access the displayed URL with a web browser (typically `http://localhost:8080`) | ||||
| 
 | ||||
| When the page loads, the app will fetch https://docs.sheetjs.com/pres.xlsx and | ||||
| store the HTML string in state. When the "Export Table" button is clicked, a | ||||
|  | ||||
| @ -76,7 +76,7 @@ This demo was tested in the following environments: | ||||
| 
 | ||||
| | Platform     | Date       | | ||||
| |:-------------|:-----------| | ||||
| | Chromium 125 | 2024-06-08 | | ||||
| | Chromium 133 | 2025-03-30 | | ||||
| 
 | ||||
| Demos exclusively using Dojo Core were tested using Dojo Toolkit `1.17.3`. | ||||
| 
 | ||||
|  | ||||
| @ -41,9 +41,10 @@ This demo was tested in the following environments: | ||||
| 
 | ||||
| | ViteJS   | Date       | | ||||
| |:---------|:-----------| | ||||
| | `5.4.10` | 2024-11-04 | | ||||
| | `4.5.5`  | 2024-11-04 | | ||||
| | `3.2.11` | 2024-11-04 | | ||||
| | `6.2.3`  | 2025-03-30 | | ||||
| | `5.4.15` | 2025-03-30 | | ||||
| | `4.5.10` | 2025-03-30 | | ||||
| | `3.2.11` | 2025-03-30 | | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
|  | ||||
| @ -90,8 +90,8 @@ Each browser demo was tested in the following environments: | ||||
| 
 | ||||
| | Browser     | Date       | | ||||
| |:------------|:-----------| | ||||
| | Chrome 126  | 2024-06-19 | | ||||
| | Safari 17.3 | 2024-06-19 | | ||||
| | Chrome 133  | 2025-03-30 | | ||||
| | Safari 18.3 | 2025-03-30 | | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| @ -411,9 +411,9 @@ This demo was tested in the following environments: | ||||
| | `12.22.12` | 2024-06-21 |                                | | ||||
| | `14.21.3`  | 2024-06-21 |                                | | ||||
| | `16.20.2`  | 2024-06-21 |                                | | ||||
| | `18.20.3`  | 2024-06-21 |                                | | ||||
| | `20.15.0`  | 2024-06-21 |                                | | ||||
| | `22.3.0`   | 2024-06-21 |                                | | ||||
| | `18.20.8`  | 2025-03-30 |                                | | ||||
| | `20.18.0`  | 2025-03-30 |                                | | ||||
| | `22.14.0`  | 2025-03-30 |                                | | ||||
| 
 | ||||
| The `NODE_TLS_REJECT_UNAUTHORIZED` workaround sets the value to `'0'`: | ||||
| 
 | ||||
| @ -484,9 +484,9 @@ This demo was tested in the following environments: | ||||
| 
 | ||||
| | NodeJS     | Date       | | ||||
| |:-----------|:-----------| | ||||
| | `18.20.3`  | 2024-06-21 | | ||||
| | `20.15.0`  | 2024-06-21 | | ||||
| | `22.3.0`   | 2024-06-21 | | ||||
| | `18.20.8`  | 2025-03-30 | | ||||
| | `20.18.0`  | 2025-03-30 | | ||||
| | `22.14.0`  | 2025-03-30 | | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| @ -579,9 +579,9 @@ This demo was tested in the following environments: | ||||
| | `12.22.12` | 2024-06-21 |                                | | ||||
| | `14.21.3`  | 2024-06-21 |                                | | ||||
| | `16.20.2`  | 2024-06-21 |                                | | ||||
| | `18.20.3`  | 2024-06-21 |                                | | ||||
| | `20.15.0`  | 2024-06-21 |                                | | ||||
| | `22.3.0`   | 2024-06-21 |                                | | ||||
| | `18.20.8`  | 2025-03-30 |                                | | ||||
| | `20.18.0`  | 2025-03-30 |                                | | ||||
| | `22.14.0`  | 2025-03-30 |                                | | ||||
| 
 | ||||
| The `NODE_TLS_REJECT_UNAUTHORIZED` workaround sets the value to `'0'`: | ||||
| 
 | ||||
| @ -651,9 +651,9 @@ This demo was tested in the following environments: | ||||
| | `12.22.12` | 1.7.2  | 2024-06-21 | | ||||
| | `14.21.3`  | 1.7.2  | 2024-06-21 | | ||||
| | `16.20.2`  | 1.7.2  | 2024-06-21 | | ||||
| | `18.20.3`  | 1.7.2  | 2024-06-21 | | ||||
| | `20.15.0`  | 1.7.2  | 2024-06-21 | | ||||
| | `22.3.0`   | 1.7.2  | 2024-06-21 | | ||||
| | `18.20.8`  | 1.8.4  | 2025-03-30 | | ||||
| | `20.18.0`  | 1.8.4  | 2025-03-30 | | ||||
| | `22.14.0`  | 1.8.4  | 2025-03-30 | | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| @ -663,7 +663,7 @@ This demo was tested in the following environments: | ||||
| 1) Install the [NodeJS module](/docs/getting-started/installation/nodejs) | ||||
| 
 | ||||
| <CodeBlock language="bash">{`\ | ||||
| npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz axios@1.7.2`} | ||||
| npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz axios@1.8.4`} | ||||
| </CodeBlock> | ||||
| 
 | ||||
| 2) Save the following to `SheetJSAxios.js`: | ||||
|  | ||||
| @ -135,8 +135,8 @@ Each browser demo was tested in the following environments: | ||||
| 
 | ||||
| | Browser     | Date       | | ||||
| |:------------|:-----------| | ||||
| | Chrome 126  | 2024-06-19 | | ||||
| | Safari 17.3 | 2024-06-19 | | ||||
| | Chrome 133  | 2025-03-30 | | ||||
| | Safari 18.3 | 2025-03-30 | | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
|  | ||||
| @ -169,7 +169,7 @@ export default defineConfig({ | ||||
|   plugins: [ | ||||
|     { // this plugin handles ?sheetjs tags | ||||
|       name: "vite-sheet", | ||||
|       transform(code, id) { | ||||
|       transform(_code, id) { | ||||
|         if(!id.match(/\?sheetjs$/)) return; | ||||
|         var wb = read(readFileSync(id.replace(/\?sheetjs$/, ""))); | ||||
|         var data = utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]); | ||||
| @ -243,7 +243,7 @@ export default defineConfig({ | ||||
|   plugins: [ | ||||
|     { // this plugin handles ?html tags | ||||
|       name: "vite-sheet-html", | ||||
|       transform(code, id) { | ||||
|       transform(_code, id) { | ||||
|         if(!id.match(/\?html/)) return; | ||||
|         var wb = read(readFileSync(id.replace(/\?html/, ""))); | ||||
|         var html = utils.sheet_to_html(wb.Sheets[wb.SheetNames[0]]); | ||||
| @ -309,7 +309,7 @@ export default defineConfig({ | ||||
|   plugins: [ | ||||
|     { // this plugin handles ?b64 tags | ||||
|       name: "vite-b64-plugin", | ||||
|       transform(code, id) { | ||||
|       transform(_code, id) { | ||||
|         if(!id.match(/\?b64$/)) return; | ||||
|         var path = id.replace(/\?b64/, ""); | ||||
|         var data = readFileSync(path, "base64"); | ||||
| @ -356,10 +356,11 @@ This demo was tested in the following environments: | ||||
| 
 | ||||
| | ViteJS   | Date       | | ||||
| |:---------|:-----------| | ||||
| | `5.2.12` | 2024-06-02 | | ||||
| | `4.5.3`  | 2024-06-02 | | ||||
| | `3.2.10` | 2024-06-02 | | ||||
| | `2.9.18` | 2024-06-02 | | ||||
| | `6.2.3`  | 2025-03-30 | | ||||
| | `5.4.15` | 2025-03-30 | | ||||
| | `4.5.10` | 2025-03-30 | | ||||
| | `3.2.11` | 2025-03-30 | | ||||
| | `2.9.18` | 2025-03-30 | | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
|  | ||||
| @ -53,15 +53,15 @@ This demo was tested in the following environments: | ||||
| 
 | ||||
| | OS         | Device              | Config | Date       | | ||||
| |:-----------|:--------------------|:-------|:-----------| | ||||
| | Android 30 | NVIDIA Shield       | A      | 2024-05-30 | | ||||
| | iOS 15.1   | iPad Pro            | A      | 2024-05-30 | | ||||
| | Android 34 | NVIDIA Shield       | B      | 2025-03-30 | | ||||
| | iOS 15.6   | iPhone 13 Pro Max   | B      | 2025-03-30 | | ||||
| 
 | ||||
| **Simulators** | ||||
| 
 | ||||
| | OS         | Device              | Config | Dev Platform | Date       | | ||||
| |:-----------|:--------------------|:-------|:-------------|:-----------| | ||||
| | Android 34 | Pixel 3a            | A      | `darwin-arm` | 2024-05-30 | | ||||
| | iOS 17.5   | iPhone SE (3rd gen) | A      | `darwin-arm` | 2024-05-30 | | ||||
| | Android 34 | Pixel 3a            | B      | `darwin-arm` | 2025-03-30 | | ||||
| | iOS 18.2   | iPhone SE (3rd gen) | B      | `darwin-arm` | 2025-03-30 | | ||||
| 
 | ||||
| <details> | ||||
|   <summary><b>Configurations</b> (click to show)</summary> | ||||
| @ -72,6 +72,12 @@ Configuration A: | ||||
| - Cordova: `cordova-lib@12.0.1`, `android 13.0.0, ios 7.1.0` | ||||
| - File Integration: `@awesome-cordova-plugins/file` version `6.7.0` | ||||
| 
 | ||||
| Configuration B: | ||||
| 
 | ||||
| - Ionic: `@ionic/angular 8.5.2`, `@ionic/angular-toolkit 12.1.1` | ||||
| - Cordova: `cordova-lib@12.0.2`, `android 14.0.0, ios 7.1.1` | ||||
| - File Integration: `@awesome-cordova-plugins/file` version `6.16.0` | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| ::: | ||||
| @ -81,15 +87,15 @@ Configuration A: | ||||
| Before starting this demo, manually disable telemetry: | ||||
| 
 | ||||
| ```bash | ||||
| npx @ionic/cli config set -g telemetry false | ||||
| npx @capacitor/cli telemetry off | ||||
| npx -y @ionic/cli config set -g telemetry false | ||||
| npx -y @capacitor/cli telemetry off | ||||
| ``` | ||||
| 
 | ||||
| To verify telemetry was disabled: | ||||
| 
 | ||||
| ```bash | ||||
| npx @ionic/cli config get -g telemetry | ||||
| npx @capacitor/cli telemetry | ||||
| npx -y @ionic/cli config get -g telemetry | ||||
| npx -y @capacitor/cli telemetry | ||||
| ``` | ||||
| 
 | ||||
| ::: | ||||
| @ -223,7 +229,12 @@ known location. After writing, an alert will display the location of the file. | ||||
| 
 | ||||
| ### Platform Setup | ||||
| 
 | ||||
| 0) Disable telemetry as noted in the warning. | ||||
| 0) Disable telemetry: | ||||
| 
 | ||||
| ```bash | ||||
| npx -y @ionic/cli config set -g telemetry false | ||||
| npx -y @capacitor/cli telemetry off | ||||
| ``` | ||||
| 
 | ||||
| 1) Follow the official instructions for iOS and Android development[^9]. | ||||
| 
 | ||||
| @ -262,7 +273,7 @@ When asked to select `NgModules` or `Standalone Components`, select `NgModules` | ||||
| 
 | ||||
| If a prompt asks to confirm Cordova use, enter <kbd>Y</kbd> to continue. | ||||
| 
 | ||||
| If a prompt asks about creating an Ionic account, enter <kbd>N</kbd> to opt out. | ||||
| If a prompt asks to create an Ionic account, enter <kbd>N</kbd> to opt out. | ||||
| 
 | ||||
| :::caution pass | ||||
| 
 | ||||
| @ -284,28 +295,9 @@ cd .. | ||||
| ```bash | ||||
| cd SheetJSIonic | ||||
| ionic cordova plugin add cordova-plugin-file | ||||
| ionic cordova platform add android --confirm | ||||
| ionic cordova platform add ios --confirm | ||||
| npm i --save @awesome-cordova-plugins/core @awesome-cordova-plugins/file @ionic/cordova-builders | ||||
| ``` | ||||
| 
 | ||||
| :::note pass | ||||
| 
 | ||||
| If `cordova-plugin-file` is added before the platforms, installation may fail: | ||||
| 
 | ||||
| ``` | ||||
| CordovaError: Could not load API for ios project | ||||
| ``` | ||||
| 
 | ||||
| This can be resolved by removing and reinstalling the `ios` platform: | ||||
| 
 | ||||
| ```bash | ||||
| ionic cordova platform rm ios | ||||
| ionic cordova platform add ios --confirm | ||||
| ``` | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| :::caution pass | ||||
| 
 | ||||
| If the `npm i` step fails due to `rxjs` resolution, add the highlighted lines | ||||
| @ -375,10 +367,144 @@ curl.exe -o src/app/home/home.page.ts -L https://docs.sheetjs.com/ionic/home.pag | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| ### Android | ||||
| 
 | ||||
| 8) Add the Android platform to the project: | ||||
| 
 | ||||
| ```bash | ||||
| ionic cordova platform add android --confirm | ||||
| npm i --save cordova-android | ||||
| ``` | ||||
| 
 | ||||
| 9) Enable file reading and writing in the Android app. | ||||
| 
 | ||||
| Edit `platforms/android/app/src/main/AndroidManifest.xml` and add the following | ||||
| two lines before the `application` tag: | ||||
| 
 | ||||
| ```xml title="platforms/android/app/src/main/AndroidManifest.xml (add to file)" | ||||
|     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> | ||||
|     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> | ||||
| ``` | ||||
| 
 | ||||
| In the `application` tag, add the attribute `android:requestLegacyExternalStorage="true"`. | ||||
| 
 | ||||
| 10) Build the app and start the emulator: | ||||
| 
 | ||||
| ```bash | ||||
| ionic cordova emulate android | ||||
| ``` | ||||
| 
 | ||||
| When the app is loaded, a list of Presidents should be displayed. This list is | ||||
| dynamically generated by fetching and parsing a test file. | ||||
| 
 | ||||
| :::caution pass | ||||
| 
 | ||||
| In some test runs, `cordova build android --emulator` step failed with error: | ||||
| 
 | ||||
| ``` | ||||
| Could not find or parse valid build output file | ||||
| ``` | ||||
| 
 | ||||
| This was resolved by forcefully installing `cordova-android`: | ||||
| 
 | ||||
| ```bash | ||||
| npm i --save cordova-android | ||||
| ``` | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| :::caution pass | ||||
| 
 | ||||
| In some test runs, Ionic could not find the emulator: | ||||
| 
 | ||||
| ``` | ||||
| ERR_NO_TARGET: No target devices/emulators available. | ||||
| ``` | ||||
| 
 | ||||
| The target emulator can be found by running | ||||
| 
 | ||||
| ```bash | ||||
| avdmanager list avd | ||||
| ``` | ||||
| 
 | ||||
| In a test run, the output showed a Pixel 3a with the following details: | ||||
| 
 | ||||
| ```text | ||||
| // highlight-next-line | ||||
|     Name: Pixel_3a_API_34 | ||||
|   Device: pixel_3a (Google) | ||||
|     Path: /Users/SheetJS/.android/avd/Pixel_4_API_33.avd | ||||
| ``` | ||||
| 
 | ||||
| The Ionic command accepts a `--target` flag. Pass the emulator name: | ||||
| 
 | ||||
| ```bash | ||||
| ionic cordova emulate android --target=Pixel_3a_API_34 | ||||
| ``` | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| :::caution pass | ||||
| 
 | ||||
| In some tests, the build failed with a Gradle error: | ||||
| 
 | ||||
| ``` | ||||
| Could not find an installed version of Gradle either in Android Studio, | ||||
| or on your system to install the gradle wrapper. Please include gradle | ||||
| in your path or install Android Studio | ||||
| ``` | ||||
| 
 | ||||
| On macOS, this issue was resolved by installing Gradle with Homebrew manager: | ||||
| 
 | ||||
| ```bash | ||||
| brew install gradle | ||||
| ``` | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| :::danger pass | ||||
| 
 | ||||
| When the demo was last tested on Android, reading files worked as expected. | ||||
| However, the generated files were not externally visible from the Files app. | ||||
| 
 | ||||
| **This is a known bug with Android SDK 33 and the underlying file plugins!** | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| ### iOS | ||||
| 
 | ||||
| 8) Enable file sharing and make the documents folder visible in the iOS app. | ||||
| :::danger pass | ||||
| 
 | ||||
| **iOS testing can only be performed on Apple hardware running macOS!** | ||||
| 
 | ||||
| Xcode and iOS simulators are not available on Windows or Linux. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| 11) Add the iOS platform to the project: | ||||
| 
 | ||||
| ```bash | ||||
| ionic cordova platform add ios --confirm | ||||
| ``` | ||||
| 
 | ||||
| :::note pass | ||||
| 
 | ||||
| If `cordova-plugin-file` is added before the platforms, installation may fail: | ||||
| 
 | ||||
| ``` | ||||
| CordovaError: Could not load API for ios project | ||||
| ``` | ||||
| 
 | ||||
| This can be resolved by removing and reinstalling the `ios` platform: | ||||
| 
 | ||||
| ```bash | ||||
| ionic cordova platform rm ios | ||||
| ionic cordova platform add ios --confirm | ||||
| ``` | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| 12) Enable file sharing and make the documents folder visible in the iOS app. | ||||
| Add the following lines to `platforms/ios/SheetJSIonic/SheetJSIonic-Info.plist`: | ||||
| 
 | ||||
| ```xml title="platforms/ios/SheetJSIonic/SheetJSIonic-Info.plist (add to file)" | ||||
| @ -395,7 +521,7 @@ Add the following lines to `platforms/ios/SheetJSIonic/SheetJSIonic-Info.plist`: | ||||
| 
 | ||||
| (The root element of the document is `plist` and it contains one `dict` child) | ||||
| 
 | ||||
| 9) Build the app and start the simulator | ||||
| 13) Build the app and start the simulator | ||||
| 
 | ||||
| ```bash | ||||
| ionic cordova emulate ios | ||||
| @ -464,71 +590,86 @@ ng add @ionic/cordova-builders | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| ### Android | ||||
| ### iOS Device | ||||
| 
 | ||||
| 10) Enable file reading and writing in the Android app. | ||||
| 14) Connect an iOS device to the computer and "Trust" the device if prompted. | ||||
| 
 | ||||
| Edit `platforms/android/app/src/main/AndroidManifest.xml` and add the following | ||||
| two lines before the `application` tag: | ||||
| 15) Enable code signing for the project: | ||||
| 
 | ||||
| ```xml title="platforms/android/app/src/main/AndroidManifest.xml (add to file)" | ||||
|     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> | ||||
|     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> | ||||
| ``` | ||||
| 
 | ||||
| In the `application` tag, add the attribute `android:requestLegacyExternalStorage="true"`. | ||||
| 
 | ||||
| 11) Build the app and start the emulator | ||||
| Open the `SheetJSIonic.xcodeproj` project in Xcode: | ||||
| 
 | ||||
| ```bash | ||||
| ionic cordova emulate android | ||||
| open platforms/ios/SheetJSIonic.xcodeproj | ||||
| ``` | ||||
| 
 | ||||
| When the app is loaded, a list of Presidents should be displayed. This list is | ||||
| dynamically generated by fetching and parsing a test file. | ||||
| Select the "SheetJSIonic" project in the "Project navigator" side panel. | ||||
| 
 | ||||
| :::caution pass | ||||
| In the main panel, select "Signing & Capabilities". | ||||
| 
 | ||||
| In some test runs, `cordova build android --emulator` step failed with error: | ||||
| In the "Team" dropdown, select a certificate. | ||||
| 
 | ||||
| ``` | ||||
| Could not find or parse valid build output file | ||||
| ``` | ||||
| In the "Bundle Identifier" text box, enter `com.sheetjs.SheetJSIonic` | ||||
| 
 | ||||
| This was resolved by forcefully installing `cordova-android`: | ||||
| 16) Launch the app on the device: | ||||
| 
 | ||||
| ```bash | ||||
| npm i --save cordova-android | ||||
| ionic cordova run ios --device --verbose | ||||
| ``` | ||||
| 
 | ||||
| :::info pass | ||||
| 
 | ||||
| In the most recent test, the `native-run ios` command failed with | ||||
| 
 | ||||
| ``` | ||||
| [native-run] ERR_UNKNOWN: Path 'platforms/ios/build/device/SheetJSIonic.ipa' not found | ||||
| ``` | ||||
| 
 | ||||
| Inspecting `platforms/ios/build/`, the actual folder name was: | ||||
| 
 | ||||
| ```bash | ||||
| % ls platforms/ios/build | ||||
| #highlight-next-line | ||||
| Debug-iphoneos | ||||
| ``` | ||||
| 
 | ||||
| To force `native-run` to use the device, the name must be found by inspecting | ||||
| the output of `native-run ios --list`: | ||||
| 
 | ||||
| ```bash | ||||
| % native-run ios --list | ||||
| 
 | ||||
| Connected Devices: | ||||
| 
 | ||||
|   Name     API        Target ID | ||||
|   --------------------------------------------- | ||||
|   SheetJS  iOS 15.6   12345678-90ABCDEF12345678 | ||||
| 
 | ||||
| ``` | ||||
| 
 | ||||
| `native-run` accepts a `--device` flag. Pass the device name: | ||||
| 
 | ||||
| 
 | ||||
| ```bash | ||||
| native-run ios --app platforms/ios/build/Debug-iphoneos/SheetJSIonic.ipa --device SheetJS | ||||
| ``` | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| :::caution pass | ||||
| 17) Test the app. | ||||
| 
 | ||||
| In some tests, the build failed with a Gradle error: | ||||
| The app will fetch a file and display the contents in a table. | ||||
| 
 | ||||
| ``` | ||||
| Could not find an installed version of Gradle either in Android Studio, | ||||
| or on your system to install the gradle wrapper. Please include gradle | ||||
| in your path or install Android Studio | ||||
| ``` | ||||
| Tap "Export Data" to create a file. To find the file, switch to the "Files" app | ||||
| and browse "On My iPhone" > "SheetJSIonic". There should be a new spreadsheet | ||||
| named "SheetJSIonic". | ||||
| 
 | ||||
| On macOS, this issue was resolved by installing Gradle with Homebrew manager: | ||||
| Switch to the "Numbers" app and open that file. Tap "EDIT" to make changes. | ||||
| Change cell A7 to "SheetJS Dev" and cell B7 to 47. Tap "Done" and close the app. | ||||
| 
 | ||||
| ```bash | ||||
| brew install gradle | ||||
| ``` | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| :::danger pass | ||||
| 
 | ||||
| When the demo was last tested on Android, reading files worked as expected. | ||||
| However, the generated files were not externally visible from the Files app. | ||||
| 
 | ||||
| **This is a known bug with Android SDK 33 and the underlying file plugins!** | ||||
| 
 | ||||
| ::: | ||||
| Switch back to "SheetJSIonic" and tap "Import Data". Tap "Choose Files" in the | ||||
| popup. Tap "Browse" in the bottom of the sheet. Navigate to "On My iPhone" > | ||||
| "SheetJSIonic" and tap the new "SheetJSIonic" spreadsheet. The screen will show | ||||
| the file with the new line. | ||||
| 
 | ||||
| [^1]: See ["Array of Arrays" in the API reference](/docs/api/utilities/array#array-of-arrays) | ||||
| [^2]: See [`ion-grid`](https://ionicframework.com/docs/api/grid) in the Ionic documentation. | ||||
|  | ||||
| @ -53,8 +53,8 @@ This demo was tested in the following environments: | ||||
| |:-----------|:--------------------|:------------------|:-------------|:-----------| | ||||
| | Android 35 | Pixel 9 Pro         | `6.2.0` / `6.0.3` | `darwin-x64` | 2025-01-19 | | ||||
| | iOS 18.2   | iPhone 16 Pro Max   | `6.2.0` / `6.0.3` | `darwin-x64` | 2025-01-19 | | ||||
| | Android 34 | Pixel 3a            | `6.0.0` / `6.0.0` | `darwin-arm` | 2024-06-02 | | ||||
| | iOS 17.5   | iPhone 15 Pro Max   | `6.0.0` / `6.0.0` | `darwin-arm` | 2024-06-02 | | ||||
| | Android 34 | Pixel 3a            | `7.1.0` / `7.0.0` | `darwin-arm` | 2025-03-30 | | ||||
| | iOS 18.2   | iPhone 16 Pro Max   | `7.1.0` / `7.0.0` | `darwin-arm` | 2025-03-30 | | ||||
| | Android 35 | Pixel 9             | `6.2.0` / `6.0.2` | `win11-x64`  | 2024-12-21 | | ||||
| | Android 35 | Pixel 9             | `6.2.0` / `6.0.2` | `linux-x64`  | 2025-01-02 | | ||||
| 
 | ||||
| @ -438,9 +438,8 @@ picker for saving the file. Select the `sheetjs-cap` folder and tap "Save". If | ||||
| prompted to "Replace Existing Items?", tap "Replace". | ||||
| 
 | ||||
| Switch back to the app and tap "Choose File". Tap "Choose File" in the popup. | ||||
| 
 | ||||
| Tap on "Choose File" in the app and "Choose File" in the popup. In the picker, | ||||
| tap "Recents" and select the newest `SheetJSCap` file. The table will refresh. | ||||
| In the picker, tap "Recents" and select the newest `SheetJSCap` file. The table | ||||
| will refresh with the new data. | ||||
| 
 | ||||
| ### Android Device | ||||
| 
 | ||||
|  | ||||
| @ -208,7 +208,7 @@ This demo was tested in the following environments: | ||||
| | OS and Version | Architecture | Electron | Date       | | ||||
| |:---------------|:-------------|:---------|:-----------| | ||||
| | macOS 15.2     | `darwin-x64` | `33.2.1` | 2024-12-31 | | ||||
| | macOS 14.5     | `darwin-arm` | `30.0.8` | 2024-05-28 | | ||||
| | macOS 14.5     | `darwin-arm` | `35.1.2` | 2025-03-38 | | ||||
| | Windows 11     | `win11-x64`  | `33.2.1` | 2025-02-11 | | ||||
| | Windows 11     | `win11-arm`  | `33.2.1` | 2025-02-23 | | ||||
| | Linux (HoloOS) | `linux-x64`  | `33.2.1` | 2025-01-02 | | ||||
| @ -361,7 +361,7 @@ and select `pres.numbers`. | ||||
| ## Electron Breaking Changes | ||||
| 
 | ||||
| The first version of this demo used Electron `1.7.5`. The current demo includes | ||||
| the required changes for Electron `33.2.1`. | ||||
| the required changes for Electron `35.1.2`. | ||||
| 
 | ||||
| There are no Electron-specific workarounds in the library, but Electron broke | ||||
| backwards compatibility multiple times.  A summary of changes is noted below. | ||||
|  | ||||
| @ -122,7 +122,7 @@ This demo was tested in the following environments: | ||||
| | OS and Version | Architecture | NW.js    | Date       | Notes                | | ||||
| |:---------------|:-------------|:---------|:-----------|:---------------------| | ||||
| | macOS 15.2     | `darwin-x64` | `0.94.0` | 2024-12-31 |                      | | ||||
| | macOS 14.5     | `darwin-arm` | `0.88.0` | 2024-05-28 |                      | | ||||
| | macOS 14.5     | `darwin-arm` | `0.94.0` | 2025-03-30 |                      | | ||||
| | Windows 11     | `win11-x64`  | `0.94.0` | 2024-12-19 |                      | | ||||
| | Windows 11     | `win11-arm`  | `0.94.0` | 2025-02-23 |                      | | ||||
| | Linux (HoloOS) | `linux-x64`  | `0.89.0` | 2025-01-10 |                      | | ||||
| @ -225,6 +225,7 @@ testing, version `4.11.6` correctly generated the standalone application. | ||||
| | Architecture | Command                                                       | | ||||
| |:-------------|:--------------------------------------------------------------| | ||||
| | `darwin-x64` | `open ../out/sheetjs-nwjs.app`                                | | ||||
| | `darwin-arm` | `open ../out/sheetjs-nwjs.app`                                | | ||||
| | `win11-x64`  | `..\out\sheetjs-nwjs.exe`                                     | | ||||
| | `win11-arm`  | `..\out\sheetjs-nwjs.exe`                                     | | ||||
| | `linux-x64`  | `../out/sheetjs-nwjs`                                         | | ||||
|  | ||||
| @ -295,14 +295,14 @@ async function exportFile(table_element) { | ||||
| 
 | ||||
| This demo was tested in the following environments: | ||||
| 
 | ||||
| | OS and Version | Architecture | Wails    | Date       | | ||||
| |:---------------|:-------------|:---------|:-----------| | ||||
| | macOS 15.2     | `darwin-x64` | `v2.9.2` | 2024-12-31 | | ||||
| | macOS 14.5     | `darwin-arm` | `v2.8.2` | 2024-05-28 | | ||||
| | Windows 11     | `win11-x64`  | `v2.9.2` | 2024-12-21 | | ||||
| | Windows 11     | `win11-arm`  | `v2.10`  | 2025-02-23 | | ||||
| | Linux (HoloOS) | `linux-x64`  | `v2.9.2` | 2025-01-02 | | ||||
| | Linux (Debian) | `linux-arm`  | `v2.10`  | 2025-02-16 | | ||||
| | OS and Version | Architecture | Wails     | Date       | | ||||
| |:---------------|:-------------|:----------|:-----------| | ||||
| | macOS 15.2     | `darwin-x64` | `v2.9.2`  | 2024-12-31 | | ||||
| | macOS 14.5     | `darwin-arm` | `v2.10.1` | 2025-03-30 | | ||||
| | Windows 11     | `win11-x64`  | `v2.9.2`  | 2024-12-21 | | ||||
| | Windows 11     | `win11-arm`  | `v2.10`   | 2025-02-23 | | ||||
| | Linux (HoloOS) | `linux-x64`  | `v2.9.2`  | 2025-01-02 | | ||||
| | Linux (Debian) | `linux-arm`  | `v2.10`   | 2025-02-16 | | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
|  | ||||
| @ -354,7 +354,7 @@ This demo was tested in the following environments: | ||||
| | OS and Version | Architecture | Tauri     | Date       | | ||||
| |:---------------|:-------------|:----------|:-----------| | ||||
| | macOS 15.2     | `darwin-x64` | `v1.6.0`  | 2024-12-31 | | ||||
| | macOS 14.5     | `darwin-arm` | `v1.5.14` | 2024-05-26 | | ||||
| | macOS 14.5     | `darwin-arm` | `v1.6.0`  | 2025-03-30 | | ||||
| | Windows 11     | `win11-x64`  | `v1.6.0`  | 2024-12-21 | | ||||
| | Windows 11     | `win11-arm`  | `v1.6.0`  | 2025-02-23 | | ||||
| | Linux (HoloOS) | `linux-x64`  | `v1.6.0`  | 2025-01-02 | | ||||
| @ -384,16 +384,17 @@ If required dependencies are installed, the output will show a checkmark next to | ||||
| 
 | ||||
| <pre> | ||||
| <span {...g}>[✔]</span> <span style={{...y.style,...B.style}}>Environment</span> | ||||
| {`    `}<span {...c}>-</span> <span {...B}>OS</span>: Mac OS 15.2.0 x86_64 (X64) | ||||
| {`    `}<span {...c}>-</span> <span {...B}>OS</span>: Mac OS 14.5.0 arm64 (X64) | ||||
| {`    `}<span {...g}>✔</span> <span {...B}>Xcode Command Line Tools</span>: installed | ||||
| {`    `}<span {...g}>✔</span> <span {...B}>rustc</span>: 1.83.0 (90b35a623 2024-11-26) | ||||
| {`    `}<span {...g}>✔</span> <span {...B}>cargo</span>: 1.83.0 (5ffbef321 2024-10-29) | ||||
| {`    `}<span {...g}>✔</span> <span {...B}>rustup</span>: 1.27.1 (54dd3d00f 2024-04-24) | ||||
| {`    `}<span {...g}>✔</span> <span {...B}>Rust toolchain</span>: stable-x86_64-apple-darwin (default) | ||||
| {`    `}<span {...g}>✔</span> <span {...B}>rustc</span>: 1.85.1 (4eb161250 2025-03-15) | ||||
| {`    `}<span {...g}>✔</span> <span {...B}>cargo</span>: 1.85.1 (d73d2caf9 2024-12-31) | ||||
| {`    `}<span {...g}>✔</span> <span {...B}>rustup</span>: 1.28.1 (f9edccde0 2025-03-05) | ||||
| {`    `}<span {...g}>✔</span> <span {...B}>Rust toolchain</span>: stable-aarch64-apple-darwin (default) | ||||
| {`    `}<span {...c}>-</span> <span {...B}>node</span>: 20.18.0 | ||||
| {`    `}<span {...c}>-</span> <span {...B}>pnpm</span>: 9.12.3 | ||||
| {`    `}<span {...c}>-</span> <span {...B}>npm</span>: 10.8.2 | ||||
| {`    `}<span {...c}>-</span> <span {...B}>bun</span>: 1.1.42 | ||||
| {`    `}<span {...c}>-</span> <span {...B}>deno</span>: deno 2.1.4 | ||||
| {`    `}<span {...c}>-</span> <span {...B}>bun</span>: 1.2.7 | ||||
| {`    `}<span {...c}>-</span> <span {...B}>deno</span>: deno 2.2.6 | ||||
| </pre> | ||||
| 
 | ||||
| :::caution pass | ||||
| @ -536,7 +537,7 @@ export default defineConfig(async () => ({ | ||||
| 
 | ||||
| - Replace `index.html` with the following codeblock: | ||||
| 
 | ||||
| ```html title="index.html" | ||||
| ```html title="index.html (replace contents)" | ||||
| <!doctype html> | ||||
| <html lang="en"> | ||||
|   <head> | ||||
| @ -573,7 +574,7 @@ table.center { | ||||
| 
 | ||||
| - Replace `src/main.ts` with the following codeblock: | ||||
| 
 | ||||
| ```ts title="src/main.ts" | ||||
| ```ts title="src/main.ts (replace contents)" | ||||
| import { mount } from "kaioken"; | ||||
| import App from "./App"; | ||||
| 
 | ||||
|  | ||||
| @ -193,7 +193,7 @@ This demo was tested in the following environments: | ||||
| | OS and Version | Architecture | Server   | Client   | Date       | | ||||
| |:---------------|:-------------|:---------|:---------|:-----------| | ||||
| | macOS 15.2     | `darwin-x64` | `5.5.0`  | `5.5.0`  | 2024-12-31 | | ||||
| | macOS 14.5     | `darwin-arm` | `5.1.0`  | `5.1.0`  | 2024-05-25 | | ||||
| | macOS 14.5     | `darwin-arm` | `6.0.0`  | `6.0.0`  | 2025-03-30 | | ||||
| | Windows 11     | `win11-x64`  | `5.5.0`  | `5.5.0`  | 2024-12-20 | | ||||
| | Windows 11     | `win11-arm`  | `5.6.0`  | `5.6.0`  | 2025-02-23 | | ||||
| | Linux (HoloOS) | `linux-x64`  | `5.5.0`  | `5.5.0`  | 2025-01-02 | | ||||
|  | ||||
| @ -158,15 +158,15 @@ This browser demo was tested in the following environments: | ||||
| 
 | ||||
| | Browser     | Date       | | ||||
| |:------------|:-----------| | ||||
| | Chrome 118  | 2024-06-29 | | ||||
| | Chrome 118  | 2025-03-30 | | ||||
| 
 | ||||
| Browsers that do not support WebSQL will throw errors: | ||||
| 
 | ||||
| | Browser     | Date       | Error Message                 | | ||||
| |:------------|:-----------|:------------------------------| | ||||
| | Chrome 126  | 2024-06-29 | `openDatabase is not defined` | | ||||
| | Safari 17.1 | 2024-06-29 | `Web SQL is deprecated`       | | ||||
| | Firefox 127 | 2024-06-29 | `openDatabase is not defined` | | ||||
| | Chrome 133  | 2025-03-30 | `openDatabase is not defined` | | ||||
| | Safari 18.3 | 2025-03-30 | `Web SQL is deprecated`       | | ||||
| | Firefox 136 | 2025-03-30 | `openDatabase is not defined` | | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
|  | ||||
| @ -28,8 +28,8 @@ This demo was tested in the following environments: | ||||
| 
 | ||||
| | macOS  | Language          | Date       | | ||||
| |:-------|:------------------|:-----------| | ||||
| | `14.5` | AppleScript (OSA) | 2024-06-30 | | ||||
| | `14.5` | JavaScript (JXA)  | 2024-06-30 | | ||||
| | `14.5` | AppleScript (OSA) | 2025-03-30 | | ||||
| | `14.5` | JavaScript (JXA)  | 2025-03-30 | | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
|  | ||||
| @ -548,7 +548,7 @@ This demo was tested in the following deployments: | ||||
| | Architecture | Version | Python   | Date       | | ||||
| |:-------------|:--------|:---------|:-----------| | ||||
| | `darwin-x64` | `2.7.0` | `3.13.1` | 2024-12-31 | | ||||
| | `darwin-arm` | `2.7.0` | `3.12.3` | 2024-06-30 | | ||||
| | `darwin-arm` | `2.7.0` | `3.12.3` | 2025-03-30 | | ||||
| | `linux-x64`  | `2.7.0` | `3.11.7` | 2024-12-31 | | ||||
| | `linux-arm`  | `2.7.0` | `3.11.2` | 2025-02-15 | | ||||
| 
 | ||||
| @ -1020,7 +1020,7 @@ This demo was tested in the following deployments: | ||||
| | Architecture | Version | Date       | | ||||
| |:-------------|:--------|:-----------| | ||||
| | `darwin-x64` | `2.2.0` | 2024-12-31 | | ||||
| | `darwin-arm` | `2.2.0` | 2024-06-30 | | ||||
| | `darwin-arm` | `2.2.0` | 2025-03-30 | | ||||
| | `linux-x64`  | `2.2.0` | 2024-12-31 | | ||||
| | `linux-arm`  | `2.2.0` | 2025-02-15 | | ||||
| 
 | ||||
|  | ||||
| @ -1118,7 +1118,7 @@ This demo was last tested in the following deployments: | ||||
| | Architecture | V8 Version    | Javet   | Java      | Date       | | ||||
| |:-------------|:--------------|:--------|:----------|:-----------| | ||||
| | `darwin-x64` | `13.2.152.16` | `4.1.1` | `22`      | 2025-01-19 | | ||||
| | `darwin-arm` | `12.6.228.13` | `3.1.3` | `11.0.23` | 2024-06-19 | | ||||
| | `darwin-arm` | `13.2.152.16` | `4.1.1` | `17.0.14` | 2025-03-30 | | ||||
| | `win11-x64`  | `12.6.228.13` | `3.1.3` | `21.0.5`  | 2024-12-20 | | ||||
| | `linux-x64`  | `12.6.228.13` | `3.1.3` | `17.0.7`  | 2024-06-20 | | ||||
| | `linux-arm`  | `13.2.152.16` | `4.1.1` | `17.0.14` | 2025-02-16 | | ||||
| @ -1149,7 +1149,8 @@ curl -LO https://repo1.maven.org/maven2/com/caoccao/javet/javet-v8-macos-x86_64/ | ||||
|   <TabItem value="darwin-arm" label="ARM64 Mac"> | ||||
| 
 | ||||
| ```bash | ||||
| curl -LO https://repo1.maven.org/maven2/com/caoccao/javet/javet-macos/3.1.3/javet-macos-3.1.3.jar | ||||
| curl -LO https://repo1.maven.org/maven2/com/caoccao/javet/javet/4.1.1/javet-4.1.1.jar | ||||
| curl -LO https://repo1.maven.org/maven2/com/caoccao/javet/javet-v8-macos-arm64/4.1.1/javet-v8-macos-arm64-4.1.1.jar | ||||
| ``` | ||||
| 
 | ||||
|   </TabItem> | ||||
| @ -1216,8 +1217,8 @@ java -cp ".:javet-4.1.1.jar:javet-v8-macos-x86_64-4.1.1.jar" SheetJSJavet pres.x | ||||
|   <TabItem value="darwin-arm" label="ARM64 Mac"> | ||||
| 
 | ||||
| ```bash | ||||
| javac -cp ".:javet-macos-3.1.3.jar" SheetJSJavet.java | ||||
| java -cp ".:javet-macos-3.1.3.jar" SheetJSJavet pres.xlsx | ||||
| javac -cp ".:javet-4.1.1.jar:javet-v8-macos-arm64-4.1.1.jar" SheetJSJavet.java | ||||
| java -cp ".:javet-4.1.1.jar:javet-v8-macos-arm64-4.1.1.jar" SheetJSJavet pres.xlsx | ||||
| ``` | ||||
| 
 | ||||
|   </TabItem> | ||||
| @ -1279,7 +1280,7 @@ This demo was last tested in the following deployments: | ||||
| | Architecture | V8 Version    | Date       | | ||||
| |:-------------|:--------------|:-----------| | ||||
| | `darwin-x64` | `12.3.219.12` | 2024-07-16 | | ||||
| | `darwin-arm` | `12.3.219.12` | 2024-07-16 | | ||||
| | `darwin-arm` | `12.3.219.12` | 2025-03-30 | | ||||
| | `win11-x64`  | `12.3.219.12` | 2024-12-20 | | ||||
| | `win11-arm`  | `12.3.219.12` | 2025-02-23 | | ||||
| | `linux-x64`  | `12.3.219.12` | 2025-01-10 | | ||||
|  | ||||
| @ -33,7 +33,7 @@ Swift on MacOS supports JavaScriptCore without additional dependencies. | ||||
| | Architecture | Swift   | Date       | | ||||
| |:-------------|:--------|:-----------| | ||||
| | `darwin-x64` | `6.0.2` | 2024-12-17 | | ||||
| | `darwin-arm` | `5.10`  | 2024-06-30 | | ||||
| | `darwin-arm` | `6.0.3` | 2025-03-30 | | ||||
| 
 | ||||
| [**C / C++ Compiled from Source**](#c) | ||||
| 
 | ||||
| @ -753,13 +753,51 @@ to `SheetJSwift.xlsx`, which can be opened in a spreadsheet editor. | ||||
| It is straightforward to load the platform-native (macOS) or compiled libraries | ||||
| in programs built in other programming languages. | ||||
| 
 | ||||
| The JavaScriptCore C interface does not use "blingos" (function-like macros), so | ||||
| it is possible to reference each method in an external binding. | ||||
| 
 | ||||
| ### Rust | ||||
| 
 | ||||
| Writing bindings is fairly mechanical. For example, the following C code | ||||
| creates a string within the engine from a UTF8 string: | ||||
| Writing bindings is fairly mechanical. There are 4 parts to the process: | ||||
| 
 | ||||
| ```c | ||||
| JSStringRef script = JSStringCreateWithUTF8CString("SheetJS"); | ||||
| 0) Link to the external library. | ||||
| 
 | ||||
| 1) Generate Rust representations of the original C data types. | ||||
| 
 | ||||
| 2) Translate the function declaration. | ||||
| 
 | ||||
| 3) Write a wrapper to convert between Rust concepts and C concepts. | ||||
| 
 | ||||
| For example, the following C code creates a string within the engine from a | ||||
| UTF8 string: | ||||
| 
 | ||||
| ```c title="Sample use of JSStringCreateWithUTF8CString" | ||||
| const char *code = "'Sheet' + 'JS'"; | ||||
| JSStringRef script = JSStringCreateWithUTF8CString(code); | ||||
| ``` | ||||
| 
 | ||||
| An ergonomic wrapper function would take a Rust string literal and handle unsafe | ||||
| data operations: | ||||
| 
 | ||||
| ```rust title="Theoretical equivalent in Rust" | ||||
| let code: &str = "'Sheet' + 'JS'"; | ||||
| let script: JSStringRef = JSC::JSStringCreateWithUTF8CString(code); | ||||
| ``` | ||||
| 
 | ||||
| **Rust Linkage** | ||||
| 
 | ||||
| Custom directives are typically added to `build.rs`. The `cargo::rustc-link-lib` | ||||
| directive instructs the Rust compiler to link against an external library. | ||||
| 
 | ||||
| The following snippet will instruct the toolchain to link against the system | ||||
| `JavaScriptCore.framework` framework on macOS: | ||||
| 
 | ||||
| ```rust title="build.rs (link to JavaScriptCore.framework on macOS)" | ||||
| #[cfg(target_os = "macos")] | ||||
| fn main() { | ||||
|   // highlight-next-line | ||||
|   println!("cargo::rustc-link-lib=framework=JavaScriptCore"); | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| **Rust Types** | ||||
| @ -767,7 +805,7 @@ JSStringRef script = JSStringCreateWithUTF8CString("SheetJS"); | ||||
| `JSStringRef` is a pointer to an opaque data type. The spiritual equivalent | ||||
| according to the Rustonomicon is a pointer to an opaque struct[^9]: | ||||
| 
 | ||||
| ```rust | ||||
| ```rust title="JSStringRef opaque type in Rust" | ||||
| #[repr(C)] | ||||
| pub struct JSString { | ||||
|   _data: [u8; 0], | ||||
| @ -779,7 +817,7 @@ type JSStringRef = *mut JSContext; | ||||
| 
 | ||||
| **Function Declaration** | ||||
| 
 | ||||
| The `JSStringCreateWithUTF8CString` function in declared in C as follows: | ||||
| The `JSStringCreateWithUTF8CString` function is declared in C as follows: | ||||
| 
 | ||||
| ```c | ||||
| JSStringRef JSStringCreateWithUTF8CString(const char * string); | ||||
| @ -787,8 +825,9 @@ JSStringRef JSStringCreateWithUTF8CString(const char * string); | ||||
| 
 | ||||
| The equivalent Rust declaration must be defined in an `extern "C"` block: | ||||
| 
 | ||||
| ```rust | ||||
| ```rust title="JSStringCreateWithUTF8CString Rust declaration" | ||||
| unsafe extern "C" { | ||||
|   // JSStringRef JSStringCreateWithUTF8CString(const char * string); | ||||
|   pub unsafe fn JSStringCreateWithUTF8CString(string: *const u8) -> JSStringRef; | ||||
| } | ||||
| ``` | ||||
| @ -825,7 +864,7 @@ let ref: JSStringRef = JSStringCreateWithUTF8CString(cstr.as_ptr() as *const u8) | ||||
| 
 | ||||
| The demo makes a safe wrapper to perform the unsafe waltz in one line: | ||||
| 
 | ||||
| ```rust | ||||
| ```rust title="Ergonomic wrapper for JSStringCreateWithUTF8CString" | ||||
| pub struct JSC; | ||||
| impl JSC { | ||||
|   pub fn JSStringCreateWithUTF8CString(str: &str) -> JSStringRef { unsafe { | ||||
|  | ||||
| @ -177,7 +177,7 @@ This demo was tested in the following deployments: | ||||
| | Architecture | Jurassic | Date       | | ||||
| |:-------------|:---------|:-----------| | ||||
| | `darwin-x64` | `3.2.8`  | 2024-12-17 | | ||||
| | `darwin-arm` | `3.2.7`  | 2024-06-15 | | ||||
| | `darwin-arm` | `3.2.9`  | 2025-03-30 | | ||||
| | `win11-x64`  | `3.2.8`  | 2024-12-19 | | ||||
| | `win11-arm`  | `3.2.9`  | 2025-02-23 | | ||||
| | `linux-x64`  | `3.2.8`  | 2025-01-10 | | ||||
|  | ||||
| @ -144,11 +144,11 @@ worker.addEventListener('message', function(e) { | ||||
| 
 | ||||
| :::danger pass | ||||
| 
 | ||||
| Each moving part in this solution has been deprecated years ago: | ||||
| Each moving part in this solution has been deprecated many years ago: | ||||
| 
 | ||||
| - Adobe stopped supporting Flash Player at the end of 2020 | ||||
| - Microsoft stopped supporting IE8 in 2019 and stopped supporting IE9 in 2020 | ||||
| - `Downloadify` support ended in 2010 and `SWFObject` support ended in 2016 | ||||
| - Adobe discontinued Flash Player | ||||
| - Microsoft discontinued Internet Explorer | ||||
| - `Downloadify` and `SWFObject` are no longer supported | ||||
| 
 | ||||
| New projects should strongly consider requiring modern browsers.  This info is | ||||
| provided on an "as is" basis and there is no realistic way to provide support | ||||
|  | ||||
| @ -340,9 +340,9 @@ _Assign a dynamic array formula_ | ||||
| XLSX.utils.sheet_set_array_formula(worksheet, range, formula, true); | ||||
| ``` | ||||
| 
 | ||||
| Released in 2020, Dynamic Array Formulae are supported in the XLSX/XLSM and XLSB | ||||
| file formats.  They are represented like normal array formulae but have special | ||||
| cell metadata indicating that the formula should be allowed to adjust the range. | ||||
| Dynamic Array Formulae are supported in the XLSX/XLSM and XLSB file formats. | ||||
| They are internally stored as normal array formulae but have special cell | ||||
| metadata indicating that the formula should be allowed to adjust the range. | ||||
| 
 | ||||
| An array formula can be marked as dynamic by setting the cell `D` property to | ||||
| true.  The `F` range is expected but can be the set to the current cell: | ||||
|  | ||||
| @ -15,12 +15,12 @@ | ||||
|     "make": "electron-forge make" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "@electron-forge/cli": "7.6.0", | ||||
|     "@electron-forge/maker-deb": "7.6.0", | ||||
|     "@electron-forge/maker-rpm": "7.6.0", | ||||
|     "@electron-forge/maker-squirrel": "7.6.0", | ||||
|     "@electron-forge/maker-zip": "7.6.0", | ||||
|     "electron": "33.2.1" | ||||
|     "@electron-forge/cli": "7.8.0", | ||||
|     "@electron-forge/maker-deb": "7.8.0", | ||||
|     "@electron-forge/maker-rpm": "7.8.0", | ||||
|     "@electron-forge/maker-squirrel": "7.8.0", | ||||
|     "@electron-forge/maker-zip": "7.8.0", | ||||
|     "electron": "35.1.2" | ||||
|   }, | ||||
|   "config": { | ||||
|     "forge": { | ||||
|  | ||||
| @ -10,6 +10,7 @@ type AOA = any[][]; | ||||
|   selector: 'app-home', | ||||
|   //templateUrl: 'home.page.html',
 | ||||
|   styleUrls: ['home.page.scss'], | ||||
|   standalone: false, | ||||
|   template: ` | ||||
| <ion-header> | ||||
|   <ion-toolbar> | ||||
|  | ||||
| @ -10,7 +10,7 @@ export default defineConfig({ | ||||
|     vue(), | ||||
|     { // this plugin handles ?sheetjs tags
 | ||||
|       name: "vite-sheet", | ||||
|       transform(code, id) { | ||||
|       transform(_code, id) { | ||||
|         if(!id.match(/\?sheetjs$/)) return; | ||||
|         var wb = read(readFileSync(id.replace(/\?sheetjs$/, ""))); | ||||
|         var data = utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]); | ||||
| @ -19,7 +19,7 @@ export default defineConfig({ | ||||
|     }, | ||||
|     { // this plugin handles ?html tags
 | ||||
|       name: "vite-sheet-html", | ||||
|       transform(code, id) { | ||||
|       transform(_code, id) { | ||||
|         if(!id.match(/\?html/)) return; | ||||
|         var wb = read(readFileSync(id.replace(/\?html/, ""))); | ||||
|         var html = utils.sheet_to_html(wb.Sheets[wb.SheetNames[0]]); | ||||
| @ -28,7 +28,7 @@ export default defineConfig({ | ||||
|     }, | ||||
|     { // this plugin handles ?b64 tags
 | ||||
|       name: "vite-b64-plugin", | ||||
|       transform(code, id) { | ||||
|       transform(_code, id) { | ||||
|         if(!id.match(/\?b64$/)) return; | ||||
|         var path = id.replace(/\?b64/, ""); | ||||
|         var data = readFileSync(path, "base64"); | ||||
|  | ||||
| @ -1,72 +1,109 @@ | ||||
| #!/bin/bash | ||||
| # https://docs.sheetjs.com/docs/demos/frontend/bundler/vitejs | ||||
| # NOTE: this only checks whether data or SheetJS code is added to the bundle | ||||
| 
 | ||||
| cd /tmp | ||||
| rm -rf sheetjs-vite-tests | ||||
| mkdir sheetjs-vite-tests | ||||
| cd sheetjs-vite-tests | ||||
| 
 | ||||
| for n in {3..5}; do | ||||
| npm create vite@$n sheetjs-vite$n -- --template vue-ts | ||||
| for n in {3..6}; do | ||||
| npm create -y vite@$n sheetjs-vite$n -- --template vue-ts | ||||
| cd sheetjs-vite$n | ||||
| npm i | ||||
| npm i --save puppeteer express@4 | ||||
| npm i --save https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz | ||||
| npm ls | grep vite | ||||
| 
 | ||||
| ## See https://github.com/vuejs/language-tools/issues/4484#issuecomment-2182469459 | ||||
| if [[ "$n" == "4" ]]; then npm i "vue-tsc@2"; fi | ||||
| 
 | ||||
| curl -O https://docs.sheetjs.com/vitejs/vite.config.ts | ||||
| 
 | ||||
| mkdir -p data | ||||
| curl -L -o data/pres.xlsx https://sheetjs.com/pres.xlsx | ||||
| curl -L -o data/pres.xlsx https://docs.sheetjs.com/pres.xlsx | ||||
| 
 | ||||
| cat >src/components/HelloWorld.vue <<EOF | ||||
| <script setup lang="ts"> | ||||
| // @ts-ignore | ||||
| import data from '../../data/pres.xlsx?sheetjs'; | ||||
| import { version, utils, writeFileXLSX } from 'xlsx'; | ||||
| 
 | ||||
| interface President { | ||||
|   terms: { "type": "prez" | "viceprez"; }[]; | ||||
|   name: { first: string; last: string; } | ||||
|   bio: { birthday: string; } | ||||
| } | ||||
| 
 | ||||
| async function xport() { | ||||
| /* fetch JSON data and parse */ | ||||
| const url = "https://docs.sheetjs.com/executive.json"; | ||||
| const raw_data: President[] = await (await fetch(url)).json(); | ||||
| 
 | ||||
| /* filter for the Presidents */ | ||||
| const prez = raw_data.filter(row => row.terms.some(term => term.type === "prez")); | ||||
| 
 | ||||
| /* sort by first presidential term */ | ||||
| prez.forEach(row => row.start = row.terms.find(term => term.type === "prez").start); | ||||
| prez.sort((l,r) => l.start.localeCompare(r.start)); | ||||
| 
 | ||||
| /* flatten objects */ | ||||
| const rows = prez.map(row => ({ | ||||
|   name: row.name.first + " " + row.name.last, | ||||
|   birthday: row.bio.birthday | ||||
| })); | ||||
| 
 | ||||
| /* generate worksheet and workbook */ | ||||
| const worksheet = utils.json_to_sheet(rows); | ||||
| const workbook = utils.book_new(); | ||||
| utils.book_append_sheet(workbook, worksheet, "Dates"); | ||||
| 
 | ||||
| /* fix headers */ | ||||
| utils.sheet_add_aoa(worksheet, [["Name", "Birthday"]], { origin: "A1" }); | ||||
| 
 | ||||
| /* calculate column width */ | ||||
| const max_width = rows.reduce((w, r) => Math.max(w, r.name.length), 10); | ||||
| worksheet["!cols"] = [ { wch: max_width } ]; | ||||
| 
 | ||||
| /* create an XLSX file and try to save to Presidents.xlsx */ | ||||
| console.log(utils.sheet_to_csv(worksheet)); | ||||
| writeFileXLSX(workbook, "Presidents.xlsx"); | ||||
| } | ||||
| 
 | ||||
| </script> | ||||
| 
 | ||||
| <template> | ||||
|   <table> | ||||
|     <tr><th>Name</th><th>Index</th></tr> | ||||
|     <tr v-for="(row,R) in data" v-bind:key="R"> | ||||
|       <td>{{row.Name}}</td> | ||||
|       <td>{{row.Index}}</td> | ||||
|     </tr> | ||||
|   </table> | ||||
|   <button type="button" @click="xport">Export with SheetJS version {{ version }}</button> | ||||
| </template> | ||||
| EOF | ||||
| 
 | ||||
| npm run build | ||||
| echo "### Results: " $(grep Clinton -R dist | wc -l) $(grep BESSELJ -R dist | wc -l) | ||||
| npx vite build | ||||
| 
 | ||||
| cat >src/components/HelloWorld.vue <<EOF | ||||
| <script setup lang="ts"> | ||||
| // @ts-ignore | ||||
| import b64 from '../../data/pres.xlsx?b64'; | ||||
| import { read, utils } from "xlsx"; | ||||
| /* parse workbook and convert first sheet to row array */ | ||||
| const wb = read(b64); | ||||
| const ws = wb.Sheets[wb.SheetNames[0]]; | ||||
| interface IPresident { Name: string; Index: number; }; | ||||
| const data = utils.sheet_to_json<IPresident>(ws); | ||||
| </script> | ||||
| 
 | ||||
| <template> | ||||
|   <table> | ||||
|     <tr><th>Name</th><th>Index</th></tr> | ||||
|     <tr v-for="(row,R) in data" v-bind:key="R"> | ||||
|       <td>{{row.Name}}</td> | ||||
|       <td>{{row.Index}}</td> | ||||
|     </tr> | ||||
|   </table> | ||||
| </template> | ||||
| cat >test.cjs <<EOF | ||||
| const puppeteer = require('puppeteer'); | ||||
| const express = require('express'); | ||||
| const app = express(); | ||||
| app.use(express.static('./dist/')); | ||||
| app.listen(7262, async() => { | ||||
|   await new Promise((res,rej) => setTimeout(res, 1000)); | ||||
|   const browser = await puppeteer.launch(); | ||||
|   const page = await browser.newPage(); | ||||
|   page.on("console", msg => console.log("PAGE LOG:", msg.text())); | ||||
|   await page.setViewport({width: 1920, height: 1080}); | ||||
|   const client = await page.target().createCDPSession(); | ||||
|   await client.send('Browser.setDownloadBehavior', { | ||||
|     behavior: 'allow', | ||||
|     downloadPath: require("path").resolve('./') | ||||
|   }); | ||||
|   page.on('request', req => console.log(req.url())); | ||||
|   await page.goto('http://localhost:7262/'); | ||||
|   await page.click("button"); | ||||
|   await new Promise((res,rej) => setTimeout(res, 1000)); | ||||
|   await browser.close(); | ||||
|   process.exit(); | ||||
| }); | ||||
| EOF | ||||
| 
 | ||||
| npm run build | ||||
| echo "### Results: " $(grep Clinton -R dist | wc -l) $(grep BESSELJ -R dist | wc -l) | ||||
| node test.cjs | ||||
| npx -y xlsx-cli Presidents.xlsx | head -n 3 | ||||
| rm -f Presidents.xlsx | ||||
| 
 | ||||
| 
 | ||||
| cd - | ||||
| 
 | ||||
| done | ||||
|  | ||||
| @ -6,7 +6,7 @@ rm -rf sheetjs-vite-static | ||||
| mkdir sheetjs-vite-static | ||||
| cd sheetjs-vite-static | ||||
| 
 | ||||
| for n in {2..5}; do | ||||
| for n in {2..6}; do | ||||
| npm create -y vite@$n sheetjs-vite-$n -- --template vue-ts | ||||
| cd sheetjs-vite-$n | ||||
| npm i | ||||
| @ -24,9 +24,13 @@ if [[ "$n" == "2" ]]; then | ||||
|   # Please update to v0.35.0 or higher for TypeScript version: 4.9.5 | ||||
|   # | ||||
|   # Forcefully upgrading `vue-tsc` appears to be innocuous. | ||||
|   npm i --save vue-tsc@latest | ||||
|   npm i --save "vue-tsc@1.x" | ||||
| elif [[ "$n" == "4" ]]; then | ||||
|   # Search string not found: "/supportedTSExtensions = .*(?=;)/" | ||||
|   npm i --save "vue-tsc@2" | ||||
| fi | ||||
| curl -O https://docs.sheetjs.com/vitejs/vite.config.ts | ||||
| 
 | ||||
| mkdir -p data | ||||
| curl -L -o data/pres.xlsx https://docs.sheetjs.com/pres.xlsx | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user