forked from sheetjs/docs.sheetjs.com
		
	rnm
This commit is contained in:
		
							parent
							
								
									be15eb3620
								
							
						
					
					
						commit
						4dd53501ff
					
				@ -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
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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:
 | 
			
		||||
 | 
			
		||||
<CodeBlock language="bash">{`\
 | 
			
		||||
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`}
 | 
			
		||||
</CodeBlock>
 | 
			
		||||
 | 
			
		||||
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.
 | 
			
		||||
 | 
			
		||||
@ -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 |
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
@ -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:
 | 
			
		||||
 | 
			
		||||
<table><thead><tr>
 | 
			
		||||
  <th><a href="#windows-demo">Win10</a></th>
 | 
			
		||||
@ -41,8 +42,6 @@ The "Complete Example" creates an app that looks like the screenshots below:
 | 
			
		||||
 | 
			
		||||
</td></tr></tbody></table>
 | 
			
		||||
 | 
			
		||||
<details><summary><b>Tested Environments</b> (click to show)</summary>
 | 
			
		||||
 | 
			
		||||
:::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.
 | 
			
		||||
 | 
			
		||||
<table><thead><tr><th>Spreadsheet</th><th>Array of Arrays</th></tr></thead><tbody><tr><td>
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
</td><td>
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
[
 | 
			
		||||
  ["Name", "Index"],
 | 
			
		||||
  ["Bill Clinton", 42],
 | 
			
		||||
  ["GeorgeW Bush", 43],
 | 
			
		||||
  ["Barack Obama", 44],
 | 
			
		||||
  ["Donald Trump", 45],
 | 
			
		||||
  ["Joseph Biden", 46]
 | 
			
		||||
]
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
</td></tr></tbody></table>
 | 
			
		||||
 | 
			
		||||
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.
 | 
			
		||||
 | 
			
		||||
<details><summary><b>Explanation</b> (click to show)</summary>
 | 
			
		||||
 | 
			
		||||
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) => ( <Row key={R} /> ));
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
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 (
 | 
			
		||||
    <SafeAreaView>
 | 
			
		||||
      <ScrollView contentInsetAdjustmentBehavior="automatic">
 | 
			
		||||
        {/* Table Container */}
 | 
			
		||||
        <View>{
 | 
			
		||||
          /* Loop over the row indices */
 | 
			
		||||
          // highlight-next-line
 | 
			
		||||
          Array.from({length: aoa.length}, (_, R) => (
 | 
			
		||||
            /* Table Row */
 | 
			
		||||
            <View key={R}>{
 | 
			
		||||
              /* Loop over the column indices */
 | 
			
		||||
              // highlight-next-line
 | 
			
		||||
              Array.from({length: max_cols}, (_, C) => (
 | 
			
		||||
                /* Table Cell */
 | 
			
		||||
                <View key={C}>
 | 
			
		||||
                   // highlight-next-line
 | 
			
		||||
                  <Text>{String(aoa?.[R]?.[C]??"")}</Text>
 | 
			
		||||
                </View>
 | 
			
		||||
              ))
 | 
			
		||||
            }</View>
 | 
			
		||||
          ))
 | 
			
		||||
        }</View>
 | 
			
		||||
      </ScrollView>
 | 
			
		||||
    </SafeAreaView>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
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):
 | 
			
		||||
 | 
			
		||||
<Tabs groupId="shell">
 | 
			
		||||
  <TabItem value="pwsh" label="PowerShell">
 | 
			
		||||
 | 
			
		||||
```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
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
  </TabItem>
 | 
			
		||||
  <TabItem value="bash" label="WSL Bash">
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
curl -LO https://docs.sheetjs.com/reactnative/desktop/App.tsx
 | 
			
		||||
curl -LO https://docs.sheetjs.com/reactnative/rnw/App.tsx
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
  </TabItem>
 | 
			
		||||
@ -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:
 | 
			
		||||
 | 
			
		||||
<CodeBlock language="bash">{`\
 | 
			
		||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
 | 
			
		||||
</CodeBlock>
 | 
			
		||||
 | 
			
		||||
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 <React/RCTBridgeModule.h>
 | 
			
		||||
@ -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 <Foundation/Foundation.h>
 | 
			
		||||
@ -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 = "<group>"; };
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
:::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 (
 | 
			
		||||
    <SafeAreaView style={styles.outer}>
 | 
			
		||||
      <Text style={styles.title}>SheetJS × React Native MacOS {version}</Text>
 | 
			
		||||
      <TouchableHighlight onPress={async() => {
 | 
			
		||||
        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}`); }
 | 
			
		||||
      }}><Text style={styles.button}>Click here to Open File!</Text></TouchableHighlight>
 | 
			
		||||
      <ScrollView contentInsetAdjustmentBehavior="automatic">
 | 
			
		||||
        <View style={styles.table}>{aoa.map((row,R) => (
 | 
			
		||||
          <View style={styles.row} key={R}>{row.map((cell,C) => (
 | 
			
		||||
            <View style={styles.cell} key={C}><Text>{cell}</Text></View>
 | 
			
		||||
          ))}</View>
 | 
			
		||||
        ))}</View>
 | 
			
		||||
      </ScrollView>
 | 
			
		||||
    </SafeAreaView>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
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 <https://sheetjs.com/pres.xlsx>, 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 <https://sheetjs.com/pres.xlsx>.
 | 
			
		||||
 | 
			
		||||
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".
 | 
			
		||||
@ -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
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 108 KiB  | 
							
								
								
									
										42
									
								
								docz/static/reactnative/rnm/App.tsx
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										42
									
								
								docz/static/reactnative/rnm/App.tsx
									
									
									
									
									
										Normal file
									
								
							@ -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 (
 | 
			
		||||
    <SafeAreaView style={styles.outer}>
 | 
			
		||||
      <Text style={styles.title}>SheetJS × React Native MacOS {version}</Text>
 | 
			
		||||
      <TouchableHighlight onPress={async() => {
 | 
			
		||||
        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}`); }
 | 
			
		||||
      }}><Text style={styles.button}>Click here to Open File!</Text></TouchableHighlight>
 | 
			
		||||
      <ScrollView contentInsetAdjustmentBehavior="automatic">
 | 
			
		||||
        <View style={styles.table}>{Array.from({length: aoa.length}, (_, R) => (
 | 
			
		||||
          <View style={styles.row} key={R}>{Array.from({length: max_cols}, (_, C) => (
 | 
			
		||||
            <View style={styles.cell} key={C}><Text>{String(aoa?.[R]?.[C]??"")}</Text></View>
 | 
			
		||||
          ))}</View>
 | 
			
		||||
        ))}</View>
 | 
			
		||||
      </ScrollView>
 | 
			
		||||
    </SafeAreaView>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
							
								
								
									
										3
									
								
								docz/static/reactnative/rnm/RCTDocumentPicker.h
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										3
									
								
								docz/static/reactnative/rnm/RCTDocumentPicker.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,3 @@
 | 
			
		||||
#import <React/RCTBridgeModule.h>
 | 
			
		||||
@interface RCTDocumentPicker : NSObject <RCTBridgeModule>
 | 
			
		||||
@end
 | 
			
		||||
							
								
								
									
										30
									
								
								docz/static/reactnative/rnm/RCTDocumentPicker.m
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										30
									
								
								docz/static/reactnative/rnm/RCTDocumentPicker.m
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,30 @@
 | 
			
		||||
#import <Foundation/Foundation.h>
 | 
			
		||||
#import <React/RCTUtils.h>
 | 
			
		||||
 | 
			
		||||
#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
 | 
			
		||||
@ -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 (
 | 
			
		||||
    <SafeAreaView style={styles.outer}>
 | 
			
		||||
@ -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}`); }
 | 
			
		||||
      }}><Text style={styles.button}>Click here to Open File!</Text></TouchableHighlight>
 | 
			
		||||
      <ScrollView contentInsetAdjustmentBehavior="automatic">
 | 
			
		||||
        <View style={styles.table}>{aoa.map((row,R) => (
 | 
			
		||||
          <View style={styles.row} key={R}>{row.map((cell,C) => (
 | 
			
		||||
            <View style={styles.cell} key={C}><Text>{cell}</Text></View>
 | 
			
		||||
        <View style={styles.table}>{Array.from({length: aoa.length}, (_, R) => (
 | 
			
		||||
          <View style={styles.row} key={R}>{Array.from({length: max_cols}, (_, C) => (
 | 
			
		||||
            <View style={styles.cell} key={C}><Text>{String(aoa?.[R]?.[C]??"")}</Text></View>
 | 
			
		||||
          ))}</View>
 | 
			
		||||
        ))}</View>
 | 
			
		||||
      </ScrollView>
 | 
			
		||||
@ -38,4 +39,4 @@ const styles = StyleSheet.create({
 | 
			
		||||
  button: { marginTop: 8, fontSize: 18, fontWeight: '400', },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export default App;
 | 
			
		||||
export default App;
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user