forked from sheetjs/docs.sheetjs.com
		
	rnm
This commit is contained in:
		
							parent
							
								
									fc8923d20f
								
							
						
					
					
						commit
						bb95be789f
					
				
							
								
								
									
										12
									
								
								.spelling
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										12
									
								
								.spelling
									
									
									
									
									
								
							@ -7,6 +7,10 @@ docs.sheetjs.com
 | 
			
		||||
TabItem
 | 
			
		||||
DocCardList
 | 
			
		||||
 | 
			
		||||
# frontmatter noise
 | 
			
		||||
api
 | 
			
		||||
csf
 | 
			
		||||
 | 
			
		||||
# Excel-related terms
 | 
			
		||||
A1-Style
 | 
			
		||||
AutoFilter
 | 
			
		||||
@ -111,6 +115,7 @@ Auth
 | 
			
		||||
BOM
 | 
			
		||||
Base64
 | 
			
		||||
Base64-encoded
 | 
			
		||||
Big5
 | 
			
		||||
Booleans
 | 
			
		||||
Browserify
 | 
			
		||||
Bundlers
 | 
			
		||||
@ -139,11 +144,13 @@ ES5
 | 
			
		||||
ES6
 | 
			
		||||
ESM
 | 
			
		||||
ETH
 | 
			
		||||
Endian
 | 
			
		||||
Ethercalc
 | 
			
		||||
ExpressJS
 | 
			
		||||
ExtendScript
 | 
			
		||||
Fastify
 | 
			
		||||
FileReader
 | 
			
		||||
GBK
 | 
			
		||||
GatsbyJS
 | 
			
		||||
Goja
 | 
			
		||||
HTML
 | 
			
		||||
@ -222,6 +229,7 @@ SWF
 | 
			
		||||
Schemas
 | 
			
		||||
Serverless
 | 
			
		||||
SessionStorage
 | 
			
		||||
Shift-JIS
 | 
			
		||||
SlimerJS
 | 
			
		||||
Snowpack
 | 
			
		||||
SuiteScript
 | 
			
		||||
@ -321,7 +329,3 @@ vscode-data-preview
 | 
			
		||||
webpack
 | 
			
		||||
weex
 | 
			
		||||
wkhtmltopdf
 | 
			
		||||
 | 
			
		||||
# frontmatter noise
 | 
			
		||||
api
 | 
			
		||||
csf
 | 
			
		||||
 | 
			
		||||
@ -1124,7 +1124,7 @@ the `ItemGroup` that contains `ReactPackageProvider.cs`:
 | 
			
		||||
  </TabItem>
 | 
			
		||||
  <TabItem value="cpp" label="C++">
 | 
			
		||||
 | 
			
		||||
2) Create the file `windows\SheetJSWin\DocumentPicker.h` with the following:
 | 
			
		||||
4) Create the file `windows\SheetJSWin\DocumentPicker.h` with the following:
 | 
			
		||||
 | 
			
		||||
```cpp title="windows\SheetJSWin\DocumentPicker.h"
 | 
			
		||||
#pragma once
 | 
			
		||||
@ -1174,7 +1174,7 @@ namespace SheetJSWin {
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
3) Add the highlighted line to `windows\SheetJSWin\ReactPackageProvider.cpp`:
 | 
			
		||||
5) Add the highlighted line to `windows\SheetJSWin\ReactPackageProvider.cpp`:
 | 
			
		||||
 | 
			
		||||
```cpp title="windows\SheetJSWin\ReactPackageProvider.cpp"
 | 
			
		||||
#include "ReactPackageProvider.h"
 | 
			
		||||
@ -1188,7 +1188,7 @@ namespace SheetJSWin {
 | 
			
		||||
 | 
			
		||||
Now the native module will be added to the app.
 | 
			
		||||
 | 
			
		||||
4) Remove `App.js` and save the following to `App.tsx`:
 | 
			
		||||
6) Remove `App.js` and save the following to `App.tsx`:
 | 
			
		||||
 | 
			
		||||
```tsx title="App.tsx"
 | 
			
		||||
import React, { useState, type Node } from 'react';
 | 
			
		||||
@ -1234,7 +1234,7 @@ const styles = StyleSheet.create({
 | 
			
		||||
export default App;
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
5) Test the app again:
 | 
			
		||||
7) Test the app again:
 | 
			
		||||
 | 
			
		||||
```powershell
 | 
			
		||||
npx react-native run-windows --no-telemetry
 | 
			
		||||
@ -1350,6 +1350,329 @@ import { getEnforcing } from 'react-native/Libraries/TurboModule/TurboModuleRegi
 | 
			
		||||
const DocumentPicker = getEnforcing('DocumentPicker');
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* ... in some event handler ... */
 | 
			
		||||
async() => {
 | 
			
		||||
  const b64 = await DocumentPicker.PickAndRead();
 | 
			
		||||
  const wb = read(b64);
 | 
			
		||||
  // DO SOMETHING WITH `wb` HERE
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## React Native MacOS
 | 
			
		||||
 | 
			
		||||
The [NodeJS Module](../getting-started/installation/nodejs) can be imported
 | 
			
		||||
from the main app script.  File operations must be written in native code.
 | 
			
		||||
 | 
			
		||||
This demo was tested against `v0.64.30` on 2022 September 10 in MacOS 12.4
 | 
			
		||||
 | 
			
		||||
:::note
 | 
			
		||||
 | 
			
		||||
At the time of writing, the latest supported React Native version was `v0.64.3`
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
<details><summary><b>Complete Example</b> (click to show)</summary>
 | 
			
		||||
 | 
			
		||||
0) Follow the [React Native](https://reactnative.dev/docs/environment-setup)
 | 
			
		||||
   guide for React Native CLI on MacOS.
 | 
			
		||||
 | 
			
		||||
:::caution
 | 
			
		||||
 | 
			
		||||
NodeJS `v16` is required.  There are OS-specific tools for downgrading:
 | 
			
		||||
 | 
			
		||||
- [`nvm-windows`](https://github.com/coreybutler/nvm-windows/releases) Windows
 | 
			
		||||
- [`nvm`](https://github.com/nvm-sh/nvm/) Linux, MacOS, WSL, etc.
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
1) Create a new project using React Native `0.64`:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
npx react-native init SheetJSmacOS --template react-native@^0.64.0
 | 
			
		||||
cd SheetJSmacOS
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Create the MacOS part of the application:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
npx react-native-macos-init --no-telemetry
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Install Library:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
npm i --save https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
To ensure that the app works, launch the app:
 | 
			
		||||
 | 
			
		||||
```powershell
 | 
			
		||||
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`:
 | 
			
		||||
 | 
			
		||||
```objc title="macos/SheetJSmacOS-macOS/RCTDocumentPicker.h"
 | 
			
		||||
#import <React/RCTBridgeModule.h>
 | 
			
		||||
@interface RCTDocumentPicker : NSObject <RCTBridgeModule>
 | 
			
		||||
@end
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Create the file `macos/SheetJSmacOS-macOS/RCTDocumentPicker.m`:
 | 
			
		||||
 | 
			
		||||
```objc title="macos/SheetJSmacOS-macOS/RCTDocumentPicker.m"
 | 
			
		||||
#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
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
3) Edit the project file `macos/SheetJSmacOS.xcodeproj/project.pbxproj`.
 | 
			
		||||
 | 
			
		||||
There are four places where lines must be added:
 | 
			
		||||
 | 
			
		||||
A) Immediately after `/* 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 */; };
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
B) Immediately after `/* Begin PBXFileReference section */`
 | 
			
		||||
 | 
			
		||||
```plist
 | 
			
		||||
/* Begin PBXFileReference section */
 | 
			
		||||
// highlight-start
 | 
			
		||||
    4717DC6828CC495400A9BE56 /* RCTDocumentPicker.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RCTDocumentPicker.h; path = "SheetJSMacOS-macOS/RCTDocumentPicker.h"; sourceTree = "<group>"; };
 | 
			
		||||
    4717DC6928CC499A00A9BE56 /* RCTDocumentPicker.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = RCTDocumentPicker.m; path = "SheetJSMacOS-macOS/RCTDocumentPicker.m"; sourceTree = "<group>"; };
 | 
			
		||||
// highlight-end
 | 
			
		||||
    008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = main.jsbundle; sourceTree = "<group>"; };
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
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`:
 | 
			
		||||
 | 
			
		||||
```plist
 | 
			
		||||
/* Begin PBXNativeTarget section */
 | 
			
		||||
...
 | 
			
		||||
      productType = "com.apple.product-type.application";
 | 
			
		||||
    };
 | 
			
		||||
// highlight-next-line
 | 
			
		||||
    514201482437B4B30078DB4F /* SheetJSmacOS-macOS */ = {
 | 
			
		||||
      isa = PBXNativeTarget;
 | 
			
		||||
...
 | 
			
		||||
/* End PBXNativeTarget section */
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Within the block, look for `buildPhases` and find the hex string for `Sources`:
 | 
			
		||||
 | 
			
		||||
```plist
 | 
			
		||||
      buildPhases = (
 | 
			
		||||
        1A938104A937498D81B3BD3B /* [CP] Check Pods Manifest.lock */,
 | 
			
		||||
        381D8A6F24576A6C00465D17 /* Start Packager */,
 | 
			
		||||
// highlight-next-line
 | 
			
		||||
        514201452437B4B30078DB4F /* Sources */,
 | 
			
		||||
        514201462437B4B30078DB4F /* Frameworks */,
 | 
			
		||||
        514201472437B4B30078DB4F /* Resources */,
 | 
			
		||||
        381D8A6E24576A4E00465D17 /* Bundle React Native code and images */,
 | 
			
		||||
        3689826CA944E2EF44FCBC17 /* [CP] Copy Pods Resources */,
 | 
			
		||||
      );
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Search for that hex string (`514201452437B4B30078DB4F` in our example) in the
 | 
			
		||||
file and it should show up in a `PBXSourcesBuildPhase` section. Within `files`,
 | 
			
		||||
add the highlighted line:
 | 
			
		||||
 | 
			
		||||
```plist
 | 
			
		||||
    514201452437B4B30078DB4F /* Sources */ = {
 | 
			
		||||
      isa = PBXSourcesBuildPhase;
 | 
			
		||||
      buildActionMask = 2147483647;
 | 
			
		||||
      files = (
 | 
			
		||||
// highlight-next-line
 | 
			
		||||
        4717DC6A28CC499A00A9BE56 /* RCTDocumentPicker.m in Sources */,
 | 
			
		||||
        514201502437B4B30078DB4F /* ViewController.m in Sources */,
 | 
			
		||||
        514201582437B4B40078DB4F /* main.m in Sources */,
 | 
			
		||||
        5142014D2437B4B30078DB4F /* AppDelegate.m in Sources */,
 | 
			
		||||
      );
 | 
			
		||||
      runOnlyForDeploymentPostprocessing = 0;
 | 
			
		||||
    };
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
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`:
 | 
			
		||||
 | 
			
		||||
```plist
 | 
			
		||||
/* Begin PBXProject section */
 | 
			
		||||
    83CBB9F71A601CBA00E9B192 /* Project object */ = {
 | 
			
		||||
      isa = PBXProject;
 | 
			
		||||
...
 | 
			
		||||
        Base,
 | 
			
		||||
      );
 | 
			
		||||
// highlight-next-line
 | 
			
		||||
      mainGroup = 83CBB9F61A601CBA00E9B192;
 | 
			
		||||
      productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */;
 | 
			
		||||
...
 | 
			
		||||
/* End PBXProject section */
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Search for that hex string (`83CBB9F61A601CBA00E9B192` in our example) in the
 | 
			
		||||
file and it should show up in a `PBXGroup` section.  Within `children`, add the
 | 
			
		||||
highlighted lines:
 | 
			
		||||
 | 
			
		||||
```plist
 | 
			
		||||
    83CBB9F61A601CBA00E9B192 = {
 | 
			
		||||
      isa = PBXGroup;
 | 
			
		||||
      children = (
 | 
			
		||||
// highlight-start
 | 
			
		||||
        4717DC6828CC495400A9BE56 /* RCTDocumentPicker.h */,
 | 
			
		||||
        4717DC6928CC499A00A9BE56 /* RCTDocumentPicker.m */,
 | 
			
		||||
// highlight-end
 | 
			
		||||
        5142014A2437B4B30078DB4F /* SheetJSmacOS-macOS */,
 | 
			
		||||
        13B07FAE1A68108700A75B9A /* SheetJSmacOS-iOS */,
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
4) Replace `App.js` with the following:
 | 
			
		||||
 | 
			
		||||
```tsx title="App.js"
 | 
			
		||||
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:
 | 
			
		||||
 | 
			
		||||
```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.
 | 
			
		||||
 | 
			
		||||
6) Make a release build:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
xcodebuild -workspace macos/SheetJSmacOS.xcworkspace -scheme SheetJSmacOS-macOS -config Release
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
### Reading Files
 | 
			
		||||
 | 
			
		||||
Only the main UI thread can show file pickers.  This is similar to Web Worker
 | 
			
		||||
DOM access limitations in the Web platform.
 | 
			
		||||
 | 
			
		||||
This example defines a `PickAndRead` function that will show the file picker,
 | 
			
		||||
read the file contents, and return a Base64 string.
 | 
			
		||||
 | 
			
		||||
```objc
 | 
			
		||||
/* the resolve/reject is projected on the JS side as a Promise */
 | 
			
		||||
RCT_EXPORT_METHOD(PickAndRead:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
 | 
			
		||||
{
 | 
			
		||||
  /* perform file picker action in the UI thread */
 | 
			
		||||
  // highlight-next-line
 | 
			
		||||
  RCTExecuteOnMainQueue(^{
 | 
			
		||||
    /* create file picker */
 | 
			
		||||
    NSOpenPanel *panel = [NSOpenPanel openPanel];
 | 
			
		||||
    [panel setCanChooseDirectories:NO];
 | 
			
		||||
    [panel setAllowsMultipleSelection:NO];
 | 
			
		||||
    [panel setMessage:@"Select a spreadsheet to read"];
 | 
			
		||||
 | 
			
		||||
    /* show file picker */
 | 
			
		||||
    // highlight-next-line
 | 
			
		||||
    [panel beginWithCompletionHandler:^(NSInteger result){
 | 
			
		||||
      if (result == NSModalResponseOK) {
 | 
			
		||||
        /* read data and return base64 string */
 | 
			
		||||
        NSURL *selected = [[panel URLs] objectAtIndex:0];
 | 
			
		||||
        NSFileHandle *hFile = [NSFileHandle fileHandleForReadingFromURL:selected error:nil];
 | 
			
		||||
        if(hFile) {
 | 
			
		||||
          NSData *data = [hFile readDataToEndOfFile];
 | 
			
		||||
          // highlight-next-line
 | 
			
		||||
          resolve([data base64EncodedStringWithOptions:0]);
 | 
			
		||||
        } else reject(@"read_failure", @"Could not read selected file!", nil);
 | 
			
		||||
      } else reject(@"select_failure", @"No file selected!", nil);
 | 
			
		||||
    }];
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
This module is referenced in the same way as the React Native Windows example:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
import { read } from 'xlsx';
 | 
			
		||||
import { getEnforcing } from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
 | 
			
		||||
const DocumentPicker = getEnforcing('DocumentPicker');
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* ... in some event handler ... */
 | 
			
		||||
async() => {
 | 
			
		||||
  const b64 = await DocumentPicker.PickAndRead();
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user