docs.sheetjs.com/docz/docs/03-demos/17-mobile/07-lynx.md
2025-03-11 23:37:40 -04:00

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
summary
Lynx + Native Rendering

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:

The "Fetching Remote Data" example creates an app that looks like the screenshots below:

iOS Android

iOS screenshot

Android screenshot

:::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.

SpreadsheetArray of Arrays

pres.xlsx data

[
  ["Name", "Index"],
  ["Bill Clinton", 42],
  ["GeorgeW Bush", 43],
  ["Barack Obama", 44],
  ["Donald Trump", 45],
  ["Joseph Biden", 46]
]

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_json3 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!

:::

  1. Install Lynx dependencies

  2. Create project:

pnpm create rspeedy@0.8.3 -d SheetJSLynxFetch -t react-ts --tools biome
  1. 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}

  1. Download App.tsx and replace:
curl -o ./src/App.tsx https://docs.sheetjs.com/lynx/App.tsx
  1. 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
  1. 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

:::

  1. While the Android emulator is open, download LynxExplorer4 - (Is a sandbox for trying out Lynx quickly)
1. Download the pre-build app from the [GitHub Release](https://github.com/lynx-family/lynx/releases/tag/3.2.0-rc.0) and select the APK `LynxExplorer-noasan-release.apk`. 2. Drag and drop the APK `LynxExplorer-noasan-release.apk` in to your Android simulator.
  1. From step 5, you will see a QR code appear in the terminal with a hyperlink like this. Copy the HTTP link.

lynx live server link

  1. In the simulator, open the LynxExplorer app. In the input field labeled Enter Card URL, paste the link and click Go.

  2. 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

before screenshot

after screenshot

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.
  1. From step 5, you will see a QR code appear in the terminal with a hyperlink like this. Copy the HTTP link.

lynx live server link

  1. In the simulator, open the LynxExplorer app. In the input field labeled Enter Card URL, paste the link and click Go.

  2. 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

before screenshot

after screenshot