diff --git a/docz/docs/03-demos/06-desktop/06-reactnative.md b/docz/docs/03-demos/06-desktop/06-reactnative.md index b1159c5..d7ca5ba 100644 --- a/docz/docs/03-demos/06-desktop/06-reactnative.md +++ b/docz/docs/03-demos/06-desktop/06-reactnative.md @@ -41,6 +41,22 @@ The "Complete Example" creates an app that looks like the screenshots below: +
Tested Environments (click to show) + +:::note + +This demo was tested in the following environments: + +| OS and Version | Arch | RN Platform | Date | +|:---------------|:-----|:------------|:-----------| +| 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 | + +::: + +
+ ## Native Modules :::caution @@ -195,8 +211,6 @@ RCT_EXPORT_METHOD(PickAndRead:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromi ## Windows Demo -This demo was tested against `v0.70.10` on 2023 January 04 in Windows 10. - :::warning There is no simple standalone executable file at the end of the process. @@ -222,11 +236,11 @@ used to switch the NodeJS version. ::: -1) Create a new project using React Native `0.70`: +1) Create a new project using React Native `0.71`: -```powershell -npx react-native init SheetJSWin --template react-native@^0.70.0 -cd .\SheetJSWin\ +```bash +npx react-native init SheetJSWin --template react-native@^0.71.0 +cd SheetJSWin ``` Create the Windows part of the application: @@ -234,14 +248,14 @@ Create the Windows part of the application: -```powershell +```bash npx react-native-windows-init --no-telemetry --overwrite --language=cs ``` -```powershell +```bash npx react-native-windows-init --no-telemetry --overwrite ``` @@ -256,49 +270,45 @@ npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`} To ensure that the app works, launch the app: -```powershell +```bash npx react-native run-windows --no-telemetry ``` +:::caution + +When the demo was tested in Windows 11, the run step failed with the message: + +> The Windows SDK version `10.0.19041.0` was not found + +Specific Windows SDK versions can be installed through Visual Studio Installer. + +::: + -2) Create the file `windows\SheetJSWin\DocumentPicker.cs` with the following: +2) Download [`DocumentPicker.cs`](pathname:///reactnative/DocumentPicker.cs) and +save to `windows\SheetJSWin\DocumentPicker.cs`. -```csharp title="windows\SheetJSWin\DocumentPicker.cs" -using System; -using System.Threading.Tasks; -using Windows.Security.Cryptography; -using Windows.Storage; -using Windows.Storage.Pickers; -using Microsoft.ReactNative.Managed; + + -namespace SheetJSWin { - [ReactModule] - class DocumentPicker { - private ReactContext context; - [ReactInitializer] - public void Initialize(ReactContext reactContext) { context = reactContext; } - - [ReactMethod("PickAndRead")] - public async void PickAndRead(IReactPromise result) { - context.Handle.UIDispatcher.Post(async() => { try { - var picker = new FileOpenPicker(); - picker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary; - picker.FileTypeFilter.Add(".xlsx"); - picker.FileTypeFilter.Add(".xls"); - - var file = await picker.PickSingleFileAsync(); - if(file == null) throw new Exception("File not found"); - - var buf = await FileIO.ReadBufferAsync(file); - result.Resolve(CryptographicBuffer.EncodeToBase64String(buf)); - } catch(Exception e) { result.Reject(new ReactError { Message = e.Message }); }}); - } - } -} +```bash +iwr -Uri https://docs.sheetjs.com/reactnative/DocumentPicker.cs -OutFile windows/SheetJSWin/DocumentPicker.cs ``` + + + +```bash +curl -Lo windows/SheetJSWin/DocumentPicker.cs https://docs.sheetjs.com/reactnative/DocumentPicker.cs +``` + + + + + + 3) Add the highlighted line to `windows\SheetJSWin\SheetJSWin.csproj`. Look for the `ItemGroup` that contains `ReactPackageProvider.cs`: @@ -312,53 +322,26 @@ the `ItemGroup` that contains `ReactPackageProvider.cs`: -2) Create the file `windows\SheetJSWin\DocumentPicker.h` with the following: +2) Download [`DocumentPicker.h`](pathname:///reactnative/DocumentPicker.h) and +save to `windows\SheetJSWin\DocumentPicker.h`. -```cpp title="windows\SheetJSWin\DocumentPicker.h" -#pragma once + + -#include -#include -#include "NativeModules.h" - -using namespace winrt::Microsoft::ReactNative; -using namespace winrt::Windows::Storage; -using namespace winrt::Windows::Storage::Pickers; -using namespace winrt::Windows::Security::Cryptography; - -namespace SheetJSWin { - REACT_MODULE(DocumentPicker); - struct DocumentPicker { - REACT_INIT(Initialize); - void Initialize(const ReactContext& reactContext) noexcept { - context = reactContext; - } - - REACT_METHOD(PickAndRead); - void PickAndRead(ReactPromise promise) noexcept { - auto prom = promise; - context.UIDispatcher().Post([prom = std::move(prom)]()->winrt::fire_and_forget { - auto p = prom; - FileOpenPicker picker; - picker.SuggestedStartLocation(PickerLocationId::DocumentsLibrary); - picker.FileTypeFilter().Append(L".xlsx"); - picker.FileTypeFilter().Append(L".xls"); - - StorageFile file = co_await picker.PickSingleFileAsync(); - if(file == nullptr) { p.Reject("File not Found"); co_return; } - - auto buf = co_await FileIO::ReadBufferAsync(file); - p.Resolve(CryptographicBuffer::EncodeToBase64String(buf)); - co_return; - }); - } - - private: - ReactContext context{nullptr}; - }; -} +```bash +iwr -Uri https://docs.sheetjs.com/reactnative/DocumentPicker.h -OutFile windows/SheetJSWin/DocumentPicker.h ``` + + + +```bash +curl -Lo windows/SheetJSWin/DocumentPicker.h https://docs.sheetjs.com/reactnative/DocumentPicker.h +``` + + + + 3) Add the highlighted line to `windows\SheetJSWin\ReactPackageProvider.cpp`: ```cpp title="windows\SheetJSWin\ReactPackageProvider.cpp" @@ -373,55 +356,30 @@ namespace SheetJSWin { Now the native module will be added to the app. -4) Remove `App.js` and save the following to `App.tsx`: +4) Remove `App.js` (if it exists) and save the following to `App.tsx`: -```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 Windows {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; +```bash +iwr -Uri https://docs.sheetjs.com/reactnative/desktop/App.tsx -OutFile App.tsx ``` + + + +```bash +curl -LO https://docs.sheetjs.com/reactnative/desktop/App.tsx +``` + + + + + + 5) Test the app again: -```powershell +```bash npx react-native run-windows --no-telemetry ``` @@ -430,8 +388,6 @@ file picker to select the `pres.xlsx` file and the app will show the data. ## macOS Demo -This demo was tested against `v0.64.30` on 2023 January 04 in MacOS 12.4 - 0) Follow the [React Native](https://reactnative.dev/docs/environment-setup) guide for React Native CLI on MacOS. @@ -463,7 +419,7 @@ npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`} To ensure that the app works, launch the app: -```powershell +```bash npx react-native run-macos ``` diff --git a/docz/docs/03-demos/10-extensions/03-excelapi.md b/docz/docs/03-demos/10-extensions/03-excelapi.md index fc1f053..2c22348 100644 --- a/docz/docs/03-demos/10-extensions/03-excelapi.md +++ b/docz/docs/03-demos/10-extensions/03-excelapi.md @@ -93,7 +93,7 @@ async function extern(url) { 2) Install dependencies in a new PowerShell window: -```powershell +```bash npm i -g yo bower generator-office ``` @@ -109,7 +109,7 @@ npm i -g yo bower generator-office 4) Start the dev process: -```powershell +```bash cd SheetJSImport npm run build npm start diff --git a/docz/docs/09-miscellany/05-contributing.md b/docz/docs/09-miscellany/05-contributing.md index e380ae7..c104ee7 100644 --- a/docz/docs/09-miscellany/05-contributing.md +++ b/docz/docs/09-miscellany/05-contributing.md @@ -98,7 +98,7 @@ chmod +x compile-git-with-openssl.sh E) Set `git` config `core.autocrlf` setting to `false`. The following commands should be run twice, once within PowerShell and once within WSL bash: -```powershell +```bash git config --global --add core.autocrlf false git config --global --unset core.autocrlf true ``` diff --git a/docz/docusaurus.config.js b/docz/docusaurus.config.js index 09976b1..951decc 100644 --- a/docz/docusaurus.config.js +++ b/docz/docusaurus.config.js @@ -192,25 +192,31 @@ const config = { { from: '/docs/demos/extendscript', to: '/docs/demos/extensions/extendscript/' }, { from: '/docs/demos/excelapi', to: '/docs/demos/extensions/excelapi/' }, { from: '/docs/demos/chromium', to: '/docs/demos/extensions/chromium/' }, - /* cloudata */ + { from: '/docs/getting-started/demos/chromium', to: '/docs/demos/extensions/chromium/' }, + /* cloud */ { from: '/docs/demos/cloudata', to: '/docs/demos/cloud/' }, { from: '/docs/demos/cloudata/gsheet', to: '/docs/demos/cloud/gsheet/' }, { from: '/docs/demos/cloudata/airtable', to: '/docs/demos/cloud/airtable/' }, + { from: '/docs/getting-started/demos/netsuite', to: '/docs/demos/cloud/netsuite/' }, /* hosting */ { from: '/docs/demos/hosting/dropbox', to: '/docs/demos/cloud/dropbox/' }, { from: '/docs/demos/hosting/github', to: '/docs/demos/cloud/github/' }, /* data */ - { from: '/docs/demos/nosql', to: '/docs/demos/data/' }, { from: '/docs/demos/database', to: '/docs/demos/data/' }, + { from: '/docs/demos/nosql', to: '/docs/demos/data/' }, + { from: '/docs/getting-started/demos/nosql', to: '/docs/demos/data/' }, /* net */ { from: '/docs/demos/headless', to: '/docs/demos/net/headless/' }, { from: '/docs/demos/server', to: '/docs/demos/net/server/' }, { from: '/docs/demos/network', to: '/docs/demos/net/network/' }, + { from: '/docs/getting-started/demos/network', to: '/docs/demos/net/network/' }, /* local */ { from: '/docs/demos/clipboard', to: '/docs/demos/local/clipboard/' }, { from: '/docs/demos/localfile', to: '/docs/demos/local/file/' }, /* desktop */ { from: '/docs/demos/cli', to: '/docs/demos/desktop/cli/' }, + { from: '/docs/getting-started/demos/cli', to: '/docs/demos/desktop/cli/' }, + { from: '/docs/getting-started/demos/desktop', to: '/docs/demos/desktop/' }, /* bigdata */ { from: '/docs/demos/ml', to: '/docs/demos/bigdata/ml/' }, { from: '/docs/demos/worker', to: '/docs/demos/bigdata/worker/' }, diff --git a/docz/static/reactnative/DocumentPicker.cs b/docz/static/reactnative/DocumentPicker.cs new file mode 100644 index 0000000..3b48ce2 --- /dev/null +++ b/docz/static/reactnative/DocumentPicker.cs @@ -0,0 +1,31 @@ +using System; +using System.Threading.Tasks; +using Windows.Security.Cryptography; +using Windows.Storage; +using Windows.Storage.Pickers; +using Microsoft.ReactNative.Managed; + +namespace SheetJSWin { + [ReactModule] + class DocumentPicker { + private ReactContext context; + [ReactInitializer] + public void Initialize(ReactContext reactContext) { context = reactContext; } + + [ReactMethod("PickAndRead")] + public async void PickAndRead(IReactPromise result) { + context.Handle.UIDispatcher.Post(async() => { try { + var picker = new FileOpenPicker(); + picker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary; + picker.FileTypeFilter.Add(".xlsx"); + picker.FileTypeFilter.Add(".xls"); + + var file = await picker.PickSingleFileAsync(); + if(file == null) throw new Exception("File not found"); + + var buf = await FileIO.ReadBufferAsync(file); + result.Resolve(CryptographicBuffer.EncodeToBase64String(buf)); + } catch(Exception e) { result.Reject(new ReactError { Message = e.Message }); }}); + } + } +} \ No newline at end of file diff --git a/docz/static/reactnative/DocumentPicker.h b/docz/static/reactnative/DocumentPicker.h new file mode 100644 index 0000000..031a798 --- /dev/null +++ b/docz/static/reactnative/DocumentPicker.h @@ -0,0 +1,42 @@ +#pragma once + +#include +#include +#include "NativeModules.h" + +using namespace winrt::Microsoft::ReactNative; +using namespace winrt::Windows::Storage; +using namespace winrt::Windows::Storage::Pickers; +using namespace winrt::Windows::Security::Cryptography; + +namespace SheetJSWin { + REACT_MODULE(DocumentPicker); + struct DocumentPicker { + REACT_INIT(Initialize); + void Initialize(const ReactContext& reactContext) noexcept { + context = reactContext; + } + + REACT_METHOD(PickAndRead); + void PickAndRead(ReactPromise promise) noexcept { + auto prom = promise; + context.UIDispatcher().Post([prom = std::move(prom)]()->winrt::fire_and_forget { + auto p = prom; + FileOpenPicker picker; + picker.SuggestedStartLocation(PickerLocationId::DocumentsLibrary); + picker.FileTypeFilter().Append(L".xlsx"); + picker.FileTypeFilter().Append(L".xls"); + + StorageFile file = co_await picker.PickSingleFileAsync(); + if(file == nullptr) { p.Reject("File not Found"); co_return; } + + auto buf = co_await FileIO::ReadBufferAsync(file); + p.Resolve(CryptographicBuffer::EncodeToBase64String(buf)); + co_return; + }); + } + + private: + ReactContext context{nullptr}; + }; +} \ No newline at end of file diff --git a/docz/static/reactnative/desktop/App.tsx b/docz/static/reactnative/desktop/App.tsx new file mode 100644 index 0000000..fb4537d --- /dev/null +++ b/docz/static/reactnative/desktop/App.tsx @@ -0,0 +1,41 @@ +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 Windows {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; \ No newline at end of file diff --git a/docz/static/reactnative/rnw.png b/docz/static/reactnative/rnw.png index b6e40a4..7185662 100644 Binary files a/docz/static/reactnative/rnw.png and b/docz/static/reactnative/rnw.png differ