diff --git a/docz/docs/02-getting-started/01-installation/04-amd.md b/docz/docs/02-getting-started/01-installation/04-amd.md
index b523a77..6716a9a 100644
--- a/docz/docs/02-getting-started/01-installation/04-amd.md
+++ b/docz/docs/02-getting-started/01-installation/04-amd.md
@@ -36,8 +36,8 @@ new versions are released!
## NetSuite
-After downloading the script, it can be referenced directly in `define` calls
-in SuiteScripts:
+After uploading the script to the File Cabinet, it can be referenced directly in
+`define` calls in SuiteScripts:
```js
define(['N/file', './xlsx.full.min'], function(file, XLSX) {
@@ -45,8 +45,8 @@ define(['N/file', './xlsx.full.min'], function(file, XLSX) {
})
```
-As explained in the [NetSuite demo](/docs/demos/cloud/netsuite), module
-aliases are created in config files referenced via `@NAmdConfig` comments.
+As explained in the [NetSuite demo](/docs/demos/cloud/netsuite), module aliases
+can be created in config files referenced via `@NAmdConfig` comments.
## SAP UI5
diff --git a/docz/docs/03-demos/04-static/08-nextjs.md b/docz/docs/03-demos/04-static/08-nextjs.md
index f0ab7e1..3de945c 100644
--- a/docz/docs/03-demos/04-static/08-nextjs.md
+++ b/docz/docs/03-demos/04-static/08-nextjs.md
@@ -54,13 +54,13 @@ module.exports = {
NextJS collects telemetry by default. The `telemetry` subcommand can disable it:
```js
-npx next@13.4.4 telemetry disable
+npx next@13.4.12 telemetry disable
```
The setting can be verified by running
```js
-npx next@13.4.4 telemetry status
+npx next@13.4.12 telemetry status
```
:::
@@ -69,10 +69,11 @@ npx next@13.4.4 telemetry status
The following deployments were tested:
-| NextJS | Date |
-|:-------|:-----------|
-| 13.1.1 | 2023-01-14 |
-| 13.4.4 | 2023-05-26 |
+| NextJS | NodeJS | Date |
+|:--------|:----------|:-----------|
+| 11.1.4 | `16.20.1` | 2023-07-23 |
+| 12.3.4 | `18.17.0` | 2023-07-23 |
+| 13.4.12 | `18.17.0` | 2023-07-23 |
:::
@@ -503,6 +504,9 @@ This demo showcases the following SheetJS + NextJS flows:
| `/sheets/[id]` | asset module | `getStaticPaths` | `sheet_to_html` |
| `/getServerSideProps` | lifecycle | `getServerSideProps` | `sheet_to_html` |
+The commands in this demo use `next@13.4.12`. Other versions were tested by
+replacing the version number in the relevant commands.
+
:::
### Initial Setup
@@ -510,13 +514,13 @@ This demo showcases the following SheetJS + NextJS flows:
0) Disable NextJS telemetry:
```js
-npx next@13.4.4 telemetry disable
+npx next@13.4.12 telemetry disable
```
Confirm it is disabled by running
```js
-npx next@13.4.4 telemetry status
+npx next@13.4.12 telemetry status
```
1) Set up folder structure. At the end, a `pages` folder with a `sheets`
@@ -538,7 +542,7 @@ curl -LO https://docs.sheetjs.com/next/sheetjs.xlsx
3) Install dependencies:
{`\
-npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz next@13.4.4`}
+npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz next@13.4.12`}
4) Download NextJS config scripts and place in the root folder:
@@ -596,7 +600,7 @@ cd ../..
6) Test the deployment:
```bash
-npx next@13.4.4
+npx next@13.4.12
```
Open a web browser and access:
@@ -622,20 +626,20 @@ After saving the file, the website should refresh with the new row.
8) Stop the server and run a production build:
```bash
-npx next@13.4.4 build
+npx next@13.4.12 build
```
The final output will show a list of the routes and types:
```
Route (pages) Size First Load JS
-┌ ○ / 563 B 74.4 kB
-├ /_app 0 B 73.9 kB
-├ ○ /404 182 B 74.1 kB
-├ λ /getServerSideProps 522 B 74.4 kB
-├ ● /getStaticPaths 2.89 kB 76.8 kB
-├ ● /getStaticProps 586 B 74.5 kB
-└ ● /sheets/[id] 522 B 74.4 kB
+┌ ○ / 563 B 75.3 kB
+├ /_app 0 B 74.8 kB
+├ ○ /404 182 B 75 kB
+├ λ /getServerSideProps 522 B 75.3 kB
+├ ● /getStaticPaths 2.91 kB 77.7 kB
+├ ● /getStaticProps 586 B 75.4 kB
+└ ● /sheets/[id] (303 ms) 522 B 75.3 kB
├ /sheets/0
└ /sheets/1
```
@@ -647,7 +651,7 @@ worksheets in the file. `/getServerSideProps` is server-rendered.
9) Try to build a static site:
```bash
-npx next@13.4.4 export
+npx next@13.4.12 export
```
:::note The static export will fail!
@@ -663,19 +667,19 @@ is still server-rendered.
```bash
rm -f pages/getServerSideProps.js
-npx next@13.4.4 build
+npx next@13.4.12 build
```
Inspecting the output, there should be no lines with the `λ` symbol:
```
Route (pages) Size First Load JS
-┌ ○ / 563 B 74.4 kB
-├ /_app 0 B 73.9 kB
-├ ○ /404 182 B 74.1 kB
-├ ● /getStaticPaths 2.89 kB 76.8 kB
-├ ● /getStaticProps 586 B 74.5 kB
-└ ● /sheets/[id] 522 B 74.4 kB
+┌ ○ / 563 B 75.3 kB
+├ /_app 0 B 74.8 kB
+├ ○ /404 182 B 75 kB
+├ ● /getStaticPaths 2.91 kB 77.7 kB
+├ ● /getStaticProps 586 B 75.4 kB
+└ ● /sheets/[id] 522 B 75.3 kB
├ /sheets/0
└ /sheets/1
```
@@ -683,7 +687,7 @@ Route (pages) Size First Load JS
11) Generate the static site:
```bash
-npx next@13.4.4 export
+npx next@13.4.12 export
```
The static site will be written to the `out` subfolder
@@ -694,5 +698,6 @@ The static site will be written to the `out` subfolder
npx http-server out
```
-The command will start a local HTTP server for testing the generated site. Note
-that `/getServerSideProps` will 404 since the page was removed.
+The command will start a local HTTP server at `http://localhost:8080/` for
+testing the generated site. Note that `/getServerSideProps` will 404 since the
+page was removed.
diff --git a/docz/docs/03-demos/04-static/09-nuxtjs.md b/docz/docs/03-demos/04-static/09-nuxtjs.md
index f308793..1ffe7a0 100644
--- a/docz/docs/03-demos/04-static/09-nuxtjs.md
+++ b/docz/docs/03-demos/04-static/09-nuxtjs.md
@@ -20,7 +20,6 @@ The following deployments were tested:
| Nuxt Content | Nuxt | Date |
|:-------------|:---------|:-----------|
| `1.15.1` | `2.16.3` | 2023-06-01 |
-| `2.3.0` | `3.0.0` | 2023-01-19 |
| `2.6.0` | `3.5.2` | 2023-06-01 |
:::
diff --git a/docz/docs/03-demos/06-desktop/06-reactnative.md b/docz/docs/03-demos/06-desktop/06-reactnative.md
index d8d4217..ac416aa 100644
--- a/docz/docs/03-demos/06-desktop/06-reactnative.md
+++ b/docz/docs/03-demos/06-desktop/06-reactnative.md
@@ -1,5 +1,7 @@
---
title: React Native
+sidebar_label: React Native
+description: Build data-intensive desktop apps with React Native. Seamlessly integrate spreadsheets into your app using SheetJS. Securely process and generate Excel files at the desk.
pagination_prev: demos/mobile/index
pagination_next: demos/data/index
sidebar_position: 6
@@ -7,26 +9,25 @@ sidebar_custom_props:
summary: Native Components with React
---
+# Sheets on the Desktop with React Native
+
import current from '/version.js';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeBlock from '@theme/CodeBlock';
-:::note
-
-This section covers React Native for desktop applications. For iOS and Android
-applications, [check the mobile demo](/docs/demos/mobile/reactnative)
-
-:::
-
-React Native for Windows + macOS is a backend for React Native that supports
+React Native for Windows + macOS[^1] is a backend for React Native that supports
native apps. The Windows backend builds apps for use on Windows 10 / 11, Xbox,
and other supported platforms. The macOS backend supports macOS 10.14 SDK
-The [NodeJS Module](/docs/getting-started/installation/nodejs) can be imported
-from the main app script. File operations must be written in native code.
+[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
+data from spreadsheets.
-The "Complete Example" creates an app that looks like the screenshots below:
+This demo uses React Native for Windows + macOS and SheetJS to process
+spreadsheets. We'll explore how to load SheetJS in a React Native deskktop app
+and create native modules for selecting and reading files from the computer.
+
+The Windows and macOS demos create apps that look like the screenshots below:
Win10 |
@@ -41,8 +42,6 @@ The "Complete Example" creates an app that looks like the screenshots below:
-Tested Environments (click to show)
-
:::note
This demo was tested in the following environments:
@@ -51,13 +50,169 @@ This demo was tested in the following environments:
|:---------------|:-----|:------------|:-----------|
| Windows 10 | x64 | `v0.70.10` | 2023-01-04 |
| Windows 11 | x64 | `v0.71.11` | 2023-05-11 |
-| MacOS 12.4 | x64 | `v0.64.30` | 2023-01-04 |
+| MacOS 12.6 | x64 | `v0.71.26` | 2023-07-23 |
| MacOS 13.4 | arm | `v0.71.18` | 2023-07-06 |
:::
+:::info pass
+
+This section covers React Native for desktop applications. For iOS and Android
+applications, [check the mobile demo](/docs/demos/mobile/reactnative)
+
+:::
+
+## Integration Details
+
+The [SheetJS NodeJS Module](/docs/getting-started/installation/nodejs) can be
+imported from the main `App.js` entrypoint or any script in the project.
+
+### Internal State
+
+For simplicity, this demo uses an "Array of Arrays"[^2] as the internal state.
+
+Spreadsheet | Array of Arrays |
---|
+
+![`pres.xlsx` data](pathname:///pres.png)
+
+ |
+
+```js
+[
+ ["Name", "Index"],
+ ["Bill Clinton", 42],
+ ["GeorgeW Bush", 43],
+ ["Barack Obama", 44],
+ ["Donald Trump", 45],
+ ["Joseph Biden", 46]
+]
+```
+
+ |
+
+Each array within the structure corresponds to one row.
+
+The state is initialized with the following snippet:
+
+```js
+const [ aoa, setAoA ] = useState(["SheetJS".split(""), "5433795".split("")]);
+```
+
+#### Updating State
+
+Starting from a SheetJS worksheet object, `sheet_to_json`[^3] with the `header`
+option can generate an array of arrays:
+
+```js
+/* assuming `wb` is a SheetJS workbook */
+function update_state(wb) {
+ /* convert first worksheet to AOA */
+ const wsname = wb.SheetNames[0];
+ const ws = wb.Sheets[wsname];
+ const data = utils.sheet_to_json(ws, {header:1});
+
+ /* update state */
+ setAoA(data);
+}
+```
+
+### Displaying Data
+
+The demos use native `View` elements from `react-native` to display data.
+
+Explanation (click to show)
+
+Since some spreadsheets may have empty cells between cells containing data,
+looping over the rows may skip values!
+
+This example explicitly loops over the row and column indices.
+
+**Determining the Row Indices**
+
+The first row index is `0` and the last row index is `aoa.length - 1`. This
+corresponds to the `for` loop:
+
+```js
+for(var R = 0; R < aoa.length; ++R) {/* ... */}
+```
+
+**Determining the Column Indices**
+
+The first column index is `0` and the last column index must be calculated from
+the maximum column index across every row.
+
+Traditionally this would be implemented in a `for` loop:
+
+```js
+var max_col_index = 0;
+for(var R = 0; R < aoa.length; ++R) {
+ if(!aoa[R]) continue;
+ max_col_index = Math.max(max_col_index, aoa[R].length - 1);
+}
+```
+
+`Array#reduce` simplifies this calculation:
+
+```js
+const max_col_index = aoa.reduce((C,row) => Math.max(C,row.length), 1) - 1;
+```
+
+**Looping from 0 to N-1**
+
+Traditionally a `for` loop would be used:
+
+```js
+var data = [];
+for(var R = 0; R < max_row; ++R) data[R] = func(R);
+```
+
+For creating an array of React Native components, `Array.from` should be used:
+
+```jsx
+var children = Array.from({length: max_row}, (_,R) => (
));
+```
+
+The relevant parts for rendering data are shown below:
+
+```jsx
+import React, { useState, type FC } from 'react';
+import { SafeAreaView, ScrollView, Text, View } from 'react-native';
+
+const App: FC = () => {
+ const [ aoa, setAoA ] = useState(["SheetJS".split(""), "5433795".split("")]);
+ const max_cols = aoa.reduce((acc,row) => Math.max(acc,row.length),1);
+
+ return (
+
+
+ {/* Table Container */}
+ {
+ /* Loop over the row indices */
+ // highlight-next-line
+ Array.from({length: aoa.length}, (_, R) => (
+ /* Table Row */
+ {
+ /* Loop over the column indices */
+ // highlight-next-line
+ Array.from({length: max_cols}, (_, C) => (
+ /* Table Cell */
+
+ // highlight-next-line
+ {String(aoa?.[R]?.[C]??"")}
+
+ ))
+ }
+ ))
+ }
+
+
+ );
+};
+export default App;
+```
+
## Native Modules
:::caution
@@ -70,8 +225,7 @@ assumes some familiarity with Objective-C.
:::
-React Native for Windows + macOS use [Turbo Modules](https://reactnative.dev/docs/the-new-architecture/pillars-turbomodules)
-for effortless integration with native libraries and code.
+React Native for Windows + macOS use Turbo Modules[^4] for native integrations.
The demos define a native module named `DocumentPicker`.
@@ -357,20 +511,20 @@ curl -Lo windows/SheetJSWin/DocumentPicker.h https://docs.sheetjs.com/reactnativ
Now the native module will be added to the app.
-4) Remove `App.js` (if it exists) and save the following to `App.tsx`:
+4) Remove `App.js` (if it exists) and download [`App.tsx`](https://docs.sheetjs.com/reactnative/rnw/App.tsx):
```bash
-iwr -Uri https://docs.sheetjs.com/reactnative/desktop/App.tsx -OutFile App.tsx
+iwr -Uri https://docs.sheetjs.com/reactnative/rnw/App.tsx -OutFile App.tsx
```
```bash
-curl -LO https://docs.sheetjs.com/reactnative/desktop/App.tsx
+curl -LO https://docs.sheetjs.com/reactnative/rnw/App.tsx
```
@@ -389,29 +543,31 @@ file picker to select the `pres.xlsx` file and the app will show the data.
## macOS Demo
-0) Follow the [React Native](https://reactnative.dev/docs/environment-setup)
- guide for React Native CLI on MacOS.
+0) Follow the "Setting up the development environment"[^5] guide in the React
+ Native documentation for "React Native CLI Quickstart" + "macOS" + "iOS".
-1) Create a new project using React Native `0.71`:
+### Project Setup
+
+1) Create a new React Native project using React Native `0.71`:
```bash
-npx react-native init SheetJSmacOS --template react-native@^0.71.0
+npx -y react-native init SheetJSmacOS --template react-native@^0.71.0
cd SheetJSmacOS
```
-Create the MacOS part of the application:
+2) Create the MacOS part of the application:
```bash
-npx react-native-macos-init --no-telemetry
+npx -y react-native-macos-init --no-telemetry
```
-Install the SheetJS library:
+3) Install the SheetJS library:
{`\
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
-To ensure that the app works, launch the app:
+4) To ensure that the app works, launch the app:
```bash
npx react-native run-macos
@@ -419,7 +575,10 @@ npx react-native run-macos
Close the running app from the dock and close the Metro terminal window.
-2) Create the file `macos/SheetJSmacOS-macOS/RCTDocumentPicker.h`:
+### Native Module
+
+5) Create the file `macos/SheetJSmacOS-macOS/RCTDocumentPicker.h` with the
+ following contents:
```objc title="macos/SheetJSmacOS-macOS/RCTDocumentPicker.h"
#import
@@ -427,7 +586,8 @@ Close the running app from the dock and close the Metro terminal window.
@end
```
-Create the file `macos/SheetJSmacOS-macOS/RCTDocumentPicker.m`:
+6) Create the file `macos/SheetJSmacOS-macOS/RCTDocumentPicker.m` with the
+ following contents:
```objc title="macos/SheetJSmacOS-macOS/RCTDocumentPicker.m"
#import
@@ -462,20 +622,26 @@ RCT_EXPORT_METHOD(PickAndRead:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromi
@end
```
-3) Edit the project file `macos/SheetJSmacOS.xcodeproj/project.pbxproj`.
+7) Edit the project file `macos/SheetJSmacOS.xcodeproj/project.pbxproj`.
There are four places where lines must be added:
-A) Immediately after `/* Begin PBXBuildFile section */`
+:::note pass
+
+A) Copy the highlighted line and paste under `/* Begin PBXBuildFile section */`:
```plist
/* Begin PBXBuildFile section */
// highlight-next-line
4717DC6A28CC499A00A9BE56 /* RCTDocumentPicker.m in Sources */ = {isa = PBXBuildFile; fileRef = 4717DC6928CC499A00A9BE56 /* RCTDocumentPicker.m */; };
- 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; };
+ 5142014D2437B4B30078DB4F /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5142014C2437B4B30078DB4F /* AppDelegate.mm */; };
```
-B) Immediately after `/* Begin PBXFileReference section */`
+:::
+
+:::note pass
+
+B) Copy the highlighted lines and paste under `/* Begin PBXFileReference section */`:
```plist
/* Begin PBXFileReference section */
@@ -486,6 +652,10 @@ B) Immediately after `/* Begin PBXFileReference section */`
008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = main.jsbundle; sourceTree = ""; };
```
+:::
+
+:::note pass
+
C) The goal is to add a reference to the `PBXSourcesBuildPhase` block for the
`macOS` target. To determine this, look in the `PBXNativeTarget section` for
a block with the comment `SheetJSmacOS-macOS`:
@@ -505,6 +675,9 @@ a block with the comment `SheetJSmacOS-macOS`:
Within the block, look for `buildPhases` and find the hex string for `Sources`:
```plist
+ 514201482437B4B30078DB4F /* SheetJSmacOS-macOS */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 5142015A2437B4B40078DB4F /* Build configuration list for PBXNativeTarget "SheetJSmacOS-macOS" */;
buildPhases = (
1A938104A937498D81B3BD3B /* [CP] Check Pods Manifest.lock */,
381D8A6F24576A6C00465D17 /* Start Packager */,
@@ -528,14 +701,17 @@ add the highlighted line:
files = (
// highlight-next-line
4717DC6A28CC499A00A9BE56 /* RCTDocumentPicker.m in Sources */,
- 514201502437B4B30078DB4F /* ViewController.m in Sources */,
514201582437B4B40078DB4F /* main.m in Sources */,
- 5142014D2437B4B30078DB4F /* AppDelegate.m in Sources */,
+ 5142014D2437B4B30078DB4F /* AppDelegate.mm in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
```
+:::
+
+:::note pass
+
D) The goal is to add file references to the "main group". Search for
`/* Begin PBXProject section */` and there should be one Project object.
Within the project object, look for `mainGroup`:
@@ -570,63 +746,57 @@ highlighted lines:
13B07FAE1A68108700A75B9A /* SheetJSmacOS-iOS */,
```
-4) Replace `App.tsx` with the following:
+:::
-```tsx title="App.tsx"
-import React, { useState, type Node } from 'react';
-import { SafeAreaView, ScrollView, StyleSheet, Text, TouchableHighlight, View } from 'react-native';
-import { read, utils, version } from 'xlsx';
-import { getEnforcing } from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
-const DocumentPicker = getEnforcing('DocumentPicker');
-
-const App: () => Node = () => {
-
- const [ aoa, setAoA ] = useState(["SheetJS".split(""), "5433795".split("")]);
-
- return (
-
- SheetJS × React Native MacOS {version}
- {
- try {
- const b64 = await DocumentPicker.PickAndRead();
- const wb = read(b64);
- setAoA(utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]], { header: 1 } ));
- } catch(err) { alert(`Error: ${err.message}`); }
- }}>Click here to Open File!
-
- {aoa.map((row,R) => (
- {row.map((cell,C) => (
- {cell}
- ))}
- ))}
-
-
- );
-};
-
-const styles = StyleSheet.create({
- cell: { flex: 4 },
- row: { flexDirection: 'row', justifyContent: 'space-evenly', padding: 10, backgroundColor: 'white', },
- table: { display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', },
- outer: { marginTop: 32, paddingHorizontal: 24, },
- title: { fontSize: 24, fontWeight: '600', },
- button: { marginTop: 8, fontSize: 18, fontWeight: '400', },
-});
-
-export default App;
-```
-
-5) Test the app:
+8) To ensure that the app still works, launch the app again:
```bash
npx react-native run-macos
```
-Download , then click on "open file". Use the
-file picker to select the `pres.xlsx` file and the app will show the data.
+Close the running app from the dock and close the Metro terminal window.
-6) Make a release build:
+### Application
+
+9) Download [`App.tsx`](https://docs.sheetjs.com/reactnative/rnm/App.tsx) and
+ replace the file in the project:
+
+```bash
+curl -LO https://docs.sheetjs.com/reactnative/rnm/App.tsx
+```
+
+10) Test the app:
+
+```bash
+npx react-native run-macos
+```
+
+Download .
+
+Click "Click here to Open File!" and use the file picker to select `pres.xlsx` .
+The app will refresh and display the data from the file.
+
+11) Make a release build:
```bash
xcodebuild -workspace macos/SheetJSmacOS.xcworkspace -scheme SheetJSmacOS-macOS -config Release
```
+
+The last line of the output will include the path to the app. If it is not
+displayed, the app path can be found in the `DerivedData` folder:
+
+```bash
+find ~/Library/Developer/Xcode/DerivedData -name SheetJSmacOS.app | grep Release
+```
+
+12) Run the release app:
+
+```bash
+open -a "$(find ~/Library/Developer/Xcode/DerivedData -name SheetJSmacOS.app | grep Release | head -n 1)"
+```
+
+[^1]: The [official website](https://microsoft.github.io/react-native-windows/) covers both platforms, but there are separate repositories for [Windows](https://github.com/microsoft/react-native-windows) and [macOS](https://github.com/microsoft/react-native-macos)
+[^2]: See ["Array of Arrays" in the API reference](/docs/api/utilities/array#array-of-arrays)
+[^3]: See ["Array Output" in "Utility Functions"](/docs/api/utilities/array#array-output)
+[^4]: See ["Turbo Native Modules"](https://reactnative.dev/docs/the-new-architecture/pillars-turbomodules) in the React Native documentation.
+[^5]: See ["Setting up the development environment"](https://reactnative.dev/docs/environment-setup) in the React Native documentation. Select the "React Native CLI Quickstart" tab and choose the Development OS "macOS" and the Target OS "iOS".
\ No newline at end of file
diff --git a/docz/docs/03-demos/09-cloud/04-netsuite.md b/docz/docs/03-demos/09-cloud/02-netsuite.md
similarity index 100%
rename from docz/docs/03-demos/09-cloud/04-netsuite.md
rename to docz/docs/03-demos/09-cloud/02-netsuite.md
diff --git a/docz/docs/03-demos/09-cloud/02-aws.md b/docz/docs/03-demos/09-cloud/11-aws.md
similarity index 100%
rename from docz/docs/03-demos/09-cloud/02-aws.md
rename to docz/docs/03-demos/09-cloud/11-aws.md
diff --git a/docz/docs/03-demos/09-cloud/09-azure.md b/docz/docs/03-demos/09-cloud/12-azure.md
similarity index 100%
rename from docz/docs/03-demos/09-cloud/09-azure.md
rename to docz/docs/03-demos/09-cloud/12-azure.md
diff --git a/docz/docs/03-demos/09-cloud/10-github.md b/docz/docs/03-demos/09-cloud/18-github.md
similarity index 97%
rename from docz/docs/03-demos/09-cloud/10-github.md
rename to docz/docs/03-demos/09-cloud/18-github.md
index afcab2e..7fce5b2 100644
--- a/docz/docs/03-demos/09-cloud/10-github.md
+++ b/docz/docs/03-demos/09-cloud/18-github.md
@@ -15,7 +15,7 @@ changes. Git can also store and track binary data artifacts.
GitHub is a popular host for Git repositories. GitHub's "Flat Data" project
explores storing and comparing versions of structured CSV and JSON data. The
-official "Excel to CSV" example uses SheetJS to generate CSV data from files:
+official "Excel to CSV"[^1] example uses SheetJS to generate CSV data from files:
```mermaid
sequenceDiagram
@@ -273,3 +273,5 @@ jobs:
The update process will run once an hour. If you return in a few hours and
refresh the page, there should be more commits in the selection list.
+
+[^1]: See ["Excel to CSV"](https://githubnext.com/projects/flat-data#:~:text=View%20code-,Excel,-to%20CSV) in the "Flat Data" writeup
\ No newline at end of file
diff --git a/docz/docs/03-demos/09-cloud/11-deno.md b/docz/docs/03-demos/09-cloud/19-deno.md
similarity index 100%
rename from docz/docs/03-demos/09-cloud/11-deno.md
rename to docz/docs/03-demos/09-cloud/19-deno.md
diff --git a/docz/docs/03-demos/09-cloud/03-gsheet.md b/docz/docs/03-demos/09-cloud/21-gsheet.md
similarity index 100%
rename from docz/docs/03-demos/09-cloud/03-gsheet.md
rename to docz/docs/03-demos/09-cloud/21-gsheet.md
diff --git a/docz/docs/03-demos/09-cloud/08-airtable.md b/docz/docs/03-demos/09-cloud/22-airtable.md
similarity index 100%
rename from docz/docs/03-demos/09-cloud/08-airtable.md
rename to docz/docs/03-demos/09-cloud/22-airtable.md
diff --git a/docz/docs/03-demos/09-cloud/05-dropbox.mdx b/docz/docs/03-demos/09-cloud/31-dropbox.mdx
similarity index 100%
rename from docz/docs/03-demos/09-cloud/05-dropbox.mdx
rename to docz/docs/03-demos/09-cloud/31-dropbox.mdx
diff --git a/docz/docs/03-demos/09-cloud/index.md b/docz/docs/03-demos/09-cloud/index.md
index 46b24c8..82996c8 100644
--- a/docz/docs/03-demos/09-cloud/index.md
+++ b/docz/docs/03-demos/09-cloud/index.md
@@ -28,6 +28,8 @@ form data. This can be disabled with cloud-specific configuration:
- [AWS Lambda Functions](/docs/demos/cloud/aws#aws-lambda-functions)
- [Azure Functions](/docs/demos/cloud/azure#azure-functions)
+- [GitHub Actions](/docs/demos/cloud/github)
+- [Deno Deploy](/docs/demos/cloud/deno)
## Cloud Storage
@@ -44,7 +46,6 @@ File hosting services provide simple solutions for storing data, synchronizing
files across devices, and sharing with specific users or customers. Demos:
- [Dropbox](/docs/demos/cloud/dropbox)
-- [GitHub](/docs/demos/cloud/github)
## Cloud Data
diff --git a/docz/static/reactnative/rnm.png b/docz/static/reactnative/rnm.png
index 3759114..b5a357e 100644
Binary files a/docz/static/reactnative/rnm.png and b/docz/static/reactnative/rnm.png differ
diff --git a/docz/static/reactnative/rnm/App.tsx b/docz/static/reactnative/rnm/App.tsx
new file mode 100644
index 0000000..169653b
--- /dev/null
+++ b/docz/static/reactnative/rnm/App.tsx
@@ -0,0 +1,42 @@
+import React, { useState, type FC } from 'react';
+import { SafeAreaView, ScrollView, StyleSheet, Text, TouchableHighlight, View, Alert } from 'react-native';
+import { read, utils, version } from 'xlsx';
+import { getEnforcing } from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
+const DocumentPicker = getEnforcing('DocumentPicker');
+
+const App: FC = () => {
+
+ const [ aoa, setAoA ] = useState(["SheetJS".split(""), "5433795".split("")]);
+ const max_cols = aoa.reduce((acc,row) => Math.max(acc,row.length),1);
+
+ return (
+
+ SheetJS × React Native MacOS {version}
+ {
+ try {
+ const b64 = await DocumentPicker.PickAndRead();
+ const wb = read(b64);
+ setAoA(utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]], { header: 1 } ));
+ } catch(err) { Alert.alert(`Read Error`, `${err instanceof Error ? err.message : err}`); }
+ }}>Click here to Open File!
+
+ {Array.from({length: aoa.length}, (_, R) => (
+ {Array.from({length: max_cols}, (_, C) => (
+ {String(aoa?.[R]?.[C]??"")}
+ ))}
+ ))}
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ cell: { flex: 4 },
+ row: { flexDirection: 'row', justifyContent: 'space-evenly', padding: 10, backgroundColor: 'white', },
+ table: { display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', },
+ outer: { marginTop: 32, paddingHorizontal: 24, },
+ title: { fontSize: 24, fontWeight: '600', },
+ button: { marginTop: 8, fontSize: 18, fontWeight: '400', },
+});
+
+export default App;
diff --git a/docz/static/reactnative/rnm/RCTDocumentPicker.h b/docz/static/reactnative/rnm/RCTDocumentPicker.h
new file mode 100644
index 0000000..d6ae774
--- /dev/null
+++ b/docz/static/reactnative/rnm/RCTDocumentPicker.h
@@ -0,0 +1,3 @@
+#import
+@interface RCTDocumentPicker : NSObject
+@end
\ No newline at end of file
diff --git a/docz/static/reactnative/rnm/RCTDocumentPicker.m b/docz/static/reactnative/rnm/RCTDocumentPicker.m
new file mode 100644
index 0000000..1cdd47f
--- /dev/null
+++ b/docz/static/reactnative/rnm/RCTDocumentPicker.m
@@ -0,0 +1,30 @@
+#import
+#import
+
+#import "RCTDocumentPicker.h"
+
+@implementation RCTDocumentPicker
+
+RCT_EXPORT_MODULE();
+
+RCT_EXPORT_METHOD(PickAndRead:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
+{
+ RCTExecuteOnMainQueue(^{
+ NSOpenPanel *panel = [NSOpenPanel openPanel];
+ [panel setCanChooseDirectories:NO];
+ [panel setAllowsMultipleSelection:NO];
+ [panel setMessage:@"Select a spreadsheet to read"];
+
+ [panel beginWithCompletionHandler:^(NSInteger result){
+ if (result == NSModalResponseOK) {
+ NSURL *selected = [[panel URLs] objectAtIndex:0];
+ NSFileHandle *hFile = [NSFileHandle fileHandleForReadingFromURL:selected error:nil];
+ if(hFile) {
+ NSData *data = [hFile readDataToEndOfFile];
+ resolve([data base64EncodedStringWithOptions:0]);
+ } else reject(@"read_failure", @"Could not read selected file!", nil);
+ } else reject(@"select_failure", @"No file selected!", nil);
+ }];
+ });
+}
+@end
\ No newline at end of file
diff --git a/docz/static/reactnative/desktop/App.tsx b/docz/static/reactnative/rnw/App.tsx
similarity index 70%
rename from docz/static/reactnative/desktop/App.tsx
rename to docz/static/reactnative/rnw/App.tsx
index fb4537d..63fda15 100644
--- a/docz/static/reactnative/desktop/App.tsx
+++ b/docz/static/reactnative/rnw/App.tsx
@@ -1,12 +1,13 @@
-import React, { useState, type Node } from 'react';
-import { SafeAreaView, ScrollView, StyleSheet, Text, TouchableHighlight, View } from 'react-native';
+import React, { useState, type FC } from 'react';
+import { SafeAreaView, ScrollView, StyleSheet, Text, TouchableHighlight, View, Alert } from 'react-native';
import { read, utils, version } from 'xlsx';
import { getEnforcing } from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
const DocumentPicker = getEnforcing('DocumentPicker');
-const App: () => Node = () => {
+const App: FC = () => {
const [ aoa, setAoA ] = useState(["SheetJS".split(""), "5433795".split("")]);
+ const max_cols = aoa.reduce((acc,row) => Math.max(acc,row.length),1);
return (
@@ -16,12 +17,12 @@ const App: () => Node = () => {
const b64 = await DocumentPicker.PickAndRead();
const wb = read(b64);
setAoA(utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]], { header: 1 } ));
- } catch(err) { alert(`Error: ${err.message}`); }
+ } catch(err) { Alert.alert(`Read Error`, `${err instanceof Error ? err.message : err}`); }
}}>Click here to Open File!
- {aoa.map((row,R) => (
- {row.map((cell,C) => (
- {cell}
+ {Array.from({length: aoa.length}, (_, R) => (
+ {Array.from({length: max_cols}, (_, C) => (
+ {String(aoa?.[R]?.[C]??"")}
))}
))}
@@ -38,4 +39,4 @@ const styles = StyleSheet.create({
button: { marginTop: 8, fontSize: 18, fontWeight: '400', },
});
-export default App;
\ No newline at end of file
+export default App;