diff --git a/docz/docs/02-getting-started/02-examples/06-loader.md b/docz/docs/02-getting-started/02-examples/06-loader.md index 6da92f2..6a0ebe6 100644 --- a/docz/docs/02-getting-started/02-examples/06-loader.md +++ b/docz/docs/02-getting-started/02-examples/06-loader.md @@ -39,6 +39,7 @@ This demo was tested in the following configurations: | NVIDIA RTX PRO 6000 (96 GB VRAM) + Ryzen Z2 Go (32 GB RAM) | `linux-x64` | Ollama | 2025-11-15 | | NVIDIA RTX 5090 (32 GB VRAM) + Ryzen AI Z2 Extreme (24 GB RAM) | `win11-x64` | `llama.cpp` | 2026-05-05 | | NVIDIA RTX 5090 (32 GB VRAM) + Ryzen Z2 Go (32 GB RAM) | `linux-x64` | Ollama | 2025-11-15 | +| NVIDIA RTX 5060 Ti (16 GB VRAM) + Ryzen Z2 Extreme (32 GB RAM) | `win11-x64` | `llama.cpp` | 2026-06-05 | | AMD AI PRO R9700 (32 GB VRAM) + Ryzen Z1 Extreme (16 GB RAM) | `win11-x64` | Ollama | 2026-01-17 | | AMD AI PRO R9700 (32 GB VRAM) + Ryzen Z1 Extreme (16 GB RAM) | `linux-x64` | Ollama | 2026-01-17 | | AMD RX 9070 XT (16 GB VRAM) + Ryzen Z2 Go (32 GB RAM) | `win11-x64` | Ollama | 2026-01-17 | diff --git a/docz/docs/03-demos/04-grid/10-tabulator.md b/docz/docs/03-demos/04-grid/03-tabulator.md similarity index 100% rename from docz/docs/03-demos/04-grid/10-tabulator.md rename to docz/docs/03-demos/04-grid/03-tabulator.md diff --git a/docz/docs/03-demos/04-grid/05-handsontable.md b/docz/docs/03-demos/04-grid/05-handsontable.md new file mode 100644 index 0000000..8c8e01e --- /dev/null +++ b/docz/docs/03-demos/04-grid/05-handsontable.md @@ -0,0 +1,228 @@ +--- +title: Handsontable +pagination_prev: demos/frontend/index +pagination_next: demos/net/index +--- + + + + + + +import current from '/version.js'; +import CodeBlock from '@theme/CodeBlock'; + +:::danger pass + +**Handsontable has relicensed away from open source!** + +The original MIT license still applies to version `6.2.2`. + +After adding the new `licenseKey` requirement, basic integrations still work +with version `17.1.0`. + +::: + +[Handsontable](https://handsontable.com/) is a robust JavaScript data grid. + +The following live integrations use the standalone build: + +- [Version `6.2.2` (MIT Licensed)](pathname:///handsontable/) +- [Version `17.1.0` (Proprietary)](pathname:///handsontable/non-oss.html) + +:::note Tested Deployments + +This demo was tested in the following environments: + +| Browser | Date | +|:-------------|:-----------| +| Chromium 148 | 2026-06-09 | +| Safari 18.2 | 2026-06-09 | + +::: + +:::tip pass + +This demo barely scratches the surface. The underlying grid component includes +many additional features that work with [SheetJS Pro](https://sheetjs.com/pro). + +::: + +## Integration Details + +[The "Frameworks" section](/docs/getting-started/installation/frameworks) covers +installation with Yarn and other package managers. + +Using the `npm` tool, the following command installs SheetJS and Handsontable: + +{`\ +npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz handsontable@6.2.2`} + + +Methods and components in both libraries can be loaded in pages using `import`: + +```js +import { read, utils, writeFile } from 'xlsx'; +import Handsontable from 'handsontable'; +import 'handsontable/dist/handsontable.css' +``` + +:::info pass + +Official framework wrapper packages (e.g. `@handsontable/react-wrapper`) should +be used in greenfield projects, as they encapsulate best practices. + +Due to framework volatility, the pre-baked integrations may not work with older +versions of ReactJS. + +::: + +### Internal State + +Handsontable uses [arrays of arrays](/docs/api/utilities/array#array-of-arrays) +under the hood by default. This is the most flexible approach for processing +arbitrary data. + +If a schema is passed when the table is constructed, Handsontable will use +[arrays of objects](/docs/api/utilities/array#arrays-of-objects) instead[^1]. + +### Reading Data + +The SheetJS [`read`](/docs/api/parse-options) function processes file data and +returns a [workbook object](/docs/csf/book). After selecting a worksheet, the +[`sheet_to_json` method](/docs/api/utilities/array#array-output) can return an +array of arrays or array of objects. + +The result of `sheet_to_json` can be passed directly to the `loadData` method[^2] +of a Handsontable instance. + +The following snippet fetches a file, extracts data from the first worksheet, +and passes the data to the grid: + +```js +import { read, utils } from 'xlsx'; +import Handsontable from 'handsontable'; + +/* `hot` is assumed to be the Handsontable instance */ +// const hot = new Handsontable(/* ... */); + +async function fetch_and_view_first_sheet() { + /* fetch and parse https://docs.sheetjs.com/pres.numbers */ + const file = await (await fetch("https://docs.sheetjs.com/pres.numbers")).arrayBuffer(); + const wb = read(file); + + // highlight-start + /* Generate an array of arrays from the first worksheet */ + const first_sheet = wb.Sheets[wb.SheetNames[0]]; + const aoa = utils.sheet_to_json(first_sheet, { header: 1 }); + + /* load data into Handsontable instance */ + hot.loadData(aoa); + // highlight-end +} +``` + +### Writing Data + +The `getData` method[^3] of a Handsontable instance returns the current data. By +default, the method returns an array of arrays. + +The SheetJS [`aoa_to_sheet`](/docs/api/utilities/array#array-of-arrays-input) +method generates a worksheet object from the data. After creating a new workbook +with [`book_new`](/docs/api/utilities/wb), [`writeFile`](/docs/api/write-options) + +The following snippet pulls data from the grid and exports to `SheetJSHOT.xlsx`: + +```js +import { utils, writeFile } from 'xlsx'; +import Handsontable from 'handsontable'; + +function export_data_to_xlsx(hot) { + /* pull data from the Handsontable instance */ + const aoa = hot.getData(); + + /* generate a SheetJS worksheet object */ + const ws = utils.aoa_to_sheet(aoa); + + /* generate a single-sheet workbook and export to SheetJSHOT.xlsx */ + const wb = utils.book_new(ws, "Exported Data"); + writeFile(wb, "SheetJSHOT.xlsx"); +} +``` + +:::note pass + +For framework-native state management, the recommended approach is to listen for +grid events and explicitly update a separate copy of the data[^4]. + +::: + +## Demo + +This sample ReactJS-powered site uses SheetJS and Handsontable to display data +from a [sample NUMBERS spreadsheet](pathname:///pres.numbers) and export data +to a new file. + +1) Create a new project from the ViteJS `react-ts` template: + +```bash +npm create vite@latest -- sheetjs-hot --template react-ts --no-interactive +cd sheetjs-hot +npm i +``` + +2) Install SheetJS and Handsontable libraries: + +{`\ +npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz handsontable@6.2.2`} + + +3) Start the dev server: + +```bash +npm run dev +``` + +The terminal window will display a URL (typically `http://localhost:5173`). +Open the URL with a web browser and confirm that a page loads. + +4) Download [`App.tsx`](pathname:///handsontable/App.tsx) and replace `src/App.tsx`: + +```bash +curl -L -o src/App.tsx https://docs.sheetjs.com/handsontable/App.tsx +``` + +#### Testing + +5) Refresh the browser window. A grid and two buttons should be visible: + +![handsontable initial view](pathname:///handsontable/pre.png) + +6) Press the "Fetch File" button. The grid will refresh with Presidential data: + +![handsontable after fetch](pathname:///handsontable/intra.png) + +7) Make some changes to the grid data. + +:::note pass + +Some statisticians believe President Grover Cleveland should be counted once. +That would imply President Clinton should be index 41 and the indices of the +other presidents should be decremented. + +::: + +Double-click on each cell in the Index column and decrement each value. The new +values should be 41, 42, 43, 44, and 45, as shown in the screenshot below: + +![handsontable after edits](pathname:///handsontable/post.png) + +8) Click on the "Download" button. The browser should attempt to download a new +spreadsheet (`SheetJSHOT.xlsx`). Save the file. + +Open the generated file and verify the contents match the grid. + +[^1]: See ["Array of Objects" in the "Data management"](https://handsontable.com/docs/javascript-data-grid/binding-to-data/#array-of-objects) section of the Handsontable documentation for more details. +[^2]: See [`loadData`](https://handsontable.com/docs/javascript-data-grid/api/core/#loaddata) in the Handsontable API documentation for more details. +[^3]: See [`getData`](https://handsontable.com/docs/javascript-data-grid/api/core/#getdata) in the Handsontable API documentation for more details. +[^4]: See ["Events and hooks" in the "Data management"](https://handsontable.com/docs/javascript-data-grid/events-and-hooks/) section of the Handsontable documentation for more details. \ No newline at end of file diff --git a/docz/docs/03-demos/04-grid/index.md b/docz/docs/03-demos/04-grid/index.md index c5fab55..aa890a0 100644 --- a/docz/docs/03-demos/04-grid/index.md +++ b/docz/docs/03-demos/04-grid/index.md @@ -54,6 +54,12 @@ through a special Export button. It handles the SheetJS operations internally. **[The exposition has been moved to a separate page.](/docs/demos/grid/tabulator)** +#### Handsontable + +[Click here for a live integration demo.](pathname:///handsontable/) + +**[The exposition has been moved to a separate page.](/docs/demos/grid/handsontable)** + #### Angular UI Grid :::danger pass diff --git a/docz/docs/03-demos/23-data/25-mongodb.md b/docz/docs/03-demos/23-data/25-mongodb.md index 2e19ecd..f45734f 100644 --- a/docz/docs/03-demos/23-data/25-mongodb.md +++ b/docz/docs/03-demos/23-data/25-mongodb.md @@ -21,8 +21,8 @@ MongoDB wire protocol. ::: -[FerretDB](https://www.ferretdb.com/) is an Apache 2.0-licensed document database -that implements the MongoDB wire protocol using PostgreSQL or SQLite as the backend. +[FerretDB](https://docs.ferretdb.io) is an Apache 2.0-licensed document database +that implements the MongoDB wire protocol using a PostgreSQL or SQLite backend. [SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing data from spreadsheets. diff --git a/docz/docs/03-demos/32-extensions/03-excelapi.md b/docz/docs/03-demos/32-extensions/03-excelapi.md index ec358aa..ea54941 100644 --- a/docz/docs/03-demos/32-extensions/03-excelapi.md +++ b/docz/docs/03-demos/32-extensions/03-excelapi.md @@ -41,7 +41,7 @@ This demo was tested in the following deployments: |:---------------|:-------------|:-----------|:-----------| | macOS 15.3 | `darwin-x64` | 16.95.4 | 2025-04-17 | | macOS 14.5 | `darwin-arm` | 16.106.3 | 2026-05-05 | -| Windows 11 | `win11-x64` | 365 (2506) | 2025-06-17 | +| Windows 11 | `win11-x64` | 365 (2604) | 2026-06-05 | | Windows 11 | `win11-arm` | 365 (2503) | 2025-04-24 | ::: diff --git a/docz/static/handsontable/App.tsx b/docz/static/handsontable/App.tsx new file mode 100644 index 0000000..6bb0829 --- /dev/null +++ b/docz/static/handsontable/App.tsx @@ -0,0 +1,45 @@ +import { useEffect, useRef, useState } from 'react'; +import { read, utils, writeFile } from 'xlsx'; +import Handsontable from 'handsontable'; +import 'handsontable/dist/handsontable.css' +import './App.css'; + +function App() { + const ref = useRef(null); + const [hot, setHot] = useState(); + + useEffect(() => { + if(!ref || !ref.current) return; + const _hot = new Handsontable(ref.current, { + data: [ ["Sheet", "JS", ""], ["Hands", "on", "Table"] ], + rowHeaders: true, colHeaders: true, height: 600, width: 800 + }); + setHot(_hot); + return () => { if(hot && !hot.isDestroyed) hot.destroy() }; + }, []); + + const fetchFile = async() => { + const ab = await (await fetch("https://docs.sheetjs.com/pres.numbers")).arrayBuffer(); + const wb = read(ab); + const ws = wb.Sheets[wb.SheetNames[0]]; + const aoa = utils.sheet_to_json(ws, { header: 1 }); + hot.loadData(aoa); + }; + + const download = async() => { + if(!hot) return; + const ws = utils.aoa_to_sheet(hot.getData()); + const wb = utils.book_new(ws); + writeFile(wb, "SheetJSHOT.xlsx"); + }; + + return ( + <> + + +
+ + ) +} + +export default App diff --git a/docz/static/handsontable/index.html b/docz/static/handsontable/index.html new file mode 100644 index 0000000..e48f5d7 --- /dev/null +++ b/docz/static/handsontable/index.html @@ -0,0 +1,164 @@ + + + + + + + +SheetJS + Handsontable Live Demo + + + + + +
+SheetJS + Handsontable Demo
+
+
Drop a spreadsheet file here to see sheet data
+ ... or click here to select a file + +
+

+
+
+ + + + + + + diff --git a/docz/static/handsontable/intra.png b/docz/static/handsontable/intra.png new file mode 100644 index 0000000..640b186 Binary files /dev/null and b/docz/static/handsontable/intra.png differ diff --git a/docz/static/handsontable/non-oss.html b/docz/static/handsontable/non-oss.html new file mode 100644 index 0000000..4cd5ef6 --- /dev/null +++ b/docz/static/handsontable/non-oss.html @@ -0,0 +1,165 @@ + + + + + + + +SheetJS + Handsontable Live Demo + + + + + +
+SheetJS + Handsontable Demo
+
+
Drop a spreadsheet file here to see sheet data
+ ... or click here to select a file + +
+

+
+
+ + + + + + + diff --git a/docz/static/handsontable/post.png b/docz/static/handsontable/post.png new file mode 100644 index 0000000..d9af2a2 Binary files /dev/null and b/docz/static/handsontable/post.png differ diff --git a/docz/static/handsontable/pre.png b/docz/static/handsontable/pre.png new file mode 100644 index 0000000..481916d Binary files /dev/null and b/docz/static/handsontable/pre.png differ diff --git a/docz/static/mathematica/PasteEscapeString.png b/docz/static/mathematica/PasteEscapeString.png new file mode 100644 index 0000000..da2a9f2 Binary files /dev/null and b/docz/static/mathematica/PasteEscapeString.png differ