11 KiB
title | sidebar_label | description | pagination_prev | pagination_next | sidebar_position | sidebar_custom_props | ||
---|---|---|---|---|---|---|---|---|
Sheets at Native Speed with Lynx | Lynx | Build data-intensive mobile apps with Lynx. Seamlessly integrate spreadsheets into your app using SheetJS. Securely process and generate Excel files in the field. | demos/static/index | demos/desktop/index | 7 |
|
import current from '/version.js'; import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; import CodeBlock from '@theme/CodeBlock';
export const r = {style: {color:"red"}}; export const g = {style: {color:"green"}}; export const y = {style: {color:"gold"}}; export const gr = {style: {color:"gray"}};
Lynx is a modern cross-platform framework. It builds iOS, Android and Web apps that use JavaScript for describing layouts and events.
SheetJS is a JavaScript library for reading and writing data from spreadsheets.
:::caution Lynx support is considered experimental.
Lynx is a great, fast, open-source alternative to React Native. Any issues should be reported to the Lynx project for further diagnosis.
:::
This demo uses ReactLynx and SheetJS to process and generate spreadsheets. We'll explore how to load SheetJS in ReactLynx app in a few ways:
- "Fetching Remote Data" uses the built-in
fetch
to download and parse remote workbook files.
The "Fetching Remote Data" example creates an app that looks like the screenshots below:
iOS | Android |
---|---|
:::caution pass Before testing this demo, follow the official React Lynx Guide!1
Follow the instructions for iOS (requires macOS) and for Android. They will cover installation and system configuration. You should be able to build and run a sample app in the Android and the iOS (if applicable) simulators.
:::
Integration Detail
The SheetJS NodeJS Module can be imported from any component or script in the app.
Internal State
For simplicity, this demo uses an "Array of Arrays"2 as the internal state.
Spreadsheet | Array of Arrays |
---|---|
|
Each array represents a row in the table.
This demo also keeps track of the column widths as a single array of numbers. The widths are used by the display component.
const [data, setData] = useState<any[]>([
"SheetJS".split(""),
[5, 4, 3, 3, 7, 9, 5],
[8, 6, 7, 5, 3, 0, 9]
]);
const [widths, setWidths] = useState<number[]>(Array.from({ length: 7 }, () => 20));
Updating State
Starting from a SheetJS worksheet object, sheet_to_json
3 with the header
option can generate an array of arrays:
/* 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 */
setData(data);
/* update column widths */
setWidths(make_width(data));
}
Calculating Column Widths
Column widths can be calculated by walking each column and calculating the max data width. Using the array of arrays:
/* this function takes an array of arrays and generates widths */
function make_width(aoa) {
/* walk each row */
aoa.forEach((r) => {
/* walk each column */
r.forEach((c, C) => {
/* update column width based on the length of the cell contents */
res[C] = Math.max(res[C]||60, String(c).length * 10);
});
});
/* use a default value for columns with no data */
for(let C = 0; C < res.length; ++C) if(!res[C]) res[C] = 60;
return res;
}
Displaying Data
The demo uses Lynx builtin element <view/>
and <text/>
to display the first worksheet.
The demo uses components similar to the example below:
{/* Table container */}
<view className='Table'>
{/* Map through each row in the data array */}
{data.map((row, rowIndex) => (
<view key={`row-${rowIndex}`} className="Row">
{/* Map through each cell in the current row */}
{Array.isArray(row) && row.map((cell, cellIndex) => (
{/* Cell with dynamic width based on content */}
<view
key={`cell-${rowIndex}-${cellIndex}`} className="Cell"
style={{ width: `${widths[cellIndex]}px` }}>
{/* Display cell content as text */}
<text>{String(cell)}</text>
</view>
))}
</view>
))}
</view>
Fetching Remote Data
This snippet downloads and parses https://docs.sheetjs.com/pres.xlsx:
/* fetch data into an ArrayBuffer */
const ab = await (await fetch("https://docs.sheetjs.com/pres.xlsx")).arrayBuffer();
/* parse data */
const wb = XLSX.read(ab);
The data.map()
approach allows direct rendering of the worksheet data in a tabular format, with each cell
width dynamically calculated based on content.
Fetch Demo
:::note Tested Deployments
This demo was tested in the following environments:
Simulators
OS | Device | Lynx | LynxExplorer | Dev Platform | Date |
---|---|---|---|---|---|
Android 35 | Pixel 3a | 0.8.3 |
3.2.0-rc.0 |
darwin-arm |
2025-03-11 |
iOS 18.3 | iPhone 16 Pro | 0.8.3 |
3.2.0-rc.0 |
darwin-arm |
2025-03-11 |
:::
:::danger Real Devices
As of 2025-03-11
, there is no simple, standalone guide on how to build your Lynx app for real devices.
:::
:::caution
First install Lynx by following the Guide1. Make sure you can run a basic test app on your simulator before continuing!
:::
-
Install Lynx dependencies
-
Create project:
pnpm create rspeedy@0.8.3 -d SheetJSLynxFetch -t react-ts --tools biome
- Install shared dependencies:
{\ cd SheetJSLynxFetch curl -o ./src/assets/SheetJS-logo.png https://docs.sheetjs.com/logo.png pnpm install pnpm i -S https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz
}
- Download
App.tsx
and replace:
curl -o ./src/App.tsx https://docs.sheetjs.com/lynx/App.tsx
- Download
App.css
and replace:
curl -o ./src/App.css https://docs.sheetjs.com/lynx/App.css
5) Start the development server, run:
pnpm run dev
- Start the Android emulator:
Details (click to hide)
Android Studio
In Android Studio, click "More actions" > "Virtual Device Manager". Look for the emulated device in the list and click the ▶ button to play.
Command Line
List the available emulators with emulator -list-avds
shjs@sheetjs SheetJSLynxFetch % emulator -list-avds
Medium_Phone_API_35
^^^^^^^^^^^^^^^^^^^--- emulator name
Emulator name should be passed to emulator -avd
. In a previous test, the name was
Medium_Phone_API_35
and the launch command was:
emulator -avd Medium_Phone_API_35
:::note pass
On macOS, ~/Library/Android/sdk/emulator/
is the typical location
for the emulator
binary. If it cannot be found, add the folder to PATH
:
export PATH="$PATH":~/Library/Android/sdk/emulator
emulator -avd Medium_Phone_API_35
:::
- While the Android emulator is open, download LynxExplorer4 - (Is a sandbox for trying out Lynx quickly)
- From step 5, you will see a QR code appear in the terminal with a hyperlink like this. Copy the HTTP link.
-
In the simulator, open the LynxExplorer app. In the input field labeled Enter Card URL, paste the link and click Go.
-
When opened, the app should look like the "Before" screenshot below. After tapping "Import data from a spreadsheet", verify that the app shows new data:
Before | After |
---|---|
iOS Testing
:::danger pass
iOS testing can only be performed on Apple hardware running macOS!
Xcode and iOS simulators are not available on Windows or Linux.
:::
1. Install Xcode open up the Mac App Store, search for [Xcode](https://apps.apple.com/us/app/xcode/id497799835), and click Install (or Update if you have it already). 2. Download [`LynxExplorer-arm64.app.tar.gz`](https://github.com/lynx-family/lynx/releases/latest/download/LynxExplorer-arm64.app.tar.gz). 3. Then, extract the downloaded archive:```bash
mkdir -p LynxExplorer-arm64.app/
tar -zxf LynxExplorer-arm64.app.tar.gz -C LynxExplorer-arm64.app/
```
4. Install LynxExplorer[^4] on simulator open Xcode, and choose Open Developer Tool from the Xcode menu. Click the
Simulator to launch one. Drag "LynxExplorer-arm64.app" into it.
- From step 5, you will see a QR code appear in the terminal with a hyperlink like this. Copy the HTTP link.
-
In the simulator, open the LynxExplorer app. In the input field labeled Enter Card URL, paste the link and click Go.
-
When opened, the app should look like the "Before" screenshot below. After tapping "Import data from a spreadsheet", verify that the app shows new data:
Before | After |
---|---|
-
Follow the "Quick Start guide and select the appropriate "Lynx Explorer sandbox" ↩︎