diff --git a/docz/docs/03-demos/02-frontend/01-kaioken.md b/docz/docs/03-demos/02-frontend/01-kaioken.md new file mode 100644 index 0000000..9b5d8d6 --- /dev/null +++ b/docz/docs/03-demos/02-frontend/01-kaioken.md @@ -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: + +
SpreadsheetState
+ +![`pres.xlsx` data](pathname:///pres.png) + + + +```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 } +] +``` + +
+ +The Kaioken `useState`[^1] hook can configure the state: + + + + +```ts +import { useState } from 'kaioken'; + +/* the kaioponent state is an array of objects */ +const [pres, setPres] = useState([]); +``` + + + + +```ts +import { useState } from 'kaioken'; + +/* the kaioponent state is an array of objects */ +const [pres, setPres] = useState([]); +``` + +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([]); +``` + +:::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. + +::: + + + + +#### 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 +``` + + + + +```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 +})(); }, []); +``` + + + + +```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(ws); // generate objects + + /* update state */ + setPres(data); // update state + // highlight-end +})(); }, []); +``` + + + + +#### 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" + + {/* The `thead` section includes the table header row */} + + {/* The `tbody` section includes the data rows */} + + {/* generate row (TR) for each president */} +// highlight-start + {pres.map(row => ( + + {/* Generate cell (TD) for name / index */} + + + + ))} +// highlight-end + +
NameIndex
{row.Name}{row.Index}
+``` + +#### 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([]); + + /* 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(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 ( + { /* generate row for each president */ + pres.map(pres => ( + + + )) + } +
NameIndex
{pres.Name}{pres.Index}
+ +
); +} +``` + +
How to run the example (click to hide) + + + + +:::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: + +{`\ +pnpm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz +pnpm run dev`} + + +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. + + + + +When the page loads, the app will fetch 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. + +
+ +### 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(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 ( <> + + // highlight-next-line +
+ ); +} +``` + +
How to run the example (click to hide) + + + + +:::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: + +{`\ +pnpm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz +pnpm run dev`} + + +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. + + + + +When the page loads, the app will fetch 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. + +
+ +[^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. diff --git a/docz/docs/03-demos/02-frontend/01-react.md b/docz/docs/03-demos/02-frontend/02-react.md similarity index 99% rename from docz/docs/03-demos/02-frontend/01-react.md rename to docz/docs/03-demos/02-frontend/02-react.md index cd1212d..6212982 100644 --- a/docz/docs/03-demos/02-frontend/01-react.md +++ b/docz/docs/03-demos/02-frontend/02-react.md @@ -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'; diff --git a/docz/docs/03-demos/02-frontend/02-vue.md b/docz/docs/03-demos/02-frontend/04-vue.md similarity index 99% rename from docz/docs/03-demos/02-frontend/02-vue.md rename to docz/docs/03-demos/02-frontend/04-vue.md index 5b7f76f..20ad5d9 100644 --- a/docz/docs/03-demos/02-frontend/02-vue.md +++ b/docz/docs/03-demos/02-frontend/04-vue.md @@ -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'; diff --git a/docz/docs/03-demos/02-frontend/04-svelte.md b/docz/docs/03-demos/02-frontend/05-svelte.md similarity index 99% rename from docz/docs/03-demos/02-frontend/04-svelte.md rename to docz/docs/03-demos/02-frontend/05-svelte.md index c4e00fc..f34437f 100644 --- a/docz/docs/03-demos/02-frontend/04-svelte.md +++ b/docz/docs/03-demos/02-frontend/05-svelte.md @@ -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'; diff --git a/docz/docs/03-demos/03-net/08-headless.md b/docz/docs/03-demos/03-net/08-headless.md index 054f03e..69f7d1b 100644 --- a/docz/docs/03-demos/03-net/08-headless.md +++ b/docz/docs/03-demos/03-net/08-headless.md @@ -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 | ::: diff --git a/docz/docs/03-demos/19-desktop/03-wails.md b/docz/docs/03-demos/19-desktop/03-wails.md index 0066636..d63e629 100644 --- a/docz/docs/03-demos/19-desktop/03-wails.md +++ b/docz/docs/03-demos/19-desktop/03-wails.md @@ -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 | diff --git a/docz/docs/03-demos/19-desktop/04-tauri.md b/docz/docs/03-demos/19-desktop/04-tauri.md index 710f9dd..bd7f845 100644 --- a/docz/docs/03-demos/19-desktop/04-tauri.md +++ b/docz/docs/03-demos/19-desktop/04-tauri.md @@ -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 + + + +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() => { }; ``` + + + +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([]); + + 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 ( <> + + {data.map((row) => + {row.map((cell) => )} + )}
{cell}
+ ); +} +``` + +
+
+ ### 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 + + + +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() => { } ``` + + + +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(["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 ( ); +} + +``` + + + + ## 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: + + + ```bash npm create tauri-app@latest -- -m npm -t vue-ts SheetJSTauri -y ``` + + + +:::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 +``` + + + + 2) Enter the directory and install dependencies: {`\ @@ -322,6 +428,20 @@ npm i --save @tauri-apps/api npm i --save-dev @tauri-apps/cli`} + + + + + + +```bash +npm add kaioken --save +npm add vite-plugin-kaioken -D --save +``` + + + + 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": "", ``` + + 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 ``` + + + +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" + + + + + + + SheetJS x Tauri + + + + +
+ + +``` + +- 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 +``` + +
+
+ 5) Build the app with ```bash diff --git a/docz/docs/03-demos/19-desktop/05-neutralino.md b/docz/docs/03-demos/19-desktop/05-neutralino.md index d04cb1d..cde5e5f 100644 --- a/docz/docs/03-demos/19-desktop/05-neutralino.md +++ b/docz/docs/03-demos/19-desktop/05-neutralino.md @@ -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 | diff --git a/docz/docs/03-demos/19-desktop/06-reactnative.md b/docz/docs/03-demos/19-desktop/06-reactnative.md index 047eb9b..bae9a78 100644 --- a/docz/docs/03-demos/19-desktop/06-reactnative.md +++ b/docz/docs/03-demos/19-desktop/06-reactnative.md @@ -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)" diff --git a/docz/docs/03-demos/20-cli/23-deno.md b/docz/docs/03-demos/20-cli/23-deno.md index 179edca..e3a82b9 100644 --- a/docz/docs/03-demos/20-cli/23-deno.md +++ b/docz/docs/03-demos/20-cli/23-deno.md @@ -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 : ```bash -curl -LO https://sheetjs.com/pres.numbers +curl -o pres.numbers https://sheetjs.com/pres.numbers ``` 2) Test the script with `deno run`: diff --git a/docz/docs/03-demos/20-cli/index.md b/docz/docs/03-demos/20-cli/index.md index ae7a3f1..470ade6 100644 --- a/docz/docs/03-demos/20-cli/index.md +++ b/docz/docs/03-demos/20-cli/index.md @@ -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 : ```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 {`\ -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`} 3) Build the V8 snapshot: @@ -414,7 +440,7 @@ cargo build --release --bin sheet2csv 5) Download the test file : ```bash -curl -LO https://sheetjs.com/pres.numbers +curl -o pres.numbers https://sheetjs.com/pres.numbers ``` 6) Test the application: diff --git a/docz/docs/03-demos/42-engines/01-duktape.md b/docz/docs/03-demos/42-engines/01-duktape.md index 158b7fc..af22292 100644 --- a/docz/docs/03-demos/42-engines/01-duktape.md +++ b/docz/docs/03-demos/42-engines/01-duktape.md @@ -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 | diff --git a/docz/docs/03-demos/42-engines/02-v8.md b/docz/docs/03-demos/42-engines/02-v8.md index 52647ab..5b5bfd7 100644 --- a/docz/docs/03-demos/42-engines/02-v8.md +++ b/docz/docs/03-demos/42-engines/02-v8.md @@ -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 | diff --git a/docz/docs/03-demos/42-engines/06-goja.md b/docz/docs/03-demos/42-engines/06-goja.md index ad6628d..f5d3fc3 100644 --- a/docz/docs/03-demos/42-engines/06-goja.md +++ b/docz/docs/03-demos/42-engines/06-goja.md @@ -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 | diff --git a/docz/docs/03-demos/42-engines/09-hermes.md b/docz/docs/03-demos/42-engines/09-hermes.md index c972582..668097c 100644 --- a/docz/docs/03-demos/42-engines/09-hermes.md +++ b/docz/docs/03-demos/42-engines/09-hermes.md @@ -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.
Installation Notes (click to show) -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: {`\ -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`} 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 \ No newline at end of file +[^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. diff --git a/docz/static/reactnative/rnm.png b/docz/static/reactnative/rnm.png index b5a357e..a8a0bfb 100644 Binary files a/docz/static/reactnative/rnm.png and b/docz/static/reactnative/rnm.png differ diff --git a/docz/static/reactnative/rnw.png b/docz/static/reactnative/rnw.png index 85951d3..01a7226 100644 Binary files a/docz/static/reactnative/rnw.png and b/docz/static/reactnative/rnw.png differ diff --git a/docz/static/tauri/App.tsx b/docz/static/tauri/App.tsx new file mode 100644 index 0000000..b462ce3 --- /dev/null +++ b/docz/static/tauri/App.tsx @@ -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([[]]) + const [origin, setOrigin] = useState(""); + + const update = (wb: WorkBook) => { + const ws = wb.Sheets[wb.SheetNames[0]]; + const d = utils.sheet_to_json(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("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 (
+

+ SheetJS + SheetJS × Tauri {version}

+ +
or +
+

Data from { origin }

+ + {data.map((row) => + {row.map((cell) => )} + )} +
{cell}
+
+ ); +} \ No newline at end of file diff --git a/docz/static/tauri/win10.png b/docz/static/tauri/win10.png index 4d411f0..278552a 100644 Binary files a/docz/static/tauri/win10.png and b/docz/static/tauri/win10.png differ diff --git a/docz/static/wails/win10.png b/docz/static/wails/win10.png index 645cd41..f8d8632 100644 Binary files a/docz/static/wails/win10.png and b/docz/static/wails/win10.png differ