win10-x64 refresh
							
								
								
									
										576
									
								
								docz/docs/03-demos/02-frontend/01-kaioken.md
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						@ -0,0 +1,576 @@
 | 
			
		||||
---
 | 
			
		||||
title: Super Saiyan Sheets with Kaioken
 | 
			
		||||
sidebar_label: Kaioken
 | 
			
		||||
description: Build interactive websites with Kaioken. Seamlessly integrate spreadsheets into your app using SheetJS. Bring Excel-powered workflows and data to the modern web.
 | 
			
		||||
pagination_prev: demos/index
 | 
			
		||||
pagination_next: demos/grid/index
 | 
			
		||||
sidebar_position: 1
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
import current from '/version.js';
 | 
			
		||||
import Tabs from '@theme/Tabs';
 | 
			
		||||
import TabItem from '@theme/TabItem';
 | 
			
		||||
import CodeBlock from '@theme/CodeBlock';
 | 
			
		||||
 | 
			
		||||
[Kaioken](https://kaioken.dev/) is a JavaScript library for building user
 | 
			
		||||
interfaces.
 | 
			
		||||
 | 
			
		||||
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
 | 
			
		||||
data from spreadsheets.
 | 
			
		||||
 | 
			
		||||
This demo uses Kaioken and SheetJS to process and generate spreadsheets. We'll
 | 
			
		||||
explore how to load SheetJS in "Kaioponents" (Kaioken components) and compare
 | 
			
		||||
common state models and data flow strategies.
 | 
			
		||||
 | 
			
		||||
:::note pass
 | 
			
		||||
 | 
			
		||||
This demo focuses on Kaioken concepts. Other demos cover general deployments:
 | 
			
		||||
 | 
			
		||||
- [Desktop application powered by Tauri](/docs/demos/desktop/tauri)
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
## Installation
 | 
			
		||||
 | 
			
		||||
[The "Frameworks" section](/docs/getting-started/installation/frameworks) covers
 | 
			
		||||
installation with Yarn and other package managers.
 | 
			
		||||
 | 
			
		||||
The library can be imported directly from JS or JSX code with:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
import { read, utils, writeFile } from 'xlsx';
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Internal State
 | 
			
		||||
 | 
			
		||||
The various SheetJS APIs work with various data shapes.  The preferred state
 | 
			
		||||
depends on the application.
 | 
			
		||||
 | 
			
		||||
### Array of Objects
 | 
			
		||||
 | 
			
		||||
Typically, some users will create a spreadsheet with source data that should be
 | 
			
		||||
loaded into the site.  This sheet will have known columns.
 | 
			
		||||
 | 
			
		||||
#### State
 | 
			
		||||
 | 
			
		||||
The example [presidents sheet](https://sheetjs.com/pres.xlsx) has one header row
 | 
			
		||||
with "Name" and "Index" columns. The natural JS representation is an object for
 | 
			
		||||
each row, using the values in the first rows as keys:
 | 
			
		||||
 | 
			
		||||
<table><thead><tr><th>Spreadsheet</th><th>State</th></tr></thead><tbody><tr><td>
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
</td><td>
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
[
 | 
			
		||||
  { Name: "Bill Clinton", Index: 42 },
 | 
			
		||||
  { Name: "GeorgeW Bush", Index: 43 },
 | 
			
		||||
  { Name: "Barack Obama", Index: 44 },
 | 
			
		||||
  { Name: "Donald Trump", Index: 45 },
 | 
			
		||||
  { Name: "Joseph Biden", Index: 46 }
 | 
			
		||||
]
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
</td></tr></tbody></table>
 | 
			
		||||
 | 
			
		||||
The Kaioken `useState`[^1] hook can configure the state:
 | 
			
		||||
 | 
			
		||||
<Tabs groupId="lang">
 | 
			
		||||
  <TabItem name="JS" value="JavaScript">
 | 
			
		||||
 | 
			
		||||
```ts
 | 
			
		||||
import { useState } from 'kaioken';
 | 
			
		||||
 | 
			
		||||
/* the kaioponent state is an array of objects */
 | 
			
		||||
const [pres, setPres] = useState([]);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
  </TabItem>
 | 
			
		||||
  <TabItem name="TS" value="TypeScript" default>
 | 
			
		||||
 | 
			
		||||
```ts
 | 
			
		||||
import { useState } from 'kaioken';
 | 
			
		||||
 | 
			
		||||
/* the kaioponent state is an array of objects */
 | 
			
		||||
const [pres, setPres] = useState<any[]>([]);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
When the spreadsheet header row is known ahead of time, row typing is possible:
 | 
			
		||||
 | 
			
		||||
```ts
 | 
			
		||||
import { useState } from 'kaioken';
 | 
			
		||||
 | 
			
		||||
interface President {
 | 
			
		||||
  Name: string;
 | 
			
		||||
  Index: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* the kaioponent state is an array of presidents */
 | 
			
		||||
const [pres, setPres] = useState<President[]>([]);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
:::caution pass
 | 
			
		||||
 | 
			
		||||
The types are informative. They do not enforce that worksheets include the named
 | 
			
		||||
columns. A runtime data validation library should be used to verify the dataset.
 | 
			
		||||
 | 
			
		||||
When the file header is not known in advance, `any` should be used.
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
  </TabItem>
 | 
			
		||||
</Tabs>
 | 
			
		||||
 | 
			
		||||
#### Updating State
 | 
			
		||||
 | 
			
		||||
The SheetJS [`read`](/docs/api/parse-options) and [`sheet_to_json`](/docs/api/utilities/array#array-output)
 | 
			
		||||
functions simplify state updates. They are best used in the function bodies of
 | 
			
		||||
`useEffect`[^2] and `useCallback`[^3] hooks.
 | 
			
		||||
 | 
			
		||||
A `useEffect` hook can download and update state when a person loads the site:
 | 
			
		||||
 | 
			
		||||
```mermaid
 | 
			
		||||
flowchart LR
 | 
			
		||||
  url[(Remote\nFile)]
 | 
			
		||||
  ab[(Data\nArrayBuffer)]
 | 
			
		||||
  wb(SheetJS\nWorkbook)
 | 
			
		||||
  ws(SheetJS\nWorksheet)
 | 
			
		||||
  aoo(array of\nobjects)
 | 
			
		||||
  state((Kaioponent\nstate))
 | 
			
		||||
  url --> |fetch\n\n| ab
 | 
			
		||||
  ab --> |read\n\n| wb
 | 
			
		||||
  wb --> |wb.Sheets\nselect sheet| ws
 | 
			
		||||
  ws --> |sheet_to_json\n\n| aoo
 | 
			
		||||
  aoo --> |setPres\nfrom `setState`| state
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
<Tabs groupId="lang">
 | 
			
		||||
  <TabItem name="JS" value="JavaScript">
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
import { useEffect } from 'kaioken';
 | 
			
		||||
import { read, utils } from 'xlsx';
 | 
			
		||||
 | 
			
		||||
/* Fetch and update the state once */
 | 
			
		||||
useEffect(() => { (async() => {
 | 
			
		||||
  /* Download from https://sheetjs.com/pres.numbers */
 | 
			
		||||
  const f = await fetch("https://sheetjs.com/pres.numbers");
 | 
			
		||||
  const ab = await f.arrayBuffer();
 | 
			
		||||
 | 
			
		||||
  // highlight-start
 | 
			
		||||
  /* parse */
 | 
			
		||||
  const wb = read(ab);
 | 
			
		||||
 | 
			
		||||
  /* generate array of objects from first worksheet */
 | 
			
		||||
  const ws = wb.Sheets[wb.SheetNames[0]]; // get the first worksheet
 | 
			
		||||
  const data = utils.sheet_to_json(ws); // generate objects
 | 
			
		||||
 | 
			
		||||
  /* update state */
 | 
			
		||||
  setPres(data); // update state
 | 
			
		||||
  // highlight-end
 | 
			
		||||
})(); }, []);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
  </TabItem>
 | 
			
		||||
  <TabItem name="TS" value="TypeScript" default>
 | 
			
		||||
 | 
			
		||||
```ts
 | 
			
		||||
import { useEffect } from 'kaioken';
 | 
			
		||||
import { read, utils } from 'xlsx';
 | 
			
		||||
 | 
			
		||||
/* Fetch and update the state once */
 | 
			
		||||
useEffect(() => { (async() => {
 | 
			
		||||
  /* Download from https://sheetjs.com/pres.numbers */
 | 
			
		||||
  const f = await fetch("https://sheetjs.com/pres.numbers");
 | 
			
		||||
  const ab = await f.arrayBuffer();
 | 
			
		||||
 | 
			
		||||
  // highlight-start
 | 
			
		||||
  /* parse */
 | 
			
		||||
  const wb = read(ab);
 | 
			
		||||
 | 
			
		||||
  /* generate array of presidents from the first worksheet */
 | 
			
		||||
  const ws = wb.Sheets[wb.SheetNames[0]]; // get the first worksheet
 | 
			
		||||
  const data: President[] = utils.sheet_to_json<President>(ws); // generate objects
 | 
			
		||||
 | 
			
		||||
  /* update state */
 | 
			
		||||
  setPres(data); // update state
 | 
			
		||||
  // highlight-end
 | 
			
		||||
})(); }, []);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
  </TabItem>
 | 
			
		||||
</Tabs>
 | 
			
		||||
 | 
			
		||||
#### Rendering Data
 | 
			
		||||
 | 
			
		||||
Kaioponents typically render HTML tables from arrays of objects. The `TR` table
 | 
			
		||||
row elements are typically generated by mapping over the state array, as shown
 | 
			
		||||
in the example JSX code:
 | 
			
		||||
 | 
			
		||||
```jsx title="Example JSX for displaying arrays of objects"
 | 
			
		||||
<table>
 | 
			
		||||
  {/* The `thead` section includes the table header row */}
 | 
			
		||||
  <thead><tr><th>Name</th><th>Index</th></tr></thead>
 | 
			
		||||
  {/* The `tbody` section includes the data rows */}
 | 
			
		||||
  <tbody>
 | 
			
		||||
    {/* generate row (TR) for each president */}
 | 
			
		||||
// highlight-start
 | 
			
		||||
    {pres.map(row => (
 | 
			
		||||
      <tr>
 | 
			
		||||
        {/* Generate cell (TD) for name / index */}
 | 
			
		||||
        <td>{row.Name}</td>
 | 
			
		||||
        <td>{row.Index}</td>
 | 
			
		||||
      </tr>
 | 
			
		||||
    ))}
 | 
			
		||||
// highlight-end
 | 
			
		||||
  </tbody>
 | 
			
		||||
</table>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### Exporting Data
 | 
			
		||||
 | 
			
		||||
The [`writeFile`](/docs/api/write-options) and [`json_to_sheet`](/docs/api/utilities/array#array-of-objects-input)
 | 
			
		||||
functions simplify exporting data. They are best used in the function bodies of
 | 
			
		||||
`useCallback`[^4] hooks attached to button or other elements.
 | 
			
		||||
 | 
			
		||||
A callback can generate a local file when a user clicks a button:
 | 
			
		||||
 | 
			
		||||
```mermaid
 | 
			
		||||
flowchart LR
 | 
			
		||||
  state((Kaioponent\nstate))
 | 
			
		||||
  ws(SheetJS\nWorksheet)
 | 
			
		||||
  wb(SheetJS\nWorkbook)
 | 
			
		||||
  file[(XLSX\nexport)]
 | 
			
		||||
  state --> |json_to_sheet\n\n| ws
 | 
			
		||||
  ws --> |book_new\nbook_append_sheet| wb
 | 
			
		||||
  wb --> |writeFile\n\n| file
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```ts
 | 
			
		||||
import { useCallback } from 'kaioken';
 | 
			
		||||
import { utils, writeFile } from 'xlsx';
 | 
			
		||||
 | 
			
		||||
/* get state data and export to XLSX */
 | 
			
		||||
const exportFile = useCallback(() => {
 | 
			
		||||
  /* generate worksheet from state */
 | 
			
		||||
  // highlight-next-line
 | 
			
		||||
  const ws = utils.json_to_sheet(pres);
 | 
			
		||||
  /* create workbook and append worksheet */
 | 
			
		||||
  const wb = utils.book_new();
 | 
			
		||||
  utils.book_append_sheet(wb, ws, "Data");
 | 
			
		||||
  /* export to XLSX */
 | 
			
		||||
  writeFile(wb, "SheetJSKaiokenAoO.xlsx");
 | 
			
		||||
}, [pres]);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### Complete Kaioponent
 | 
			
		||||
 | 
			
		||||
This complete Kaioponent example fetches a test file and displays the data in a
 | 
			
		||||
HTML table. When the export button is clicked, a callback will export a file:
 | 
			
		||||
 | 
			
		||||
```tsx title="src/SheetJSKaiokenAoO.tsx"
 | 
			
		||||
import { useCallback, useEffect, useState } from "kaioken";
 | 
			
		||||
import { read, utils, writeFileXLSX } from 'xlsx';
 | 
			
		||||
 | 
			
		||||
interface President {
 | 
			
		||||
  Name: string;
 | 
			
		||||
  Index: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default function SheetJSKaiokenAoO() {
 | 
			
		||||
  /* the kaioponent state is an array of presidents */
 | 
			
		||||
  const [pres, setPres] = useState<President[]>([]);
 | 
			
		||||
 | 
			
		||||
  /* Fetch and update the state once */
 | 
			
		||||
  useEffect(() => { (async() => {
 | 
			
		||||
    const f = await (await fetch("https://sheetjs.com/pres.xlsx")).arrayBuffer();
 | 
			
		||||
    const wb = read(f); // parse the array buffer
 | 
			
		||||
    const ws = wb.Sheets[wb.SheetNames[0]]; // get the first worksheet
 | 
			
		||||
    const data = utils.sheet_to_json<President>(ws); // generate objects
 | 
			
		||||
    setPres(data); // update state
 | 
			
		||||
  })(); }, []);
 | 
			
		||||
 | 
			
		||||
  /* get state data and export to XLSX */
 | 
			
		||||
  const exportFile = useCallback(() => {
 | 
			
		||||
    const ws = utils.json_to_sheet(pres);
 | 
			
		||||
    const wb = utils.book_new();
 | 
			
		||||
    utils.book_append_sheet(wb, ws, "Data");
 | 
			
		||||
    writeFileXLSX(wb, "SheetJSKaiokenAoO.xlsx");
 | 
			
		||||
  }, [pres]);
 | 
			
		||||
 | 
			
		||||
  return (<table><thead><tr><th>Name</th><th>Index</th></tr></thead><tbody>
 | 
			
		||||
    { /* generate row for each president */
 | 
			
		||||
      pres.map(pres => (<tr>
 | 
			
		||||
        <td>{pres.Name}</td>
 | 
			
		||||
        <td>{pres.Index}</td>
 | 
			
		||||
      </tr>))
 | 
			
		||||
    }
 | 
			
		||||
  </tbody><tfoot><td colSpan={2}>
 | 
			
		||||
    <button onclick={exportFile}>Export XLSX</button>
 | 
			
		||||
  </td></tfoot></table>);
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
<details open><summary><b>How to run the example</b> (click to hide)</summary>
 | 
			
		||||
 | 
			
		||||
<Tabs groupId="starter">
 | 
			
		||||
  <TabItem name="vite" value="ViteJS">
 | 
			
		||||
 | 
			
		||||
:::note Tested Deployments
 | 
			
		||||
 | 
			
		||||
This demo was tested in the following environments:
 | 
			
		||||
 | 
			
		||||
| Kaioken  | ViteJS  | Date       |
 | 
			
		||||
|:---------|:--------|:-----------|
 | 
			
		||||
| `0.11.2` | `5.2.6` | 2024-03-24 |
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
1) Create a new site.
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
npm create vite@latest sheetjs-kaioken -- --template vanilla-ts
 | 
			
		||||
cd sheetjs-kaioken
 | 
			
		||||
pnpm add --save kaioken
 | 
			
		||||
pnpm add --save vite-plugin-kaioken -D
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
2) Create a new file `vite.config.ts` with the following content:
 | 
			
		||||
 | 
			
		||||
```ts title="vite.config.ts (create new file)"
 | 
			
		||||
import { defineConfig } from "vite"
 | 
			
		||||
import kaioken from "vite-plugin-kaioken"
 | 
			
		||||
 | 
			
		||||
export default defineConfig({
 | 
			
		||||
  esbuild: {
 | 
			
		||||
    jsxInject: `import * as kaioken from "kaioken"`,
 | 
			
		||||
    jsx: "transform",
 | 
			
		||||
    jsxFactory: "kaioken.createElement",
 | 
			
		||||
    jsxFragment: "kaioken.fragment",
 | 
			
		||||
    loader: "tsx",
 | 
			
		||||
    include: ["**/*.tsx", "**/*.ts", "**/*.jsx", "**/*.js"],
 | 
			
		||||
  },
 | 
			
		||||
  plugins: [kaioken()],
 | 
			
		||||
})
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
3) Edit `tsconfig.json` and add `"jsx": "preserve"` within `compilerOptions`:
 | 
			
		||||
 | 
			
		||||
```js title="tsconfig.json (add highlighted line)"
 | 
			
		||||
{
 | 
			
		||||
  "compilerOptions": {
 | 
			
		||||
// highlight-next-line
 | 
			
		||||
    "jsx": "preserve",
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
4) Replace `src/main.ts` with the following codeblock:
 | 
			
		||||
 | 
			
		||||
```ts title="src/main.ts (replace contents)"
 | 
			
		||||
import { mount } from "kaioken";
 | 
			
		||||
import App from "./SheetJSKaiokenAoO";
 | 
			
		||||
 | 
			
		||||
const root = document.getElementById("app");
 | 
			
		||||
mount(App, root!);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
5) Create a new file `src/SheetJSKaiokenAoO.tsx` using the original code example.
 | 
			
		||||
 | 
			
		||||
6) Install the SheetJS dependency and start the dev server:
 | 
			
		||||
 | 
			
		||||
<CodeBlock language="bash">{`\
 | 
			
		||||
pnpm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz
 | 
			
		||||
pnpm run dev`}
 | 
			
		||||
</CodeBlock>
 | 
			
		||||
 | 
			
		||||
7) Open a web browser and access the displayed URL (`http://localhost:5173`)
 | 
			
		||||
 | 
			
		||||
The page will refresh and show a table with an Export button.  Click the button
 | 
			
		||||
and the page will attempt to download `SheetJSKaiokenAoO.xlsx`.
 | 
			
		||||
 | 
			
		||||
8) Build the site:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
pnpm run build
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The generated site will be placed in the `dist` folder.
 | 
			
		||||
 | 
			
		||||
9) Start a local web server:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
npx http-server dist
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Access the displayed URL (typically `http://localhost:8080`) with a web browser
 | 
			
		||||
and test the page.
 | 
			
		||||
 | 
			
		||||
  </TabItem>
 | 
			
		||||
</Tabs>
 | 
			
		||||
 | 
			
		||||
When the page loads, the app will fetch <https://sheetjs.com/pres.xlsx> and
 | 
			
		||||
display the data from the first worksheet in a TABLE. The "Export XLSX" button
 | 
			
		||||
will generate a workbook that can be opened in a spreadsheet editor.
 | 
			
		||||
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
### HTML
 | 
			
		||||
 | 
			
		||||
The main disadvantage of the Array of Objects approach is the specific nature
 | 
			
		||||
of the columns.  For more general use, passing around an Array of Arrays works.
 | 
			
		||||
However, this does not handle merge cells well!
 | 
			
		||||
 | 
			
		||||
The [`sheet_to_html`](/docs/api/utilities/html#html-table-output) function
 | 
			
		||||
generates HTML that is aware of merges and other worksheet features. To add the
 | 
			
		||||
table to the page, the current recommendation involves setting the `innerHTML`
 | 
			
		||||
attribute of a `ref`.
 | 
			
		||||
 | 
			
		||||
In this example, the kaioponent attaches a `ref` to the `DIV` container. During
 | 
			
		||||
export, the first `TABLE` child element can be parsed with [`table_to_book`](/docs/api/utilities/html#html-table-input) to
 | 
			
		||||
generate a workbook object.
 | 
			
		||||
 | 
			
		||||
```tsx title="src/SheetJSKaiokenHTML.tsx"
 | 
			
		||||
import { useCallback, useEffect, useRef } from "kaioken";
 | 
			
		||||
import { read, utils, writeFileXLSX } from 'xlsx';
 | 
			
		||||
 | 
			
		||||
export default function SheetJSKaiokenHTML() {
 | 
			
		||||
  /* the ref is used in export */
 | 
			
		||||
  const tbl = useRef<Element>(null);
 | 
			
		||||
 | 
			
		||||
  /* Fetch and update the state once */
 | 
			
		||||
  useEffect(() => { (async() => {
 | 
			
		||||
    const f = await (await fetch("https://sheetjs.com/pres.xlsx")).arrayBuffer();
 | 
			
		||||
    const wb = read(f); // parse the array buffer
 | 
			
		||||
    const ws = wb.Sheets[wb.SheetNames[0]]; // get the first worksheet
 | 
			
		||||
    // highlight-start
 | 
			
		||||
    const data = utils.sheet_to_html(ws); // generate HTML
 | 
			
		||||
    if(tbl.current == null) return;
 | 
			
		||||
    tbl.current.innerHTML = data;
 | 
			
		||||
    // highlight-end
 | 
			
		||||
  })(); }, []);
 | 
			
		||||
 | 
			
		||||
  /* get live table and export to XLSX */
 | 
			
		||||
  const exportFile = useCallback(() => {
 | 
			
		||||
    // highlight-start
 | 
			
		||||
    const elt = tbl.current!.getElementsByTagName("TABLE")[0];
 | 
			
		||||
    const wb = utils.table_to_book(elt);
 | 
			
		||||
    // highlight-end
 | 
			
		||||
    writeFileXLSX(wb, "SheetJSKaiokenHTML.xlsx");
 | 
			
		||||
  }, [tbl]);
 | 
			
		||||
 | 
			
		||||
  return ( <>
 | 
			
		||||
    <button onclick={exportFile}>Export XLSX</button>
 | 
			
		||||
  // highlight-next-line
 | 
			
		||||
    <div ref={tbl}/>
 | 
			
		||||
  </> );
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
<details open><summary><b>How to run the example</b> (click to hide)</summary>
 | 
			
		||||
 | 
			
		||||
<Tabs groupId="starter">
 | 
			
		||||
  <TabItem name="vite" value="ViteJS">
 | 
			
		||||
 | 
			
		||||
:::note Tested Deployments
 | 
			
		||||
 | 
			
		||||
This demo was tested in the following environments:
 | 
			
		||||
 | 
			
		||||
| Kaioken  | ViteJS  | Date       |
 | 
			
		||||
|:---------|:--------|:-----------|
 | 
			
		||||
| `0.11.2` | `5.2.6` | 2024-03-24 |
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
1) Create a new site.
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
npm create vite@latest sheetjs-kaioken -- --template vanilla-ts
 | 
			
		||||
cd sheetjs-kaioken
 | 
			
		||||
pnpm add --save kaioken
 | 
			
		||||
pnpm add --save vite-plugin-kaioken -D
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
2) Create a new file `vite.config.ts` with the following content:
 | 
			
		||||
 | 
			
		||||
```ts title="vite.config.ts (create new file)"
 | 
			
		||||
import { defineConfig } from "vite"
 | 
			
		||||
import kaioken from "vite-plugin-kaioken"
 | 
			
		||||
 | 
			
		||||
export default defineConfig({
 | 
			
		||||
  esbuild: {
 | 
			
		||||
    jsxInject: `import * as kaioken from "kaioken"`,
 | 
			
		||||
    jsx: "transform",
 | 
			
		||||
    jsxFactory: "kaioken.createElement",
 | 
			
		||||
    jsxFragment: "kaioken.fragment",
 | 
			
		||||
    loader: "tsx",
 | 
			
		||||
    include: ["**/*.tsx", "**/*.ts", "**/*.jsx", "**/*.js"],
 | 
			
		||||
  },
 | 
			
		||||
  plugins: [kaioken()],
 | 
			
		||||
})
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
3) Edit `tsconfig.json` and add `"jsx": "preserve"` within `compilerOptions`:
 | 
			
		||||
 | 
			
		||||
```js title="tsconfig.json (add highlighted line)"
 | 
			
		||||
{
 | 
			
		||||
  "compilerOptions": {
 | 
			
		||||
// highlight-next-line
 | 
			
		||||
    "jsx": "preserve",
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
4) Replace `src/main.ts` with the following codeblock:
 | 
			
		||||
 | 
			
		||||
```ts title="src/main.ts (replace contents)"
 | 
			
		||||
import { mount } from "kaioken";
 | 
			
		||||
import App from "./SheetJSKaiokenHTML";
 | 
			
		||||
 | 
			
		||||
const root = document.getElementById("app");
 | 
			
		||||
mount(App, root!);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
5) Create a new file `src/SheetJSKaiokenHTML.tsx` using the original code example.
 | 
			
		||||
 | 
			
		||||
6) Install the SheetJS dependency and start the dev server:
 | 
			
		||||
 | 
			
		||||
<CodeBlock language="bash">{`\
 | 
			
		||||
pnpm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz
 | 
			
		||||
pnpm run dev`}
 | 
			
		||||
</CodeBlock>
 | 
			
		||||
 | 
			
		||||
7) Open a web browser and access the displayed URL (`http://localhost:5173`)
 | 
			
		||||
 | 
			
		||||
The page will refresh and show a table with an Export button.  Click the button
 | 
			
		||||
and the page will attempt to download `SheetJSKaiokenHTML.xlsx`.
 | 
			
		||||
 | 
			
		||||
8) Build the site:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
pnpm run build
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The generated site will be placed in the `dist` folder.
 | 
			
		||||
 | 
			
		||||
9) Start a local web server:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
npx http-server dist
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Access the displayed URL (typically `http://localhost:8080`) with a web browser
 | 
			
		||||
and test the page.
 | 
			
		||||
 | 
			
		||||
  </TabItem>
 | 
			
		||||
</Tabs>
 | 
			
		||||
 | 
			
		||||
When the page loads, the app will fetch <https://sheetjs.com/pres.xlsx> and
 | 
			
		||||
display the data from the first worksheet in a TABLE. The "Export XLSX" button
 | 
			
		||||
will generate a workbook that can be opened in a spreadsheet editor.
 | 
			
		||||
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
[^1]: See [`useState`](https://kaioken.dev/docs/hooks/usestate) in the Kaioken documentation.
 | 
			
		||||
[^2]: See [`useEffect`](https://kaioken.dev/docs/hooks/useeffect) in the Kaioken documentation.
 | 
			
		||||
[^3]: See [`useCallback`](https://kaioken.dev/docs/hooks/usecallback) in the Kaioken documentation.
 | 
			
		||||
[^4]: See [`useCallback`](https://kaioken.dev/docs/hooks/usecallback) in the Kaioken documentation.
 | 
			
		||||
@ -4,7 +4,7 @@ sidebar_label: ReactJS
 | 
			
		||||
description: Build interactive websites with ReactJS. Seamlessly integrate spreadsheets into your app using SheetJS. Bring Excel-powered workflows and data to the modern web.
 | 
			
		||||
pagination_prev: demos/index
 | 
			
		||||
pagination_next: demos/grid/index
 | 
			
		||||
sidebar_position: 1
 | 
			
		||||
sidebar_position: 2
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
import current from '/version.js';
 | 
			
		||||
@ -4,7 +4,7 @@ sidebar_label: VueJS
 | 
			
		||||
description: Build interactive websites with VueJS. Seamlessly integrate spreadsheets into your app using SheetJS. Bring Excel-powered workflows and data to the modern web.
 | 
			
		||||
pagination_prev: demos/index
 | 
			
		||||
pagination_next: demos/grid/index
 | 
			
		||||
sidebar_position: 2
 | 
			
		||||
sidebar_position: 4
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
import current from '/version.js';
 | 
			
		||||
@ -4,7 +4,7 @@ sidebar_label: Svelte
 | 
			
		||||
description: Build interactive websites with Svelte. Seamlessly integrate spreadsheets into your app using SheetJS. Bring Excel-powered workflows and data to the modern web.
 | 
			
		||||
pagination_prev: demos/index
 | 
			
		||||
pagination_next: demos/grid/index
 | 
			
		||||
sidebar_position: 4
 | 
			
		||||
sidebar_position: 5
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
import current from '/version.js';
 | 
			
		||||
@ -405,7 +405,7 @@ This demo was tested in the following environments:
 | 
			
		||||
| Architecture | PhantomJS | Date       |
 | 
			
		||||
|:-------------|:----------|:-----------|
 | 
			
		||||
| `darwin-x64` | `2.1.1`   | 2024-03-15 |
 | 
			
		||||
| `win10-x64`  | `2.1.1`   | 2024-02-23 |
 | 
			
		||||
| `win10-x64`  | `2.1.1`   | 2024-03-24 |
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -299,7 +299,7 @@ This demo was tested in the following environments:
 | 
			
		||||
|:---------------|:-------------|:---------|:-----------|
 | 
			
		||||
| macOS 14.4     | `darwin-x64` | `v2.8.0` | 2024-03-15 |
 | 
			
		||||
| macOS 14.1.2   | `darwin-arm` | `v2.6.0` | 2023-12-01 |
 | 
			
		||||
| Windows 10     | `win10-x64`  | `v2.8.0` | 2024-03-10 |
 | 
			
		||||
| Windows 10     | `win10-x64`  | `v2.8.0` | 2024-03-24 |
 | 
			
		||||
| Windows 11     | `win11-arm`  | `v2.6.0` | 2023-12-01 |
 | 
			
		||||
| Linux (HoloOS) | `linux-x64`  | `v2.8.0` | 2024-03-21 |
 | 
			
		||||
| Linux (Debian) | `linux-arm`  | `v2.6.0` | 2023-12-01 |
 | 
			
		||||
 | 
			
		||||
@ -150,10 +150,14 @@ async function openFile() {
 | 
			
		||||
 | 
			
		||||
At this point, standard SheetJS utility functions[^8] can extract data from the
 | 
			
		||||
workbook object. The demo includes a button that calls `sheet_to_json`[^9] to
 | 
			
		||||
generate an array of arrays of data. The following snippet uses VueJS framework
 | 
			
		||||
but the same logic works with ReactJS and other front-end frameworks:
 | 
			
		||||
generate an array of arrays of data.
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
<Tabs groupId="framework">
 | 
			
		||||
  <TabItem value="vuejs" label="VueJS">
 | 
			
		||||
 | 
			
		||||
The following snippet uses the VueJS framework:
 | 
			
		||||
 | 
			
		||||
```js title="VueJS sample"
 | 
			
		||||
import { utils } from 'xlsx';
 | 
			
		||||
import { shallowRef } from 'vue';
 | 
			
		||||
const data = shallowRef([[]]); // update data by setting `data.value`
 | 
			
		||||
@ -174,6 +178,45 @@ const open_button_callback = async() => {
 | 
			
		||||
};
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
  </TabItem>
 | 
			
		||||
  <TabItem value="kaioken" label="Kaioken" default>
 | 
			
		||||
 | 
			
		||||
The following snippet shows a simple Kaioponent:
 | 
			
		||||
 | 
			
		||||
```tsx title="Kaioponent for importing data"
 | 
			
		||||
import { utils } from 'xlsx';
 | 
			
		||||
import { useState } from 'kaioken';
 | 
			
		||||
 | 
			
		||||
function SheetJSImportKaioponent() {
 | 
			
		||||
  const [data, setData] = useState<any[][]>([]);
 | 
			
		||||
 | 
			
		||||
  const open_callback = async() => {
 | 
			
		||||
    const wb = await openFile();
 | 
			
		||||
 | 
			
		||||
    /* get the first worksheet */
 | 
			
		||||
    // highlight-start
 | 
			
		||||
    const ws = wb.Sheets[wb.SheetNames[0]];
 | 
			
		||||
    // highlight-end
 | 
			
		||||
 | 
			
		||||
    /* get data from the first worksheet */
 | 
			
		||||
    // highlight-start
 | 
			
		||||
    const array = utils.sheet_to_json(ws, { header: 1 });
 | 
			
		||||
    // highlight-end
 | 
			
		||||
    setData(array);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return ( <>
 | 
			
		||||
    <button type="button" onclick={open_callback}>Load Data</button>
 | 
			
		||||
    <table><tbody>{data.map((row) =>
 | 
			
		||||
      <tr>{row.map((cell) => <td>{cell}</td>)}</tr>
 | 
			
		||||
    )}</tbody></table>
 | 
			
		||||
  </>);
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
  </TabItem>
 | 
			
		||||
</Tabs>
 | 
			
		||||
 | 
			
		||||
### Writing Files
 | 
			
		||||
 | 
			
		||||
There are three steps to writing files:
 | 
			
		||||
@ -221,10 +264,14 @@ async function saveFile(wb) {
 | 
			
		||||
 | 
			
		||||
The demo includes a button that calls `aoa_to_sheet`[^14] to generate a sheet
 | 
			
		||||
from array of arrays of data. A workbook is constructed using `book_new` and
 | 
			
		||||
`book_append_sheet`[^15]. The following snippet uses VueJS framework but the
 | 
			
		||||
same logic works with ReactJS and other front-end frameworks:
 | 
			
		||||
`book_append_sheet`[^15].
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
<Tabs groupId="framework">
 | 
			
		||||
  <TabItem value="vuejs" label="VueJS">
 | 
			
		||||
 | 
			
		||||
The following snippet uses the VueJS framework:
 | 
			
		||||
 | 
			
		||||
```js title="VueJS sample"
 | 
			
		||||
import { utils } from 'xlsx';
 | 
			
		||||
import { shallowRef } from 'vue';
 | 
			
		||||
const data = shallowRef([[]]); // `data.value` is an array of arrays
 | 
			
		||||
@ -249,6 +296,45 @@ const save_button_callback = async() => {
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
  </TabItem>
 | 
			
		||||
  <TabItem value="kaioken" label="Kaioken" default>
 | 
			
		||||
 | 
			
		||||
The following snippet shows a simple Kaioponent:
 | 
			
		||||
 | 
			
		||||
```js title="Kaioponent for exporting data"
 | 
			
		||||
import { utils } from 'xlsx';
 | 
			
		||||
import { useState } from 'kaioken';
 | 
			
		||||
 | 
			
		||||
function SheetJSExportKaioponent() {
 | 
			
		||||
  const [data, setData] = useState<any[][]>(["SheetJS".split(""), "Kaioken".split("")]);
 | 
			
		||||
 | 
			
		||||
  const save_callback = async() => {
 | 
			
		||||
    /* generate worksheet from the data */
 | 
			
		||||
    // highlight-start
 | 
			
		||||
    const ws = utils.aoa_to_sheet(data);
 | 
			
		||||
    // highlight-end
 | 
			
		||||
 | 
			
		||||
    /* create a new workbook object */
 | 
			
		||||
    // highlight-start
 | 
			
		||||
    const wb = utils.book_new();
 | 
			
		||||
    // highlight-end
 | 
			
		||||
 | 
			
		||||
    /* append the worksheet to the workbook using the sheet name "SheetJSTauri" */
 | 
			
		||||
    // highlight-start
 | 
			
		||||
    utils.book_append_sheet(wb, ws, "SheetJSTauri");
 | 
			
		||||
    // highlight-end
 | 
			
		||||
 | 
			
		||||
    await saveFile(wb);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return ( <button type="button" onclick={save_callback}>Save Data</button> );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
  </TabItem>
 | 
			
		||||
</Tabs>
 | 
			
		||||
 | 
			
		||||
## Complete Example
 | 
			
		||||
 | 
			
		||||
:::note Tested Deployments
 | 
			
		||||
@ -259,7 +345,7 @@ This demo was tested in the following environments:
 | 
			
		||||
|:---------------|:-------------|:----------|:-----------|
 | 
			
		||||
| macOS 14.4     | `darwin-x64` | `v1.5.11` | 2024-03-15 |
 | 
			
		||||
| macOS 14.0     | `darwin-arm` | `v1.5.2`  | 2023-10-18 |
 | 
			
		||||
| Windows 10     | `win10-x64`  | `v1.5.0`  | 2023-10-01 |
 | 
			
		||||
| Windows 10     | `win10-x64`  | `v1.5.11` | 2024-03-24 |
 | 
			
		||||
| Windows 11     | `win11-arm`  | `v1.5.7`  | 2023-12-01 |
 | 
			
		||||
| Linux (HoloOS) | `linux-x64`  | `v1.5.11` | 2024-03-21 |
 | 
			
		||||
| Linux (Debian) | `linux-arm`  | `v1.5.7`  | 2023-12-01 |
 | 
			
		||||
@ -309,10 +395,30 @@ build step will correctly detect the platform architecture.
 | 
			
		||||
 | 
			
		||||
1) Create a new Tauri app:
 | 
			
		||||
 | 
			
		||||
<Tabs groupId="framework">
 | 
			
		||||
  <TabItem value="vuejs" label="VueJS">
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
npm create tauri-app@latest -- -m npm -t vue-ts SheetJSTauri -y
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
  </TabItem>
 | 
			
		||||
  <TabItem value="kaioken" label="Kaioken" default>
 | 
			
		||||
 | 
			
		||||
:::note pass
 | 
			
		||||
 | 
			
		||||
There is no official Tauri Kaioken template. This demo starts from the vanilla
 | 
			
		||||
TypeScript template and manually wires Kaioken
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
npm create tauri-app@latest -- -m npm -t vanilla-ts SheetJSTauri -y
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
  </TabItem>
 | 
			
		||||
</Tabs>
 | 
			
		||||
 | 
			
		||||
2) Enter the directory and install dependencies:
 | 
			
		||||
 | 
			
		||||
<CodeBlock language="bash">{`\
 | 
			
		||||
@ -322,6 +428,20 @@ npm i --save @tauri-apps/api
 | 
			
		||||
npm i --save-dev @tauri-apps/cli`}
 | 
			
		||||
</CodeBlock>
 | 
			
		||||
 | 
			
		||||
<Tabs groupId="framework">
 | 
			
		||||
  <TabItem value="vuejs" label="VueJS">
 | 
			
		||||
 | 
			
		||||
  </TabItem>
 | 
			
		||||
  <TabItem value="kaioken" label="Kaioken" default>
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
npm add kaioken --save
 | 
			
		||||
npm add vite-plugin-kaioken -D --save
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
  </TabItem>
 | 
			
		||||
</Tabs>
 | 
			
		||||
 | 
			
		||||
3) Add the highlighted lines to `src-tauri/tauri.conf.json` in the
 | 
			
		||||
   `tauri.allowlist` section:
 | 
			
		||||
 | 
			
		||||
@ -353,6 +473,8 @@ In the same file, look for the `"identifier"` key and replace the value with `co
 | 
			
		||||
      "longDescription": "",
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
<Tabs groupId="framework">
 | 
			
		||||
  <TabItem value="vuejs" label="VueJS">
 | 
			
		||||
 | 
			
		||||
4) Download [`App.vue`](pathname:///tauri/App.vue) and replace `src/App.vue`
 | 
			
		||||
   with the downloaded script.
 | 
			
		||||
@ -361,6 +483,99 @@ In the same file, look for the `"identifier"` key and replace the value with `co
 | 
			
		||||
curl -o src/App.vue https://docs.sheetjs.com/tauri/App.vue
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
  </TabItem>
 | 
			
		||||
  <TabItem value="kaioken" label="Kaioken" default>
 | 
			
		||||
 | 
			
		||||
4) Wire up Kaioken to the Tauri app:
 | 
			
		||||
 | 
			
		||||
- Add the highlighted lines to `vite.config.ts`:
 | 
			
		||||
 | 
			
		||||
```ts title="vite.config.ts (add highlighted lines)"
 | 
			
		||||
import { defineConfig } from "vite";
 | 
			
		||||
// highlight-next-line
 | 
			
		||||
import kaioken from "vite-plugin-kaioken"
 | 
			
		||||
 | 
			
		||||
// https://vitejs.dev/config/
 | 
			
		||||
export default defineConfig(async () => ({
 | 
			
		||||
// highlight-start
 | 
			
		||||
  esbuild: {
 | 
			
		||||
    jsxInject: `import * as kaioken from "kaioken"`,
 | 
			
		||||
    jsx: "transform",
 | 
			
		||||
    jsxFactory: "kaioken.createElement",
 | 
			
		||||
    jsxFragment: "kaioken.fragment",
 | 
			
		||||
    loader: "tsx",
 | 
			
		||||
    include: ["**/*.tsx", "**/*.ts", "**/*.jsx", "**/*.js"],
 | 
			
		||||
  },
 | 
			
		||||
  plugins: [kaioken()],
 | 
			
		||||
// highlight-end
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
- Add the highlighted line to `tsconfig.json`:
 | 
			
		||||
 | 
			
		||||
```js title="tsconfig.json (add highlighted line)"
 | 
			
		||||
{
 | 
			
		||||
  "compilerOptions": {
 | 
			
		||||
// highlight-next-line
 | 
			
		||||
    "jsx": "preserve",
 | 
			
		||||
    "target": "ES2020",
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
- Replace `index.html` with the following codeblock:
 | 
			
		||||
 | 
			
		||||
```html title="index.html"
 | 
			
		||||
<!doctype html>
 | 
			
		||||
<html lang="en">
 | 
			
		||||
  <head>
 | 
			
		||||
    <meta charset="UTF-8" />
 | 
			
		||||
    <link rel="stylesheet" href="/src/styles.css" />
 | 
			
		||||
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
 | 
			
		||||
    <title>SheetJS x Tauri</title>
 | 
			
		||||
    <script type="module" src="/src/main.ts" defer></script>
 | 
			
		||||
  </head>
 | 
			
		||||
 | 
			
		||||
  <body>
 | 
			
		||||
    <div id="container" class="container"></div>
 | 
			
		||||
  </body>
 | 
			
		||||
</html>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
- Add the following lines to `src/styles.css`:
 | 
			
		||||
 | 
			
		||||
```css title="src/styles.css (add to end)"
 | 
			
		||||
.logo {
 | 
			
		||||
  padding: 0px;
 | 
			
		||||
  height: 64px; width: 64px;
 | 
			
		||||
  vertical-align: middle;
 | 
			
		||||
}
 | 
			
		||||
.logo:hover {
 | 
			
		||||
  filter: drop-shadow(0 0 2em #646cffaa);
 | 
			
		||||
}
 | 
			
		||||
.centre { text-align: center; }
 | 
			
		||||
table.center {
 | 
			
		||||
  margin-left: auto;
 | 
			
		||||
  margin-right: auto;
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
- Replace `src/main.ts` with the following codeblock:
 | 
			
		||||
 | 
			
		||||
```ts title="src/main.ts"
 | 
			
		||||
import { mount } from "kaioken";
 | 
			
		||||
import App from "./App";
 | 
			
		||||
 | 
			
		||||
const root = document.getElementById("container");
 | 
			
		||||
mount(App, root!);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
- Download [`App.tsx`](pathname:///tauri/App.tsx) and save to `src/App.tsx`:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
curl -o src/App.tsx https://docs.sheetjs.com/tauri/App.tsx
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
  </TabItem>
 | 
			
		||||
</Tabs>
 | 
			
		||||
 | 
			
		||||
5) Build the app with
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
 | 
			
		||||
@ -194,7 +194,7 @@ This demo was tested in the following environments:
 | 
			
		||||
|:---------------|:-------------|:---------|:---------|:-----------|
 | 
			
		||||
| macOS 14.4     | `darwin-x64` | `5.0.0`  | `5.0.1`  | 2024-03-15 |
 | 
			
		||||
| macOS 14.0     | `darwin-arm` | `4.14.1` | `3.12.0` | 2023-10-18 |
 | 
			
		||||
| Windows 10     | `win10-x64`  | `4.14.1` | `3.12.0` | 2023-12-09 |
 | 
			
		||||
| Windows 10     | `win10-x64`  | `5.1.0`  | `5.1.0`  | 2024-03-24 |
 | 
			
		||||
| Windows 11     | `win11-arm`  | `4.14.1` | `3.12.0` | 2023-12-01 |
 | 
			
		||||
| Linux (HoloOS) | `linux-x64`  | `5.0.0`  | `5.0.1`  | 2024-03-21 |
 | 
			
		||||
| Linux (Debian) | `linux-arm`  | `4.14.1` | `3.12.0` | 2023-12-01 |
 | 
			
		||||
 | 
			
		||||
@ -46,10 +46,10 @@ This demo was tested in the following environments:
 | 
			
		||||
 | 
			
		||||
| OS and Version | Architecture | RN Platform | Date       |
 | 
			
		||||
|:---------------|:-------------|:------------|:-----------|
 | 
			
		||||
| Windows 10     | `win10-x64`  | `v0.72.16`  | 2023-10-27 |
 | 
			
		||||
| Windows 10     | `win10-x64`  | `v0.73.11`  | 2024-03-24 |
 | 
			
		||||
| Windows 11     | `win11-x64`  | `v0.72.12`  | 2023-10-14 |
 | 
			
		||||
| Windows 11     | `win11-arm`  | `v0.72.20`  | 2023-12-01 |
 | 
			
		||||
| MacOS 14.4     | `darwin-x64` | `v0.73.21`  | 2024-03-15 |
 | 
			
		||||
| MacOS 14.4     | `darwin-x64` | `v0.73.22`  | 2024-03-24 |
 | 
			
		||||
| MacOS 14.1.2   | `darwin-arm` | `v0.72.11`  | 2023-12-01 |
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
@ -420,10 +420,10 @@ setup instructions" to find instructions for manual installation.
 | 
			
		||||
 | 
			
		||||
### Project Setup
 | 
			
		||||
 | 
			
		||||
1) Create a new project using React Native `0.72.7`:
 | 
			
		||||
1) Create a new project using React Native `0.73.6`:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
npx react-native init SheetJSWin --template react-native@0.72.7
 | 
			
		||||
npx react-native init SheetJSWin --template react-native@0.73.6
 | 
			
		||||
cd SheetJSWin
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
@ -527,7 +527,7 @@ curl -Lo windows/SheetJSWin/DocumentPicker.cs https://docs.sheetjs.com/reactnati
 | 
			
		||||
Search for `ReactPackageProvider.cs` in the file. There will be one instance.
 | 
			
		||||
Add the highlighted line just before that instance:
 | 
			
		||||
 | 
			
		||||
```xml title="windows\SheetJSWin\SheetJSWin.csproj"
 | 
			
		||||
```xml title="windows\SheetJSWin\SheetJSWin.csproj (add highlighted line)"
 | 
			
		||||
<!-- highlight-next-line -->
 | 
			
		||||
    <Compile Include="DocumentPicker.cs" />
 | 
			
		||||
    <Compile Include="ReactPackageProvider.cs" />
 | 
			
		||||
 | 
			
		||||
@ -101,7 +101,7 @@ This demo was last tested in the following deployments:
 | 
			
		||||
|:-------------|:---------|:-----------|
 | 
			
		||||
| `darwin-x64` | `1.41.3` | 2024-03-15 |
 | 
			
		||||
| `darwin-arm` | `1.37.2` | 2023-10-18 |
 | 
			
		||||
| `win10-x64`  | `1.37.1` | 2023-10-09 |
 | 
			
		||||
| `win10-x64`  | `1.41.3` | 2024-03-24 |
 | 
			
		||||
| `win11-x64`  | `1.37.2` | 2023-10-14 |
 | 
			
		||||
| `win11-arm`  | `1.38.4` | 2023-12-01 |
 | 
			
		||||
| `linux-x64`  | `1.41.3` | 2024-03-18 |
 | 
			
		||||
@ -114,7 +114,7 @@ This demo was last tested in the following deployments:
 | 
			
		||||
1) Download the test file <https://sheetjs.com/pres.numbers>:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
curl -LO https://sheetjs.com/pres.numbers
 | 
			
		||||
curl -o pres.numbers https://sheetjs.com/pres.numbers
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
2) Test the script with `deno run`:
 | 
			
		||||
 | 
			
		||||
@ -103,7 +103,7 @@ This demo was tested in the following deployments:
 | 
			
		||||
|:-------------|:--------|:---------|:-----------|
 | 
			
		||||
| `darwin-x64` | `5.8.1` | `18.5.0` | 2024-03-15 |
 | 
			
		||||
| `darwin-arm` | `5.8.1` | `18.5.0` | 2023-12-01 |
 | 
			
		||||
| `win10-x64`  | `5.8.1` | `18.5.0` | 2023-10-09 |
 | 
			
		||||
| `win10-x64`  | `5.8.1` | `18.5.0` | 2024-03-24 |
 | 
			
		||||
| `win11-arm`  | `5.8.1` | `18.5.0` | 2023-12-01 |
 | 
			
		||||
| `linux-x64`  | `5.8.1` | `18.5.0` | 2024-03-21 |
 | 
			
		||||
| `linux-arm`  | `5.8.1` | `18.5.0` | 2023-12-01 |
 | 
			
		||||
@ -115,7 +115,7 @@ This demo was tested in the following deployments:
 | 
			
		||||
|:-------------|:--------|:----------|:-----------|
 | 
			
		||||
| `darwin-x64` | `2.4.0` | `21.7.1`  | 2024-03-15 |
 | 
			
		||||
| `darwin-arm` | `2.3.0` | `21.3.0`  | 2023-12-01 |
 | 
			
		||||
| `win10-x64`  | `2.1.2` | `16.20.2` | 2023-10-09 |
 | 
			
		||||
| `win10-x64`  | `2.4.0` | `16.20.2` | 2024-03-24 |
 | 
			
		||||
| `linux-x64`  | `2.4.0` | `21.7.1`  | 2024-03-21 |
 | 
			
		||||
| `linux-arm`  | `2.3.0` | `21.3.0`  | 2023-12-01 |
 | 
			
		||||
 | 
			
		||||
@ -127,13 +127,13 @@ This demo was tested in the following deployments:
 | 
			
		||||
0) Download the test file <https://sheetjs.com/pres.numbers>:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
curl -LO https://sheetjs.com/pres.numbers
 | 
			
		||||
curl -o pres.numbers https://sheetjs.com/pres.numbers
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
1) Download [`xlsx-cli.js`](pathname:///cli/xlsx-cli.js)
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
curl -LO https://docs.sheetjs.com/cli/xlsx-cli.js
 | 
			
		||||
curl -o xlsx-cli.js https://docs.sheetjs.com/cli/xlsx-cli.js
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
2) Install the dependencies:
 | 
			
		||||
@ -279,9 +279,35 @@ npx boxednode@2.4.0 -s xlsx-cli.js -t xlsx-cli.exe -n 16.20.2
 | 
			
		||||
:::info pass
 | 
			
		||||
 | 
			
		||||
The Windows 10 build requires Visual Studio with "Desktop development with C++"
 | 
			
		||||
workload, Python 3, and NASM[^1].
 | 
			
		||||
workload, Python 3.11, and NASM[^1].
 | 
			
		||||
 | 
			
		||||
The build command should be run in "x64 Native Tools Command Prompt"
 | 
			
		||||
**The build command must be run in "x64 Native Tools Command Prompt"**
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
:::caution pass
 | 
			
		||||
 | 
			
		||||
When the demo was last tested, the build failed:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
Not an executable Python program
 | 
			
		||||
Could not find Python.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
By default, Windows aliases `python` to a Microsoft Store installer. If the
 | 
			
		||||
official installer was used, the alias should be disabled manually:
 | 
			
		||||
 | 
			
		||||
1) Open Start menu and type "app alias". Click "Manage app execution aliases".
 | 
			
		||||
 | 
			
		||||
2) Disable the App Installer for all items with `python` in the name.
 | 
			
		||||
 | 
			
		||||
Using Python 3.12, the build fails with an error:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
Please use python3.11 or python3.10 or python3.9 or python3.8 or python3.7 or python3.6.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
In the most recent test, Python 3.11.8 was installed from the official site.
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
@ -345,7 +371,7 @@ This demo was last tested in the following deployments:
 | 
			
		||||
|:-------------|:--------------|:---------|:-----------|
 | 
			
		||||
| `darwin-x64` | `12.3.219.9`  | `0.88.0` | 2024-03-15 |
 | 
			
		||||
| `darwin-arm` | `11.8.172.13` | `0.79.2` | 2023-10-18 |
 | 
			
		||||
| `win10-x64`  | `11.8.172.13` | `0.79.2` | 2023-10-09 |
 | 
			
		||||
| `win10-x64`  | `12.3.219.9`  | `0.88.0` | 2024-03-24 |
 | 
			
		||||
| `win11-x64`  | `11.8.172.13` | `0.79.2` | 2023-10-14 |
 | 
			
		||||
| `linux-x64`  | `12.3.219.9`  | `0.88.0` | 2024-03-18 |
 | 
			
		||||
| `linux-arm`  | `12.0.267.8`  | `0.82.0` | 2023-12-01 |
 | 
			
		||||
@ -366,9 +392,9 @@ cd sheetjs2csv
 | 
			
		||||
- [`sheet2csv.rs`](pathname:///cli/sheet2csv.rs)
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
curl -LO https://docs.sheetjs.com/cli/Cargo.toml
 | 
			
		||||
curl -LO https://docs.sheetjs.com/cli/snapshot.rs
 | 
			
		||||
curl -LO https://docs.sheetjs.com/cli/sheet2csv.rs
 | 
			
		||||
curl -o Cargo.toml https://docs.sheetjs.com/cli/Cargo.toml
 | 
			
		||||
curl -o snapshot.rs https://docs.sheetjs.com/cli/snapshot.rs
 | 
			
		||||
curl -o sheet2csv.rs https://docs.sheetjs.com/cli/sheet2csv.rs
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
2) Download the SheetJS Standalone script and move to the project directory:
 | 
			
		||||
@ -378,7 +404,7 @@ curl -LO https://docs.sheetjs.com/cli/sheet2csv.rs
 | 
			
		||||
</ul>
 | 
			
		||||
 | 
			
		||||
<CodeBlock language="bash">{`\
 | 
			
		||||
curl -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js`}
 | 
			
		||||
curl -o xlsx.full.min.js https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js`}
 | 
			
		||||
</CodeBlock>
 | 
			
		||||
 | 
			
		||||
3) Build the V8 snapshot:
 | 
			
		||||
@ -414,7 +440,7 @@ cargo build --release --bin sheet2csv
 | 
			
		||||
5) Download the test file <https://sheetjs.com/pres.numbers>:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
curl -LO https://sheetjs.com/pres.numbers
 | 
			
		||||
curl -o pres.numbers https://sheetjs.com/pres.numbers
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
6) Test the application:
 | 
			
		||||
 | 
			
		||||
@ -132,7 +132,7 @@ This demo was tested in the following deployments:
 | 
			
		||||
|:-------------|:--------|:-----------|
 | 
			
		||||
| `darwin-x64` | `2.7.0` | 2024-03-15 |
 | 
			
		||||
| `darwin-arm` | `2.7.0` | 2023-10-18 |
 | 
			
		||||
| `win10-x64`  | `2.7.0` | 2023-10-27 |
 | 
			
		||||
| `win10-x64`  | `2.7.0` | 2024-03-27 |
 | 
			
		||||
| `win11-arm`  | `2.7.0` | 2023-12-01 |
 | 
			
		||||
| `linux-x64`  | `2.7.0` | 2024-03-21 |
 | 
			
		||||
| `linux-arm`  | `2.7.0` | 2023-12-01 |
 | 
			
		||||
 | 
			
		||||
@ -126,7 +126,7 @@ This demo was tested in the following deployments:
 | 
			
		||||
|:--------------|:-------------|:--------------|:-----------------|:-----------|
 | 
			
		||||
| `12.4.253`    | `darwin-x64` | macOS 14.4    | `clang 15.0.0`   | 2024-03-15 |
 | 
			
		||||
| `12.1.283`    | `darwin-arm` | macOS 14.1.2  | `clang 15.0.0`   | 2023-12-01 |
 | 
			
		||||
| `12.0.265`    | `win10-x64`  | Windows 10    | `CL 19.37.32822` | 2023-10-28 |
 | 
			
		||||
| `12.5.48`     | `win10-x64`  | Windows 10    | `CL 19.39.33523` | 2024-03-24 |
 | 
			
		||||
| `12.5.48`     | `linux-x64`  | HoloOS 3.5.17 | `gcc 13.1.1`     | 2024-03-21 |
 | 
			
		||||
| `11.8.82`     | `linux-arm`  | Debian 12     | `gcc 12.2.0`     | 2023-12-01 |
 | 
			
		||||
 | 
			
		||||
@ -865,7 +865,7 @@ This demo was last tested in the following deployments:
 | 
			
		||||
|:-------------|:---------|:-----------|
 | 
			
		||||
| `darwin-x64` | `0.88.0` | 2024-03-15 |
 | 
			
		||||
| `darwin-arm` | `0.82.0` | 2023-12-01 |
 | 
			
		||||
| `win10-x64`  | `0.81.0` | 2023-11-14 |
 | 
			
		||||
| `win10-x64`  | `0.89.0` | 2024-03-24 |
 | 
			
		||||
| `linux-x64`  | `0.89.0` | 2024-03-21 |
 | 
			
		||||
| `linux-arm`  | `0.82.0` | 2023-12-01 |
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -96,7 +96,7 @@ This demo was tested in the following deployments:
 | 
			
		||||
|:-------------|:-----------|:-----------|:-----------|
 | 
			
		||||
| `darwin-x64` | `e401ed4`  | `1.22.1`   | 2024-03-15 |
 | 
			
		||||
| `darwin-arm` | `873a149`  | `1.21.3`   | 2023-10-18 |
 | 
			
		||||
| `win10-x64`  | `b396bb4`  | `1.21.3`   | 2023-10-28 |
 | 
			
		||||
| `win10-x64`  | `e401ed4`  | `1.22.1`   | 2024-03-24 |
 | 
			
		||||
| `win11-arm`  | `b396bb4`  | `1.21.1`   | 2023-12-01 |
 | 
			
		||||
| `linux-x64`  | `e401ed4`  | `1.22.1`   | 2024-03-21 |
 | 
			
		||||
| `linux-arm`  | `b396bb4`  | `1.21.4`   | 2023-12-01 |
 | 
			
		||||
 | 
			
		||||
@ -374,7 +374,7 @@ fork, which powers React Native for Windows, does have built-in support[^5]
 | 
			
		||||
 | 
			
		||||
| Architecture | Git Commit | Date       |
 | 
			
		||||
|:-------------|:-----------|:-----------|
 | 
			
		||||
| `win10-x64`  | `930456b`  | 2023-10-28 |
 | 
			
		||||
| `win10-x64`  | `240573e`  | 2024-03-24 |
 | 
			
		||||
 | 
			
		||||
The ["Windows Example"](#windows-example) covers `hermes-windows`.
 | 
			
		||||
 | 
			
		||||
@ -544,12 +544,15 @@ contents of the first sheet as CSV rows.
 | 
			
		||||
 | 
			
		||||
<details><summary><b>Installation Notes</b> (click to show)</summary>
 | 
			
		||||
 | 
			
		||||
CMake and Visual Studio with "Desktop development with C++" workload must be
 | 
			
		||||
installed. In addition, the following Spectre-mitigated libs must be added:
 | 
			
		||||
The build sequence requires Python, which can be installed from the official
 | 
			
		||||
Windows installer[^7].
 | 
			
		||||
 | 
			
		||||
- MSVC C++ Spectre-mitigated libs (Latest)
 | 
			
		||||
- C++ ATL for latest build tools with Spectre Mitigations
 | 
			
		||||
- C++ MFC for latest build tools with Spectre Mitigations
 | 
			
		||||
Visual Studio with "Desktop development with C++" workload and Cmake must be
 | 
			
		||||
installed[^8]. In addition, the following Spectre-mitigated libs must be added:
 | 
			
		||||
 | 
			
		||||
- MSVC C++ x64/x86 Spectre-mitigated libs (Latest)
 | 
			
		||||
- C++ ATL for latest build tools with Spectre Mitigations (x86 & x64)
 | 
			
		||||
- C++ MFC for latest build tools with Spectre Mitigations (x86 & x64)
 | 
			
		||||
 | 
			
		||||
The easiest way to install is to select "Individual components" and search for
 | 
			
		||||
"spectre latest" (no quotation marks). Pick each option for the relevant CPU.
 | 
			
		||||
@ -604,7 +607,7 @@ cd sheetjs-hermes
 | 
			
		||||
```bash
 | 
			
		||||
git clone https://github.com/microsoft/hermes-windows
 | 
			
		||||
cd hermes-windows
 | 
			
		||||
git checkout 930456b
 | 
			
		||||
git checkout 240573e
 | 
			
		||||
cd ..
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
@ -645,7 +648,7 @@ Set-ExecutionPolicy -ExecutionPolicy RemoteSigned
 | 
			
		||||
 | 
			
		||||
:::info pass
 | 
			
		||||
 | 
			
		||||
In the most recent test, the command failed when trying to copy `hermes.exe`:
 | 
			
		||||
In some test runs, the command failed when trying to copy `hermes.exe`:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
Copy-Item: C:\Users\Me\Documents\hermes-windows\.ado\scripts\cibuild.ps1:331
 | 
			
		||||
@ -671,7 +674,7 @@ dir -r -Path .\hermes-windows\workspace\build\win32-x64-debug\ -Filter "*.lib" |
 | 
			
		||||
7) Download [`sheetjs-hermes.cpp`](pathname:///hermes/sheetjs-hermesw.cpp):
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
curl -LO https://docs.sheetjs.com/hermes/sheetjs-hermesw.cpp
 | 
			
		||||
curl -o sheetjs-hermesw.cpp https://docs.sheetjs.com/hermes/sheetjs-hermesw.cpp
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
8) Build the application:
 | 
			
		||||
@ -695,8 +698,8 @@ the project directory:
 | 
			
		||||
</ul>
 | 
			
		||||
 | 
			
		||||
<CodeBlock language="bash">{`\
 | 
			
		||||
curl -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js
 | 
			
		||||
curl -LO https://sheetjs.com/pres.numbers`}
 | 
			
		||||
curl -o xlsx.full.min.js https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js
 | 
			
		||||
curl -o pres.numbers https://sheetjs.com/pres.numbers`}
 | 
			
		||||
</CodeBlock>
 | 
			
		||||
 | 
			
		||||
10) Run the application:
 | 
			
		||||
@ -822,4 +825,6 @@ If successful, the script will print CSV data from the test file.
 | 
			
		||||
[^3]: See ["Workbook Object"](/docs/csf/book)
 | 
			
		||||
[^4]: See [`sheet_to_csv` in "Utilities"](/docs/api/utilities/csv#csv-output)
 | 
			
		||||
[^5]: See [`microsoft/hermes-windows`](https://github.com/microsoft/hermes-windows) on GitHub
 | 
			
		||||
[^6]: See ["Dependencies" in "Building and Running"](https://hermesengine.dev/docs/building-and-running/#dependencies) in the Hermes Documentation
 | 
			
		||||
[^6]: See ["Dependencies" in "Building and Running"](https://hermesengine.dev/docs/building-and-running/#dependencies) in the Hermes Documentation
 | 
			
		||||
[^7]: See ["Download Python"](https://www.python.org/downloads/) in the Python website.
 | 
			
		||||
[^8]: See [the Visual Studio website](https://visualstudio.microsoft.com/#vs-section) for download links.
 | 
			
		||||
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 108 KiB After Width: | Height: | Size: 145 KiB  | 
| 
		 Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB  | 
							
								
								
									
										86
									
								
								docz/static/tauri/App.tsx
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						@ -0,0 +1,86 @@
 | 
			
		||||
import { useEffect, useState } from 'kaioken'
 | 
			
		||||
import { read, write, utils, version, WorkBook } from 'xlsx';
 | 
			
		||||
import { DialogFilter, message, open, save } from '@tauri-apps/api/dialog';
 | 
			
		||||
import { fetch, ResponseType } from '@tauri-apps/api/http';
 | 
			
		||||
import { readBinaryFile, writeBinaryFile } from '@tauri-apps/api/fs';
 | 
			
		||||
 | 
			
		||||
const filters: DialogFilter[] = [
 | 
			
		||||
  {name: "Excel Binary Workbook", extensions: ["xlsb"]},
 | 
			
		||||
  {name: "Excel Workbook", extensions: ["xlsx"]},
 | 
			
		||||
  {name: "Excel 97-2004 Workbook", extensions: ["xls"]},
 | 
			
		||||
  {name: "Excel 2003 XML Spreadsheet", extensions: ["xml"]},
 | 
			
		||||
  {name: "Symbolic Link", extensions: ["slk"]},
 | 
			
		||||
  {name: "Flat OpenDocument Spreadsheet", extensions: ["fods"]},
 | 
			
		||||
  {name: "OpenDocument Spreadsheet", extensions: ["fods"]},
 | 
			
		||||
  // ...
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
export default function SheetJSTauriKaioken() {
 | 
			
		||||
  const [data, setData] = useState<any[][]>([[]])
 | 
			
		||||
  const [origin, setOrigin] = useState("");
 | 
			
		||||
 | 
			
		||||
  const update = (wb: WorkBook) => {
 | 
			
		||||
    const ws = wb.Sheets[wb.SheetNames[0]];
 | 
			
		||||
    const d = utils.sheet_to_json<any[]>(ws, { header: 1})
 | 
			
		||||
    setData(d);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  /* Load from File */
 | 
			
		||||
  const openFile = async() => {
 | 
			
		||||
    try {
 | 
			
		||||
      const selected = await open({
 | 
			
		||||
        title: "Open Spreadsheet",
 | 
			
		||||
        multiple: false,
 | 
			
		||||
        directory: false,
 | 
			
		||||
        filters
 | 
			
		||||
      }) as string;
 | 
			
		||||
      const d = await readBinaryFile(selected);
 | 
			
		||||
      const wb = read(d);
 | 
			
		||||
      update(wb);
 | 
			
		||||
      setOrigin(selected);
 | 
			
		||||
    } catch(e) { await message((e as Error).message || (e as string), { title: "Load Error", type: "error"}); }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  /* Save to File */
 | 
			
		||||
  const saveFile = async() => {
 | 
			
		||||
    try {
 | 
			
		||||
      const selected = await save({
 | 
			
		||||
        title: "Save to Spreadsheet",
 | 
			
		||||
        filters
 | 
			
		||||
      });
 | 
			
		||||
      if(!selected) throw new Error("No file selected");
 | 
			
		||||
      const ws = utils.aoa_to_sheet(data);
 | 
			
		||||
      const wb = utils.book_new();
 | 
			
		||||
      utils.book_append_sheet(wb, ws, "SheetJSTauri");
 | 
			
		||||
      const d = write(wb, {type: "buffer", bookType: selected.slice(selected.lastIndexOf(".") + 1) as any}) as Uint8Array;
 | 
			
		||||
      await writeBinaryFile(selected, d);
 | 
			
		||||
      await message(`File saved to ${selected}`);
 | 
			
		||||
    } catch(e) { await message((e as Error).message || (e as string), { title: "Save Error", type: "error"}); }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  /* Download from https://sheetjs.com/pres.numbers */
 | 
			
		||||
  useEffect(() => {(async() => {
 | 
			
		||||
    try {
 | 
			
		||||
      setOrigin("https://sheetjs.com/pres.numbers");
 | 
			
		||||
      const response = await fetch<Uint8Array>("https://sheetjs.com/pres.numbers", { method: "GET", responseType: ResponseType.Binary });
 | 
			
		||||
      const wb = read(new Uint8Array(response.data));
 | 
			
		||||
      update(wb);
 | 
			
		||||
    } catch(e) { await message((e as Error).message || (e as string), { title: "Fetch Error", type: "error"}); }
 | 
			
		||||
  })(); }, []);
 | 
			
		||||
 | 
			
		||||
  return (  <div>
 | 
			
		||||
    <h1><a href="https://sheetjs.com" target="_blank">
 | 
			
		||||
      <img src="https://sheetjs.com/sketch128.png" className="logo" alt="SheetJS" />
 | 
			
		||||
    SheetJS × Tauri {version}</a></h1>
 | 
			
		||||
 | 
			
		||||
    <div className="centre"><button type="button" onclick={openFile}>Load Data</button> or
 | 
			
		||||
    <button type="button" onclick={saveFile}>Save Data</button></div>
 | 
			
		||||
    <p className="centre"><b className="centre">Data from { origin }</b></p>
 | 
			
		||||
    <table className="center"><tbody>
 | 
			
		||||
    {data.map((row) => <tr>
 | 
			
		||||
      {row.map((cell) => <td>{cell}</td>)}
 | 
			
		||||
    </tr>)}
 | 
			
		||||
    </tbody></table>
 | 
			
		||||
  </div>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 119 KiB After Width: | Height: | Size: 23 KiB  | 
| 
		 Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 22 KiB  |