Demo refresh

This commit is contained in:
SheetJS 2025-04-18 00:04:01 -04:00
parent 467af52e4f
commit d953a625a2
17 changed files with 346 additions and 300 deletions

@ -302,7 +302,7 @@
<Cell><Data ss:Type="String">Rust</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"><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>

@ -99,7 +99,7 @@
<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"><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>
</Row>

@ -123,7 +123,7 @@ This demo was last tested in the following deployments:
|:-------------|:---------|:-----------|
| `darwin-x64` | `1.2.8` | 2025-03-31 |
| `darwin-arm` | `1.2.7` | 2025-03-30 |
| `win11-x64` | `1.1.42` | 2024-12-22 |
| `win11-x64` | `1.2.8` | 2025-04-17 |
| `win11-arm` | `1.2.3` | 2025-02-23 |
| `linux-x64` | `1.1.40` | 2024-12-19 |
| `linux-arm` | `1.2.2` | 2025-02-16 |

@ -35,7 +35,7 @@ This demo was tested in the following configurations:
| Platform | Architecture | Date |
|:------------------------------------------------------------------|:-------------|:-----------|
| NVIDIA RTX 4090 (24 GB VRAM) + Ryzen Z1 Extreme (16 GB RAM) | `win11-x64` | 2025-03-06 |
| NVIDIA RTX 4090 (24 GB VRAM) + Ryzen Z1 Extreme (16 GB RAM) | `win11-x64` | 2025-04-17 |
| NVIDIA RTX 4090 (24 GB VRAM) + Ryzen Z1 Extreme (16 GB RAM) | `linux-x64` | 2025-01-28 |
| AMD RX 7900 XTX (24 GB VRAM) + Ryzen Z1 Extreme (16 GB RAM) | `win11-x64` | 2025-01-12 |
| AMD RX 7900 XTX (24 GB VRAM) + Ryzen Z1 Extreme (16 GB RAM) | `linux-x64` | 2025-01-29 |
@ -853,7 +853,7 @@ npm i --save https://sheet.lol/balls/xlsx-${current}.tgz`}
4) Install dependencies:
```bash
npm i --save @langchain/core@0.3.42 langchain@0.3.19 @langchain/ollama@0.2.0 peggy@3.0.2
npm i --save @langchain/core@0.3.44 langchain@0.3.21 @langchain/ollama@0.2.0 peggy@3.0.2
```
:::note pass
@ -862,7 +862,7 @@ In some test runs, there were error messages relating to dependency and peer
dependency versions. The `--force` flag will suppress version mismatch errors:
```bash
npm i --save @langchain/core@0.3.42 langchain@0.3.19 @langchain/ollama@0.2.0 peggy@3.0.2 --force
npm i --save @langchain/core@0.3.44 langchain@0.3.21 @langchain/ollama@0.2.0 peggy@3.0.2 --force
```
:::

@ -295,7 +295,9 @@ This demo was tested in the following deployments:
| Architecture | Date |
|:-------------|:-----------|
| `darwin-x64` | 2025-04-17 |
| `darwin-arm` | 2024-10-15 |
| `win11-x64` | 2025-04-17 |
:::

@ -127,11 +127,14 @@ That approach is not explored in this demo.
This demo was tested in the following environments:
| NodeJS | Date | Dependencies |
|:----------|:-----------|:------------------------------------|
| `18.20.3` | 2024-06-30 | ExpressJS 4.19.2 + Formidable 2.1.2 |
| `20.15.0` | 2024-06-30 | ExpressJS 4.19.2 + Formidable 2.1.2 |
| `22.3.0` | 2024-06-30 | ExpressJS 4.19.2 + Formidable 2.1.2 |
| NodeJS | Date | ExpressJS |
|:----------|:-----------|:----------|
| `18.20.8` | 2025-04-17 | `5.1.0` |
| `20.18.0` | 2025-04-17 | `5.1.0` |
| `22.14.0` | 2025-04-17 | `5.1.0` |
| `18.20.8` | 2025-04-17 | `4.21.2` |
| `20.18.0` | 2025-04-17 | `4.21.2` |
| `22.14.0` | 2025-04-17 | `4.21.2` |
:::

@ -49,10 +49,11 @@ flowchart LR
This demo was tested in the following environments:
| SvelteJS | Kit | Date |
|:-----------------|:---------|:-----------|
| `4.2.17` | `2.5.10` | 2024-06-03 |
| `5.0.0-next.149` | `2.5.10` | 2024-06-03 |
| SvelteJS | Kit | Date |
|:----------|:---------|:-----------|
| `5.27.2` | `2.20.7` | 2025-04-17 |
| `4.2.19` | `2.5.10` | 2025-04-17 |
| `3.59.2` | `1.30.4` | 2025-04-17 |
:::
@ -189,7 +190,35 @@ When this demo was last tested, SvelteKit required NodeJS major version 20.
1) Create a new site:
```bash
npm create svelte@latest sheetjs-svelte
mkdir -p sheetjs-svelte
cd sheetjs-svelte
npx sv create
```
When prompted:
- `Where would you like your project to be created?`: press <kbd>Enter</kbd>
- `Which template would you like?` select `SvelteKit minimal`
- `Add type checking with TypeScript?` select `Yes, using JavaScript with JSDoc`
- `What would you like to add to your project?` press <kbd>Enter</kbd> (do not select options)
- `Which package manager do you want to install dependencies with?`: select `npm` and press <kbd>Enter</kbd>
<details>
<summary><b>Older SvelteJS versions</b> (click to show)</summary>
The following commands create SvelteJS projects for older versions:
**SvelteJS 3.x**
```bash
npm create svelte@4 sheetjs-svelte
```
**SvelteJS 4.x**
```bash
npm create svelte@6 sheetjs-svelte
```
When prompted:
@ -198,19 +227,21 @@ When prompted:
- `Add type checking with TypeScript?` select `Yes, using JavaScript with JSDoc`
- `Select additional options` press <kbd>Enter</kbd> (do not select options)
:::note pass
To test the Svelte 5 beta, select `Try the Svelte 5 preview (unstable!)`
:::
2) Enter the project folder and install dependencies:
After creating the project, enter the project folder and install dependencies:
```bash
cd sheetjs-svelte
npm i
```
</details>
2) Install dependencies:
```bash
npm i
```
3) Fetch the example file [`pres.xlsx`](https://docs.sheetjs.com/pres.xlsx) and
move to a `data` subdirectory in the root of the project:
@ -311,6 +342,14 @@ observe that the data from the spreadsheet is displayed in the page.
11) In the spreadsheet, set cell A7 to `SheetJS Dev` and cell B7 to `47`. Save
the file. After saving, the browser should automatically refresh with new data.
:::caution pass
**Live reloading may not work in newer projects!**
If the page does not reload, manually refresh the page.
:::
### Static Site
12) Stop the development server and install the static adapter:

@ -45,16 +45,16 @@ This demo was tested in the following environments:
| OS | Device | Quasar | Date |
|:-----------|:--------------------|:---------|:-----------|
| Android 30 | NVIDIA Shield | `2.16.4` | 2024-06-09 |
| iOS 15.1 | iPad Pro | `2.16.4` | 2024-06-09 |
| Android 34 | NVIDIA Shield | `2.18.1` | 2025-04-17 |
| iOS 15.1 | iPad Pro | `2.18.1` | 2025-04-17 |
**Simulators**
| OS | Device | Quasar | Dev Platform | Date |
|:-----------|:--------------------|:---------|:-------------|:-----------|
| Android 34 | Pixel 3a | `2.16.4` | `darwin-arm` | 2024-06-09 |
| iOS 17.5 | iPhone SE (3rd gen) | `2.16.4` | `darwin-arm` | 2024-06-09 |
| Android 35 | Pixel 3a | `2.16.9` | `win11-x64` | 2024-08-20 |
| Android 35 | Pixel 9 Pro XL | `2.18.1` | `darwin-arm` | 2025-04-17 |
| iOS 18.2 | iPhone 16 Pro Max | `2.18.1` | `darwin-arm` | 2025-04-17 |
| Android 36 | Pixel 9 Pro XL | `2.18.1` | `win11-x64` | 2025-04-17 |
:::
@ -167,13 +167,23 @@ window.requestFileSystem(window.PERSISTENT, 0, function(fs) {
The demo draws from the ViteJS example. Familiarity with VueJS and TypeScript
is assumed.
### Platform Setup
0) Ensure all of the dependencies are installed. Install the CLI globally:
```bash
npm i -g @quasar/cli cordova
```
(you may need to run `sudo npm i -g` if there are permission issues)
:::note pass
In some systems, the command must be run as the root user:
```bash
sudo npm i -g @quasar/cli cordova
```
:::
<details>
<summary><b>Installation Notes</b> (click to show)</summary>
@ -182,6 +192,8 @@ Quasar requires Java 17
</details>
### Base Project
1) Create a new app:
```bash
@ -194,14 +206,12 @@ When prompted:
- "What would you like to build?": `App with Quasar CLI, let's go!`
- "Project folder": `SheetJSQuasar`
- "Pick Quasar version": `Quasar v2 (Vue 3 | latest and greatest)`
- "Pick script type": `Typescript`
- "Pick Quasar App CLI variant": `Quasar App CLI with Vite 2 (stable | v1)`
- "Pick Quasar App CLI variant": `Quasar App CLI with Vite`
- "Package name": (press <kbd>Enter</kbd>, it will use the default `sheetjsquasar`)
- "Project product name": `SheetJSQuasar`
- "Project description": `SheetJS + Quasar`
- "Author": (press <kbd>Enter</kbd>, it will use Git settings)
- "Pick a Vue component style": `Composition API`
- "Pick a Vue component style": `Composition API with <script setup>`
- "Pick your CSS preprocessor": `None`
- "Check the features needed for your project": Deselect everything (scroll down to each selected item and press <kbd>Space</kbd>)
- "Install project dependencies": `Yes, use npm`
@ -221,17 +231,96 @@ npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
```bash
npx cordova telemetry off
npx quasar mode add cordova
npx quasar mode remove capacitor
```
When prompted, enter the app id `org.sheetjs.quasar`.
It will create a new `src-cordova` folder. Continue in that folder:
4) Add the Dialog plugin to the `plugins` array in `quasar.config.ts`:
```js title="quasar.config.ts (edit highlighted line)"
// Quasar plugins
// highlight-next-line
plugins: ['Dialog']
```
5) Download [`IndexPage.vue`](pathname:///quasar/IndexPage.vue) and replace the
existing page script `src/pages/IndexPage.vue`:
```bash
curl -L -o src/pages/IndexPage.vue https://docs.sheetjs.com/quasar/IndexPage.vue
```
### Android
6) Create the Android project:
```bash
cd src-cordova
npx cordova platform add android
npx cordova plugin add cordova-plugin-wkwebview-engine
npx cordova plugin add cordova-plugin-file
cd ..
```
7) Start the simulator:
```bash
npx quasar dev -m cordova -T android
```
If prompted to select an external IP, press <kbd>Enter</kbd>.
:::caution pass
If the app is blank or not refreshing, delete the app and close the simulator,
then restart the development process.
:::
:::info pass
In some test runs, the command 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
```
[Gradle](https://gradle.org/) (the complete version) must be extracted and the
`bin` folder must be added to the user PATH variable. After adding to PATH,
launch a new PowerShell or Command Prompt window and run the command.
:::
To test that reading works:
- Download https://docs.sheetjs.com/pres.numbers
- Open the Downloads folder in Finder or Explorer
- Click and drag `pres.numbers` from the window into the simulator.
- Tap "Load File", tap the `≡` icon, tap "Downloads" and select `pres.numbers`.
To test that writing works:
- Tap "Save File". You will see a popup with a location.
- Pull the file from the simulator and verify the contents:
```bash
adb exec-out run-as org.sheetjs.quasar cat files/files/SheetJSQuasar.xlsx > /tmp/SheetJSQuasar.xlsx
npx xlsx-cli /tmp/SheetJSQuasar.xlsx
```
### iOS
8) Create the iOS project:
```bash
cd src-cordova
npx cordova platform add ios
npx cordova plugin add cordova-plugin-wkwebview-engine
npx cordova plugin add cordova-plugin-file
cd ..
```
:::note pass
@ -246,13 +335,7 @@ npx cordova plugin add cordova-plugin-file
:::
Return to the project directory:
```bash
cd ..
```
4) Enable file sharing and make the documents folder visible in the iOS app.
9) Enable file sharing and make the documents folder visible in the iOS app.
The following lines must be added to `src-cordova/platforms/ios/SheetJSQuasar/SheetJSQuasar-Info.plist`:
```xml title="src-cordova/platforms/ios/SheetJSQuasar/SheetJSQuasar-Info.plist (add to file)"
@ -270,10 +353,10 @@ The following lines must be added to `src-cordova/platforms/ios/SheetJSQuasar/Sh
(The root element of the document is `plist` and it contains one `dict` child)
5) Start the development server:
10) Start the development server:
```bash
npx quasar dev -m ios
npx quasar dev -m cordova -T ios
```
If prompted to select an external IP, press <kbd>Enter</kbd>.
@ -285,52 +368,6 @@ then restart the development process.
:::
6) Add the Dialog plugin to `quasar.config.js`:
```js title="quasar.config.js (add highlighted line)"
framework: {
config: {},
// ...
// Quasar plugins
// highlight-next-line
plugins: ['Dialog']
},
```
7) In the template section of `src/pages/IndexPage.vue`, replace the example
with a Table, Save button and Load file picker component:
```html title="src/pages/IndexPage.vue (change highlighted lines)"
<template>
<q-page class="row items-center justify-evenly">
<!-- highlight-start -->
<q-table :rows="todos" />
<q-btn-group>
<q-file label="Load File" filled label-color="orange" @input="updateFile"/>
<q-btn label="Save File" @click="saveFile" />
</q-btn-group>
<!-- highlight-end -->
</q-page>
</template>
```
This uses two functions that should be added to the component script:
```ts title="src/pages/IndexPage.vue (add highlighted lines)"
const meta = ref<Meta>({
totalCount: 1200
});
// highlight-start
function saveFile() {
}
async function updateFile(v: Event) {
}
return { todos, meta, saveFile, updateFile };
// highlight-end
}
});
```
The app should now show two buttons at the bottom:
![Quasar Step 6](pathname:///mobile/quasar6.png)
@ -342,38 +379,6 @@ then restart the development process.
:::
8) Wire up the `updateFile` function:
```ts title="src/pages/IndexPage.vue (add highlighted lines)"
import { defineComponent, ref } from 'vue';
// highlight-start
import { read, write, utils } from 'xlsx';
import { useQuasar } from 'quasar';
// highlight-end
export default defineComponent({
// ...
// highlight-start
const $q = useQuasar();
function dialogerr(e: Error) { $q.dialog({title: "Error!", message: e.message || String(e)}); }
// highlight-end
function saveFile() {
}
async function updateFile(v: Event) {
// highlight-start
try {
const files = (v.target as HTMLInputElement).files;
if(!files || files.length == 0) return;
const wb = read(await files[0].arrayBuffer());
const data = utils.sheet_to_json<any>(wb.Sheets[wb.SheetNames[0]]);
todos.value = data.map(row => ({id: row.Index, content: row.Name}));
} catch(e) { dialogerr(e); }
// highlight-end
}
```
To test that reading works:
- Download https://docs.sheetjs.com/pres.numbers
@ -391,46 +396,11 @@ To test that reading works:
Once selected, the screen should refresh with new contents.
9) Wire up the `saveFile` function:
```ts title="src/pages/IndexPage.vue (add highlighted lines)"
function saveFile() {
// highlight-start
/* generate workbook from state */
const ws = utils.json_to_sheet(todos.value);
const wb = utils.book_new();
utils.book_append_sheet(wb, ws, "SheetJSQuasar");
const u8: Uint8Array = write(wb, {bookType: "xlsx", type: "buffer"});
const dir: string = $q.cordova.file.documentsDirectory || $q.cordova.file.externalApplicationStorageDirectory;
/* save to file */
window.requestFileSystem(window.PERSISTENT, 0, function(fs) {
try {
fs.root.getFile("SheetJSQuasar.xlsx", {create: true}, entry => {
const msg = `File stored at ${dir} ${entry.fullPath}`;
entry.createWriter(writer => {
try {
const data = new Blob([u8], {type: "application/vnd.ms-excel"});
writer.onwriteend = () => {
try {
$q.dialog({title: "Success!", message: msg});
} catch(e) { dialogerr(e); }
};
writer.onerror = dialogerr;
writer.write(data);
} catch(e) { dialogerr(e); }
}, dialogerr);
}, dialogerr);
} catch(e) { dialogerr(e) }
}, dialogerr);
// highlight-end
}
```
The page should revert to the old contents.
To test that writing works:
- Close the app in the simulator and re-launch the app.
- Click "Save File". You will see a popup with a location:
![Quasar Step 8](pathname:///mobile/quasar8.png)
@ -475,121 +445,23 @@ id,content
46,Joseph Biden
```
**Android**
### Android Device
10) Create the Android project:
11) Close all open emulators and simulators.
12) Disconnect any iOS or Android devices connected to the computer.
13) Connect the Android device to the computer.
14) Start the dev process:
```bash
cd src-cordova
cordova platform add android
cd ..
```
11) Start the simulator:
```bash
quasar dev -m android
npx quasar dev -m cordova -T android
```
If prompted to select an external IP, press <kbd>Enter</kbd>.
:::caution pass
If the app is blank or not refreshing, delete the app and close the simulator,
then restart the development process.
:::
:::warning pass
On Windows, the command 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
```
[Gradle](https://gradle.org/) (the complete version) must be extracted and the
`bin` folder must be added to the user PATH variable. After adding to PATH,
launch a new PowerShell or Command Prompt window and run the command.
:::
To test that reading works:
- Click and drag `pres.numbers` from a Finder window into the simulator.
- Tap "Load", tap the `≡` icon, tap "Downloads" and select `pres.numbers`.
To test that writing works:
- Tap "Save File". You will see a popup with a location.
- Pull the file from the simulator and verify the contents:
```bash
adb exec-out run-as org.sheetjs.quasar cat files/files/SheetJSQuasar.xlsx > /tmp/SheetJSQuasar.xlsx
npx xlsx-cli /tmp/SheetJSQuasar.xlsx
```
**iOS Device**
12) Close all open emulators and simulators.
13) Disconnect any iOS or Android devices connected to the computer.
14) Connect the iOS device to the computer.
15) Open the Xcode project:
```bash
open src-cordova/platforms/ios/SheetJSQuasar.xcodeproj
```
Select "SheetJSQuasar" in the Navigator. In the main pane, select "Signing &amp;
Capabilities" and ensure a Team is selected. Save and close the project.
16) Start the dev process:
```bash
quasar dev -m ios
```
If prompted to select an external IP, press <kbd>Enter</kbd>.
17) Test the application:
- Press the Home button (or swipe up with one finger) and switch to Safari.
- Download https://docs.sheetjs.com/pres.numbers
- Press the Home button (or swipe up with one finger) and select the `SheetJSQuasar` app
- Tap the "Load" button, then select "Choose File" and select the downloaded `pres.numbers`
The table will update with new data.
- Tap "Save File"
- Press the Home button (or swipe up with one finger) and switch to Files.
- Tap `<` until the main "Browse" window is displayed, then select "On My iPhone"
- Look for the "SheetJSQuasar" folder and tap `SheetJSQuasar.xlsx`.
If Numbers is installed on the device, it will display the contents of the new file.
**Android Device**
18) Close all open emulators and simulators.
19) Disconnect any iOS or Android devices connected to the computer.
20) Connect the Android device to the computer.
21) Start the dev process:
```bash
quasar dev -m android
```
If prompted to select an external IP, press <kbd>Enter</kbd>.
22) Test the application:
15) Test the application:
- Press the Home button (or swipe up with one finger) and switch to Browser.
- Download https://docs.sheetjs.com/pres.numbers
@ -606,6 +478,48 @@ methods ("Storage Access Framework") that are not implemented in Quasar.
:::
### iOS Device
16) Close all open emulators and simulators.
17) Disconnect any iOS or Android devices connected to the computer.
18) Connect the iOS device to the computer.
19) Open the Xcode project:
```bash
open src-cordova/platforms/ios/SheetJSQuasar.xcodeproj
```
Select "SheetJSQuasar" in the Navigator. In the main pane, select "Signing &amp;
Capabilities" and ensure a Team is selected. Save and close the project.
20) Start the dev process:
```bash
npx quasar dev -m cordova -T ios
```
If prompted to select an external IP, press <kbd>Enter</kbd>.
11) Test the application:
- Press the Home button (or swipe up with one finger) and switch to Safari.
- Download https://docs.sheetjs.com/pres.numbers
- Press the Home button (or swipe up with one finger) and select the `SheetJSQuasar` app
- Tap the "Load" button, then select "Choose File" and select the downloaded `pres.numbers`
The table will update with new data.
- Tap "Save File"
- Press the Home button (or swipe up with one finger) and switch to Files.
- Tap `<` until the main "Browse" window is displayed, then select "On My iPhone"
- Look for the "SheetJSQuasar" folder and tap `SheetJSQuasar.xlsx`.
If Numbers is installed on the device, it will display the contents of the new file.
[^1]: See ["File Picker"](https://quasar.dev/vue-components/file-picker) in the Quasar documentation.
[^2]: See [`read` in "Reading Files"](/docs/api/parse-options)
[^3]: See ["SheetJS Data Model"](/docs/csf/) for more details on workbooks, worksheets, and other concepts.

@ -62,15 +62,16 @@ This demo was tested in the following environments:
|:-----------|:--------------------|:-------|:-------------|:-----------|
| Android 34 | Pixel 3a | B | `darwin-arm` | 2025-03-30 |
| iOS 18.2 | iPhone SE (3rd gen) | B | `darwin-arm` | 2025-03-30 |
| Android 36 | Pixel 9 Pro XL | A | `win11-x64` | 2025-04-17 |
<details>
<summary><b>Configurations</b> (click to show)</summary>
Configuration A:
- Ionic: `@ionic/angular 8.2.0`, `@ionic/angular-toolkit 11.0.1`
- Cordova: `cordova-lib@12.0.1`, `android 13.0.0, ios 7.1.0`
- File Integration: `@awesome-cordova-plugins/file` version `6.7.0`
- Ionic: `@ionic/angular 8.5.2`, `@ionic/angular-toolkit 12.1.1`
- Cordova: `cordova-lib@12.0.2`, `android 14.0.0`
- File Integration: `@awesome-cordova-plugins/file` version `6.16.0`
Configuration B:
@ -394,6 +395,11 @@ In the `application` tag, add the attribute `android:requestLegacyExternalStorag
ionic cordova emulate android
```
If prompted to share pseudonymous usage data with Google, type <kbd>N</kbd> and
press <kbd>Enter</kbd> to opt out.
If prompted to share anonymous usage data with Cordova, type <kbd>N</kbd>.
When the app is loaded, a list of Presidents should be displayed. This list is
dynamically generated by fetching and parsing a test file.
@ -433,7 +439,7 @@ In a test run, the output showed a Pixel 3a with the following details:
// highlight-next-line
Name: Pixel_3a_API_34
Device: pixel_3a (Google)
Path: /Users/SheetJS/.android/avd/Pixel_4_API_33.avd
Path: /Users/SheetJS/.android/avd/Pixel_3a_API_34.avd
```
The Ionic command accepts a `--target` flag. Pass the emulator name:
@ -460,6 +466,8 @@ On macOS, this issue was resolved by installing Gradle with Homebrew manager:
brew install gradle
```
In Windows, Gradle must be installed manually[^11]
:::
:::danger pass
@ -681,3 +689,4 @@ the file with the new line.
[^8]: See [`write` in "Writing Files"](/docs/api/write-options)
[^9]: See ["Developing for iOS"](https://ionic-docs-o31kiyk8l-ionic1.vercel.app/docs/v6/developing/ios) and ["Developing for Android"](https://ionic-docs-o31kiyk8l-ionic1.vercel.app/docs/v6/developing/android). The Ionic team removed these pages from the official docs site and recommend the `vercel.app` docs site.
[^10]: See the [JDK Archive](https://jdk.java.net/archive/) for Java 17 JDK download links.
[^11]: See ["Installing manually"](https://gradle.org/install/#manually) in the Gradle documentation.

@ -39,6 +39,7 @@ This demo was tested in the following deployments:
| OS and Version | Architecture | Excel | Date |
|:---------------|:-------------|:-----------|:-----------|
| macOS 15.3 | `darwin-x64` | 16.95.4 | 2025-04-17 |
| macOS 14.5 | `darwin-arm` | 16.81 | 2024-12-22 |
| Windows 11 | `win11-x64` | 365 (2501) | 2025-01-19 |
@ -57,13 +58,7 @@ Excel 365 before running the demo.
The Office Add-in CLI collects telemetry by default. It can be disabled:
```js
npx office-addin-usage-data off
```
The setting can be verified by running:
```js
npx office-addin-usage-data list
npx -y office-addin-usage-data off
```
:::
@ -156,7 +151,7 @@ after testing is finished.
3) Disable telemetry:
```bash
npx office-addin-usage-data off
npx -y office-addin-usage-data off
```
4) Install dependencies:
@ -165,21 +160,31 @@ npx office-addin-usage-data off
npm i -g yo bower generator-office
```
:::note pass
In some systems, the command must be run with the root user:
```bash
sudo npm i -g yo bower generator-office
```
:::
### Creating a new Add-in
5) Run the generator:
```bash
npx yo office
npx -y yo office
```
The generator will ask a few questions:
- "Choose a project type": "Excel Custom Functions using a Shared Runtime"
- "Choose a project type": Select `Excel Custom Functions using a Shared Runtime`
- "Choose a script type": "JavaScript",
- "Choose a script type": Select `JavaScript`
- "What do you want to name your add-in?": "SheetJSImport"
- "What do you want to name your add-in?": Type `SheetJSImport` and press <kbd>Enter</kbd>
The generator will create the project and install dependencies.
@ -237,7 +242,7 @@ npm start
### Integrating the SheetJS Library
10) Install the SheetJS library in the project
10) Install the SheetJS library in the project:
<CodeBlock language="bash">{`\
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}

@ -25,9 +25,10 @@ library to export a bitfield table from Apple Numbers to a XLSX workbook.
This demo was tested by SheetJS users in the following deployments:
| Architecture | Ghidra | Date |
|:-------------|:---------|:-----------|
| `darwin-arm` | `11.13.1`| 2025-03-17 |
| Architecture | Ghidra | Date |
|:-------------|:----------|:-----------|
| `darwin-x64` | `11.13.1` | 2025-04-17 |
| `darwin-arm` | `11.13.1` | 2025-03-17 |
:::
@ -229,7 +230,7 @@ const src = decomp.getDecompiledFunction().getC();
## Complete Demo
In this demo, we will inspect the `_TSTCellToCellStorage` method within the
`TSTables` framework of Apple Numbers 14.2. This particular method handles
`TSTables` framework of Apple Numbers 14.4. This particular method handles
serialization of cells to the NUMBERS file format.
The implementation has a number of blocks which look like the following script:

@ -1114,6 +1114,7 @@ This demo was tested in the following deployments:
|:-------------|:--------|:-----------|
| `darwin-x64` | `2.2.1` | 2025-03-31 |
| `darwin-arm` | `2.2.1` | 2025-03-31 |
| `win11-x64` | `2.2.1` | 2025-04-17 |
:::

@ -78,7 +78,7 @@ Spreadsheet applications commonly display file properties in separate windows:
:::note pass
When this demo was last tested, Apple Numbers 14.2 did not support file
When this demo was last tested, Apple Numbers 14.4 did not support file
properties in the XLSX import and export codecs.
:::

@ -66,7 +66,7 @@ format has a limit of 2048 rows, so data after the 2048th row will not be saved.
|:------------------------------------------|:-----------|---------:|---------:|
| Excel 2007+ XML Formats (XLSX/XLSM) |`XFD1048576`| 16384 | 1048576 |
| Excel 2007+ Binary Format (XLSB BIFF12) |`XFD1048576`| 16384 | 1048576 |
| Numbers 14.2 (NUMBERS) |`ALL1000000`| 1000 | 1000000 |
| Numbers 14.4 (NUMBERS) |`ALL1000000`| 1000 | 1000000 |
| Quattro Pro 9+ (QPW) |`IV1000000 `| 256 | 1000000 |
| Excel 97-2004 (XLS BIFF8) |`IV65536 `| 256 | 65536 |
| Excel 5.0/95 (XLS BIFF5) |`IV16384 `| 256 | 16384 |
@ -202,7 +202,7 @@ XLR also includes a `WksSSWorkBook` stream similar to Lotus FM3/FMT files.
iWork 2013 (Numbers 3.0 / Pages 5.0 / Keynote 6.0) switched from a proprietary
XML-based format to the current file format based on the iWork Archive (IWA).
This format has been used up through the current release (Numbers 14.2) as well
This format has been used up through the current release (Numbers 14.4) as well
as the iCloud.com web interface to Numbers.
The parser focuses on extracting raw data from tables. Numbers technically

@ -60,7 +60,7 @@ src.split(/[\r\n]+/).reduce((acc,row,i) => {
const aoo = offset.map((name, idx) => ({
Mask: "0x" + (1 << idx).toString(16),
"Internal Name": name.replace(/^PTR_s_|_[0-9a-f]*$/g,"").replace(/[A-Z]/g, " $&").toLowerCase().replace(/ i d/, " ID")
}));
})).filter(x => x);
/* create worksheet */
const ws = json_to_sheet(aoo);

@ -0,0 +1,68 @@
<template>
<q-page class="row items-center justify-evenly">
<q-table :rows="todos" />
<q-btn-group>
<q-file v-model="file" label="Load File" filled label-color="orange" @input="updateFile"/>
<q-btn label="Save File" @click="saveFile" />
</q-btn-group>
</q-page>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { read, write, utils } from 'xlsx';
import { useQuasar } from 'quasar';
import type { Todo } from 'components/models';
const $q = useQuasar();
const todos = ref<Todo[]>([
{ id: 1, content: 'ct1' },
{ id: 2, content: 'ct2' },
{ id: 3, content: 'ct3' },
{ id: 4, content: 'ct4' },
{ id: 5, content: 'ct5' }
]);
const file = ref<File>();
function dialogerr(e: any) { $q.dialog({title: "Error!", message: e?.message || String(e)}); }
function saveFile() {
/* generate workbook from state */
const ws = utils.json_to_sheet(todos.value);
const wb = utils.book_new(ws, "SheetJSQuasar");
const u8: Uint8Array = write(wb, {bookType: "xlsx", type: "buffer"});
const dir: string = $q.cordova.file.documentsDirectory || $q.cordova.file.externalApplicationStorageDirectory;
/* save to file */
window.requestFileSystem(window.PERSISTENT, 0, function(fs) {
try {
fs.root.getFile("SheetJSQuasar.xlsx", {create: true}, entry => {
const msg = `File stored at ${dir} ${entry.fullPath}`;
entry.createWriter(writer => {
try {
const data = new Blob([u8], {type: "application/vnd.ms-excel"});
writer.onwriteend = () => {
try {
$q.dialog({title: "Success!", message: msg});
} catch(e) { dialogerr(e); }
};
writer.onerror = dialogerr;
writer.write(data);
} catch(e) { dialogerr(e); }
}, dialogerr);
}, dialogerr);
} catch(e) { dialogerr(e) }
}, dialogerr);
}
async function updateFile(v: Event) {
try {
const files = (v.target as HTMLInputElement).files;
if(!files || files.length == 0 || !files[0]) return;
const wb = read(await files[0].arrayBuffer());
const data = utils.sheet_to_json<any>(wb.Sheets[wb.SheetNames[0]!]!);
todos.value = data.map(row => ({id: row.Index, content: row.Name}));
} catch(e) { dialogerr(e); }
}
</script>

@ -3,13 +3,12 @@
cd /tmp
rm -rf sheetjs-worker
. ~/.bashrc ## This is apparently needed in macos
mkdir sheetjs-worker
cd sheetjs-worker
echo '{ "type": "module" }' > package.json
npm i --save https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz express@4.18.2 formidable@2.1.2
cat >worker.js <<EOF
/* load the worker_threads module */
import { parentPort } from 'node:worker_threads';
@ -70,11 +69,16 @@ app.post('/', (req, res, next) => {
app.listen(7262, () => { console.log(\`Example app listening on port 7262\`); });
EOF
# this version uses `n` to cycle through node versions
for n in 18 20 22; do
sudo n $n
node --version
npx -y concurrently -k 'node main.mjs' 'sleep 2; curl -X POST -F upload=@pres.numbers http://localhost:7262/ -J -O'
npx -y xlsx-cli SheetJSPool.xlsx
rm -f SheetJSPool.xlsx
npm i --save https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz formidable@2.1.2
for express in 4.21.2 5.1.0; do
npm i --save express@$express
npm ls | grep express
# this version uses `nvm` to cycle through node versions
for n in 18 20 22; do
nvm use $n
node --version
npx -y concurrently -k 'node main.mjs' 'sleep 2; curl -X POST -F upload=@pres.numbers http://localhost:7262/ -J -O'
npx -y xlsx-cli SheetJSPool.xlsx
rm -f SheetJSPool.xlsx
done
done