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: @@ -41,8 +42,6 @@ The "Complete Example" creates an app that looks like the screenshots below:
Win10
-
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. + +
SpreadsheetArray 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;