docs.sheetjs.com/docz/docs/03-demos/17-mobile/07-lynx.md
2025-03-30 02:31: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
React + 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 relatively new and does not currently have a deep community.

Any issues should be reported to the Lynx project for further diagnosis.

:::

This demo uses React (using ReactLynx) and SheetJS to process and generate spreadsheets. We'll explore how to load SheetJS in Lynx apps in the following scenarios:

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.

:::

:::danger pass

Lynx development requires an Apple Silicon-powered Macintosh!

X64 is currently unsupported.

:::

Integration Details

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

Lynx does not ship with a component for displaying tabular data.

The demo uses Lynx <view/> and <text/> elements to display tabular data:

{/* 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);

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.6 3.2.0-rc.1 darwin-arm 2025-03-26
iOS 18.3 iPhone 16 Pro 0.8.6 3.2.0-rc.1 darwin-arm 2025-03-26

:::

:::danger Real Devices

When this demo was last tested, there was no simple standalone guide for running Lynx apps on real devices.

:::

:::caution pass

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:

npm create rspeedy@0.8.6 -- -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 npm i npm i -S https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz}

  1. Download App.tsx into the src folder:
curl -o ./src/App.tsx https://docs.sheetjs.com/lynx/App.tsx
  1. Download App.css into the src folder:
curl -o ./src/App.css https://docs.sheetjs.com/lynx/App.css

  1. Start the development server:
npm run dev

Keep the window open.

Android

  1. Start the Android emulator:

In Android Studio, click "More actions" > "Virtual Device Manager". Look for the emulated device in the list and click the ▶ button to play.

List the available emulators with emulator -list-avds:

shjs@sheetjs SheetJSLynxFetch % emulator -list-avds
Medium_Phone_API_35
^^^^^^^^^^^^^^^^^^^--- emulator name

The 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. Download the LynxExplorer4 APK.

The latest test used LynxExplorer-noasan-release.apk for version 3.2.0-rc.1.

  1. Drag and drop the APK into the Android emulator window.

The emulator will install LynxExplorer.

  1. In the terminal window from step 5, copy the HTTP link. It will be printed below the QR code, as shown in the following screenshot:

lynx live server link

  1. In the emulator, open the "LynxExplorer" app.

  2. In the Enter Card URL input field, paste the link. Tap Go.

The view will refresh. The app should look like the "Before" screenshot:

Before After

before screenshot

after screenshot

  1. Tap "Import data from a spreadsheet" and verify that the app shows new data. The app should look like the "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. Download the LynxExplorer4 app tarball.

The latest test used LynxExplorer-arm64.app.tar.gz for version 3.2.0-rc.1.

  1. Open LynxExplorer-arm64.app.tar.gz using Finder.

The tarball contains an app named LynxExplorer-arm64 .

  1. Launch the iOS Simulator.

  2. Click and drag LynxExplorer-arm64 into the Simulator window.

The simulator will install the "LynxExplorer" app.

  1. Copy the HTTP link from the terminal window in step 5.

lynx live server link

  1. Tap the "LynxExplorer" icon in the simulator to launch the app.

  2. Tap the Enter Card URL input field and paste the link. Tap Go.

The view will refresh. The app should look like the "Before" screenshot:

Before After

before screenshot

after screenshot

  1. Tap "Import data from a spreadsheet" and verify that the app shows new data. The app should look like the "After" screenshot.

  1. Follow "Quick Start" in the Lynx documentation and select the appropriate "Lynx Explorer sandbox" ↩︎

  2. See "Array of Arrays" in the API reference ↩︎

  3. See "Array Output" in "Utility Functions" ↩︎

  4. See "LynxExplorer sandbox" ↩︎