diff --git a/docz/docs/03-demos/01-frontend/01-react.md b/docz/docs/03-demos/01-frontend/01-react.md index b8a93cc..88a6a48 100644 --- a/docz/docs/03-demos/01-frontend/01-react.md +++ b/docz/docs/03-demos/01-frontend/01-react.md @@ -78,7 +78,7 @@ The React `useState` hook can configure the state: ```ts import { useState } from 'react'; -/* the component state is an array of presidents */ +/* the component state is an array of objects */ const [pres, setPres] = useState([]); ``` @@ -88,6 +88,15 @@ const [pres, setPres] = useState([]); ```ts import { useState } from 'react'; +/* the component 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 'react'; + interface President { Name: string; Index: number; @@ -97,11 +106,13 @@ interface President { const [pres, setPres] = useState([]); ``` -:::note +:::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. + ::: diff --git a/docz/docs/03-demos/01-frontend/09-legacy.md b/docz/docs/03-demos/01-frontend/09-legacy.md index 3ea846b..9d6ba03 100644 --- a/docz/docs/03-demos/01-frontend/09-legacy.md +++ b/docz/docs/03-demos/01-frontend/09-legacy.md @@ -212,7 +212,7 @@ require(["dojo/request/xhr", "xlsx"], function(xhr, _XLSX) { The ["Dojo" section in "Bundlers"](/docs/demos/bundler#dojo) includes a complete example -mirroring the [official example](/docs/getting-started/example) +mirroring the [official export example](/docs/getting-started/example)
Details (click to show) diff --git a/docz/docs/03-demos/06-desktop/04-tauri.md b/docz/docs/03-demos/06-desktop/04-tauri.md index c372f47..93ea181 100644 --- a/docz/docs/03-demos/06-desktop/04-tauri.md +++ b/docz/docs/03-demos/06-desktop/04-tauri.md @@ -257,9 +257,10 @@ This demo was tested in the following environments: | OS and Version | Arch | Tauri | Date | |:---------------|:-----|:---------|:-----------| +| macOS 13.4.1 | ARM | `v1.4.0` | 2023-06-29 | | macOS 13.4.0 | x64 | `v1.4.0` | 2023-06-25 | | Windows 10 | x64 | `v1.2.3` | 2023-03-18 | -| Linux (HoloOS) | x64 | `v1.2.3` | 2023-03-18 | +| Linux (HoloOS) | x64 | `v1.2.3` | | ::: @@ -294,6 +295,13 @@ If required dependencies are installed, the output will show a checkmark next to - npm: 9.5.1 ``` +:::caution pass + +When the demo was last tested on ARM64 macOS, the output mentioned `X64`. The +build step will correctly detect the platform architecture. + +::: +
1) Create a new Tauri app: diff --git a/docz/docs/03-demos/06-desktop/05-neutralino.md b/docz/docs/03-demos/06-desktop/05-neutralino.md index c3d9da8..eb3d17f 100644 --- a/docz/docs/03-demos/06-desktop/05-neutralino.md +++ b/docz/docs/03-demos/06-desktop/05-neutralino.md @@ -1,5 +1,7 @@ --- title: NeutralinoJS +sidebar_label: NeutralinoJS +description: Build data-intensive desktop apps using NeutralinoJS. Seamlessly integrate spreadsheets into your app using SheetJS. Quickly modernize Excel-powered business processes. pagination_prev: demos/mobile/index pagination_next: demos/data/index sidebar_position: 5 @@ -7,15 +9,25 @@ sidebar_custom_props: summary: Webview + Lightweight Extensions --- +# Data Munging in NeutralinoJS + import current from '/version.js'; import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; import CodeBlock from '@theme/CodeBlock'; -The [Standalone build](/docs/getting-started/installation/standalone) can be added -to the entry `index.html` +[NeutralinoJS](https://neutralino.js.org/) is a modern desktop app framework. +NeutralinoJS apps pair platform-native browser tools with a static web server. -The "Complete Example" creates an app that looks like the screenshot: +[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing +data from spreadsheets. + +This demo uses NeutralinoJS and SheetJS to pull data from a spreadsheet and +display the data in the app. We'll explore how to load SheetJS in a NeutralinoJS +app and use native features to read and write files. + +The ["Complete Example"](#complete-example) section covers a complete desktop +app to read and write workbooks. The app will look like the screenshots below: @@ -37,15 +49,16 @@ The "Complete Example" creates an app that looks like the screenshot: ## Integration Details -:::note +The [SheetJS Standalone build](/docs/getting-started/installation/standalone) +can be added to the entry `index.html` -NeutralinoJS currently does not provide the equivalent of NodeJS `fs` module. -The raw `Neutralino.filesystem` and `Neutralino.os` methods are used. +For code running in the window, native methods must be explicitly enabled in the +NeutralinoJS `neutralino.conf.json` settings file[^1]. -::: +- `os.*` enables the open and save dialog methods. +- `filesystem.*` enables reading and writing file data. -The `os` and `filesystem` modules must be enabled in `neutralino.conf.json`. -The starter already enables `os` so typically one line must be added: +The starter app enables `os.*` so typically one line must be added: ```json title="neutralino.config.json" "nativeAllowList": [ @@ -57,28 +70,33 @@ The starter already enables `os` so typically one line must be added: ], ``` -:::caution - -At the time of writing, `filters` did not work as expected on MacOS. They have -been omitted in the example and commented in the code snippets - -::: - ### Reading Files -There are two steps to reading files: obtaining a path and reading binary data: +There are three steps to reading files: + +1) Show an open file dialog with `Neutralino.os.showOpenDialog`[^2]. This method + resolves to the selected path. + +2) Read raw data from the file with `Neutralino.filesystem.readBinaryFile`[^3]. + This method resolves to a standard `ArrayBuffer`. + +3) Parse the data with the SheetJS `read` method[^4]. This method returns a + SheetJS workbook object. + +The following code example defines a single function `openFile` that performs +all three steps and returns a SheetJS workbook object: ```js const filters = [ - {name: "Excel Binary Workbook", extensions: ["xlsb"]}, - {name: "Excel Workbook", extensions: ["xlsx"]}, + {name: "Excel Binary Workbook", extensions: ["xls", "xlsb"]}, + {name: "Excel Workbook", extensions: ["xls", "xlsx"]}, ] async function openFile() { /* show open file dialog */ const [filename] = await Neutralino.os.showOpenDialog( 'Open a spreadsheet', - { /* filters, */ multiSelections: false } + { filters, multiSelections: false } ); /* read data into an ArrayBuffer */ @@ -90,23 +108,56 @@ async function openFile() { } ``` -This method can be called from a button click or other event. +At this point, standard SheetJS utility functions[^5] can extract data from the +workbook object. The demo includes a button that calls `sheet_to_html`[^6] to +generate an HTML TABLE and add to the DOM: + +```js +const open_button_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 html = XLSX.utils.sheet_to_html(ws); + // highlight-end + + /* display table */ + document.getElementById('info').innerHTML = html; +}; +``` ### Writing Files -There are two steps to writing files: obtaining a path and writing binary data: +There are three steps to reading files: + +1) Show a file dialog with `Neutralino.os.showSaveDialog`[^7]. This method + resolves to the selected path. + +2) Write the data with the SheetJS `write` method[^8]. The output book type can + be inferred from the selected file path. Using the `buffer` output type[^9], + the method returns a `Uint8Array` object that plays nice with NeutralinoJS. + +2) Write to file with `Neutralino.filesystem.writeBinaryFile`[^10]. + +The following code example defines a single function `saveFile` that performs +all three steps starting from a SheetJS workbook object: ```js const filters = [ - {name: "Excel Binary Workbook", extensions: ["xlsb"]}, - {name: "Excel Workbook", extensions: ["xlsx"]}, + {name: "Excel Binary Workbook", extensions: ["xls", "xlsb"]}, + {name: "Excel Workbook", extensions: ["xls", "xlsx"]}, ] async function saveFile(wb) { /* show save file dialog */ const filename = await Neutralino.os.showSaveDialog( 'Save to file', - { /* filters */ } + { filters } ); /* Generate workbook */ @@ -118,11 +169,35 @@ async function saveFile(wb) { } ``` +The demo includes a button that calls `table_to_book`[^11] to generate a +workbook object from the HTML table: + +```js +const save_button_callback = async() => { + /* get the table */ + const tbl = document.getElementById('info').querySelector('table'); + + /* generate workbook from the table */ + // highlight-start + const wb = XLSX.utils.table_to_book(tbl); + // highlight-end + + await saveFile(wb); +} +``` + ## Complete Example -:::note +:::note pass -This demo was tested on 2023 March 19 with "binaries" `4.7.0` and "client" `3.6.0` +This demo was tested in the following environments: + +| OS and Version | Arch | Server | Client | Date | +|:---------------|:-----|:----------|:---------|:-----------| +| macOS 13.4.1 | x64 | `v4.10.0` | `v3.8.2` | 2023-06-28 | +| macOS 13.4.1 | ARM | `v4.10.0` | `v3.8.2` | 2023-06-28 | +| Windows 10 | x64 | `v4.7.0` | `v3.6.0` | 2023-03-19 | +| Linux (HoloOS) | x64 | `v4.7.0` | `v3.6.0` | | ::: @@ -137,13 +212,13 @@ cd sheetjs-neu ``` 2) Download [Standalone build](/docs/getting-started/installation/standalone) -and place in `resources/js/main.js`: +and place in the `resources/js/` folder: {`\ curl -L -o resources/js/xlsx.full.min.js https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js`} -3) Add the highlighted line to `neutralino.conf.json` in `nativeAllowList`: +3) Add the highlighted line to `neutralino.config.json` in `nativeAllowList`: ```json title="neutralino.config.json" "nativeAllowList": [ @@ -158,9 +233,16 @@ curl -L -o resources/js/xlsx.full.min.js https://cdn.sheetjs.com/xlsx-${current} 4) Set up skeleton app and print version info: -- Edit `resources/index.html` and replace the `` with the code below: +- Replace the contents of `resources/index.html` with the following code: ```html title="resources/index.html" + + + + + SheetJS + NeutralinoJS + +

SheetJS × NeutralinoJS

@@ -173,6 +255,7 @@ curl -L -o resources/js/xlsx.full.min.js https://cdn.sheetjs.com/xlsx-${current} + ``` - Append the following code to `resources/styles.css` to center the table: @@ -190,6 +273,8 @@ table { - Print the version number in the `showInfo` method of `resources/js/main.js`: ```js title="resources/js/main.js" +function showInfo() { + document.getElementById('info').innerHTML = ` ${NL_APPID} is running on port ${NL_PORT} inside ${NL_OS}

server: v${NL_VERSION} . client: v${NL_CVERSION} @@ -198,6 +283,7 @@ table { SheetJS version ${XLSX.version} // highlight-end `; +} ``` 5) Run the app: @@ -206,11 +292,11 @@ table { npx @neutralinojs/neu run ``` -You should see `SheetJS Version ` followed by the library version number. +

The app should print SheetJS Version {current}

6) Add the following code to the bottom of `resources/js/main.js`: -```js +```js title="resources/js/main.js" (async() => { const ab = await (await fetch("https://sheetjs.com/pres.numbers")).arrayBuffer(); const wb = XLSX.read(ab); @@ -219,13 +305,13 @@ You should see `SheetJS Version ` followed by the library version number. })(); ``` -Save the source file, close the app and re-run the command from step 5. +Save the source file, close the app and re-run with `npx @neutralinojs/neu run` When the app loads, a table should show in the main screen. 7) Add `importFile` and `exportFile` to the bottom of `resources/js/main.js`: -```js +```js title="resources/js/main.js" async function importData() { /* show open dialog */ const [filename] = await Neutralino.os.showOpenDialog('Open a spreadsheet'); @@ -240,7 +326,7 @@ async function importData() { } async function exportData() { - /* show save dialog */ + /* show save dialog */ const filename = await Neutralino.os.showSaveDialog('Save to file'); /* make workbook */ @@ -254,15 +340,36 @@ async function exportData() { } ``` -Save the source file, close the app and re-run the command from step 5. +Save the source file, close the app and re-run with `npx @neutralinojs/neu run` When the app loads, click the "Import File" button and select a spreadsheet to -see the contents. Click "Export File" and enter `SheetJSNeu.xlsx` to write. +see the contents. + +Click "Export File" and enter `SheetJSNeu.xlsx` to write a new file. + +:::caution pass + +When saving the file, the actual file extension must be included. Attempting to +save as `SheetJSNeu` will not automatically add the `.xlsx` extension! + +::: 8) Build production apps: ```bash -npx @neutralinojs/neu run +npx @neutralinojs/neu build ``` Platform-specific programs will be created in the `dist` folder. + +[^1]: See [`nativeAllowList`](https://neutralino.js.org/docs/configuration/neutralino.config.json#nativeallowlist-string) in the NeutralinoJS documentation +[^2]: See [`os.showOpenDialog`](https://neutralino.js.org/docs/api/os#osshowopendialogtitle-options) in the NeutralinoJS documentation +[^3]: See [`filesystem.readBinaryFile`](https://neutralino.js.org/docs/api/filesystem/#filesystemreadbinaryfilefilename) in the NeutralinoJS documentation +[^4]: See [`read` in "Reading Files"](/docs/api/parse-options) +[^5]: See ["Utility Functions"](/docs/api/utilities/) +[^6]: See ["HTML Table Output" in "Utility Functions"](/docs/api/utilities/html#html-table-output) +[^7]: See [`os.showSaveDialog`](https://neutralino.js.org/docs/api/os#osshowsavedialogtitle-options) in the NeutralinoJS documentation +[^8]: See [`write` in "Writing Files"](/docs/api/write-options) +[^9]: See ["Supported Output Formats"](/docs/api/write-options#supported-output-formats) +[^10]: See [`filesystem.writeBinaryFile`](https://neutralino.js.org/docs/api/filesystem/#filesystemwritebinaryfilefilename-data) in the NeutralinoJS documentation +[^11]: See ["HTML Table Input" in "Utility Functions"](/docs/api/utilities/html#html-table-input) diff --git a/docz/docs/03-demos/07-data/29-pouchdb.md b/docz/docs/03-demos/07-data/29-pouchdb.md index aac5be3..1706b15 100644 --- a/docz/docs/03-demos/07-data/29-pouchdb.md +++ b/docz/docs/03-demos/07-data/29-pouchdb.md @@ -16,7 +16,7 @@ PouchDB is a pure JS database with built-in synchronization features. `Database#allDocs` is the standard approach for bulk data export. The generated row objects have additional `_id` and `_rev` keys that should be removed. -Nested objects must be flattened. The ["Tutorial"](/docs/getting-started/example) +Nested objects must be flattened. The ["Export Tutorial"](/docs/getting-started/example) includes an example of constructing a simple array. ```js diff --git a/docz/docs/06-solutions/01-input.md b/docz/docs/06-solutions/01-input.md index dd08dc5..ff67132 100644 --- a/docz/docs/06-solutions/01-input.md +++ b/docz/docs/06-solutions/01-input.md @@ -735,8 +735,8 @@ the function and the optional `opts` argument in more detail. #### Examples -["Complete Example"](/docs/getting-started/example) contains a detailed example -"Get Data from a JSON Endpoint and Generate a Workbook" +["Export Tutorial"](/docs/getting-started/example) contains a detailed +example of fetching data from a JSON Endpoint and generating a workbook. [`x-spreadsheet`](/docs/demos/grid/xs) is an interactive data grid for previewing and modifying structured data in the web browser. diff --git a/docz/docs/07-csf/07-features/03-dates.md b/docz/docs/07-csf/07-features/03-dates.md index 9ba8abd..232c1e2 100644 --- a/docz/docs/07-csf/07-features/03-dates.md +++ b/docz/docs/07-csf/07-features/03-dates.md @@ -60,7 +60,7 @@ of date or time. Instead, dates and times are stored as offsets from an epoch. The magic behind date interpretations is hidden in functions or number formats. SheetJS attempts to create a friendly JS date experience while also exposing -options to use the traditional date codes +options to use the traditional date codes. :::tip pass @@ -104,7 +104,7 @@ function SheetJSNow() { ## How Spreadsheets Understand Time Excel stores dates as numbers. When displaying dates, the format code should -include special date and time tokens like `yyyyy` for long year. `EDATE` and +include special date and time tokens like `yyyy` for long year. `EDATE` and other date functions operate on and return date numbers. For date formats like `yyyy-mm-dd`, the integer part represents the number of diff --git a/docz/static/data/mf221.xlw b/docz/static/data/mf221.xlw new file mode 100644 index 0000000..1d52f8b Binary files /dev/null and b/docz/static/data/mf221.xlw differ diff --git a/docz/static/neu/macos.png b/docz/static/neu/macos.png index 40252f8..827baba 100644 Binary files a/docz/static/neu/macos.png and b/docz/static/neu/macos.png differ
Win10