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 |