diff --git a/docz/docs/03-demos/14-grid.md b/docz/docs/03-demos/14-grid.md index e6d45b9..588d6be 100644 --- a/docz/docs/03-demos/14-grid.md +++ b/docz/docs/03-demos/14-grid.md @@ -27,6 +27,86 @@ suitable for a number of libraries. When more advanced shapes are needed, it is easier to munge the output of an array of arrays. +### x-spreadsheet + +With a familiar UI, [`x-spreadsheet`](https://myliang.github.io/x-spreadsheet/) +is an excellent choice for developers looking for a modern editor. + +[Click here for a live integration demo.](pathname:///xspreadsheet/) + +
Full Exposition (click to show) + +**Obtaining the Library** + +The `x-data-spreadsheet` NodeJS packages include a minified script that can be +directly inserted as a script tag. The unpkg CDN also serves this script: + +```html + + + + +``` + +**Previewing and Editing Data** + +The HTML document needs a container element: + +```html +
+``` + +Grid initialization is a one-liner: + +```js +var grid = x_spreadsheet(document.getElementById("gridctr")); +``` + +`x-spreadsheet` handles the entire edit cycle. No intervention is necessary. + +**SheetJS and x-spreadsheet** + +The integration library can be downloaded from the SheetJS CDN: + +[Development Use](https://cdn.sheetjs.com/xspreadsheet/xlsxspread.js) + +[Production Use](https://cdn.sheetjs.com/xspreadsheet/xlsxspread.min.js) + + +When used in a browser tag, it exposes two functions: `xtos` and `stox`. + +- `stox(worksheet)` returns a data structure suitable for `grid.loadData` +- `xtos(data)` accepts the result of `grid.getData` and generates a workbook + +_Reading Data_ + +The following snippet fetches a spreadsheet and loads the grid: + +```js +(async() => { + const ab = await (await fetch("https://sheetjs.com/pres.numbers")).arrayBuffer(); + grid.loadData(stox(XLSX.read(ab))); +})(); +``` + +The same pattern can be used in file input elements and other data sources. + +_Writing Data_ + +The following snippet exports the grid data to a file: + +```js +/* build workbook from the grid data */ +XLSX.writeFile(xtos(grid.getData()), "SheetJS.xlsx"); +``` + +**Additional Features** + +This demo barely scratches the surface. The underlying grid component includes +many additional features that work with [SheetJS Pro](https://sheetjs.com/pro). + +
+ ### Canvas DataGrid After extensive testing, [`canvas-datagrid`](https://canvas-datagrid.js.org/demo.html) @@ -120,7 +200,6 @@ many additional features including massive data streaming, sorting and styling. - ### Angular UI Grid :::warning @@ -223,7 +302,7 @@ import { WorkSheet, utils } from 'xlsx'; type Row = any[]; -function ws_to_rdg(rows: Row[]): WorkSheet { +function rdg_to_ws(rows: Row[]): WorkSheet { return utils.aoa_to_sheet(rows); } ``` @@ -361,8 +440,135 @@ export default function App() { 4) run `npm start`. When you load the dev page in the browser, it will attempt to fetch and load the data. - - The following screenshot was taken from the demo: ![react-data-grid screenshot](pathname:///react/rdg1.png) + + + +### vue3-table-lite + +:::note + +This demo was tested against `vue3-table-lite 1.2.4`, VueJS `3.2.37`, ViteJS +3.0.7, and `@vitejs/plugin-vue` 3.0.3 on 2022 August 18 + +::: + +[`vue3-table-lite`](https://vue3-lite-table.vercel.app/) is a data grid built +for Vue + +[A complete example is included below.](#vte-demo) + +#### Rows and Columns Bindings + +`vue3-table-lite` presents two bindable attributes: an array of column metadata +(`columns`) and an array of objects representing the displayed data (`rows`). +Typically both are `ref` objects: + + +```html + + + +``` + +These can be mutated through the `value` property in Vue lifecycle methods: + +```ts +import { onMounted } from "vue"; +onMounted(() => { + columns.value = [ { field: "name", label: "Names" }]; + rows.value = [ { name: "SheetJS" }, { name: "VueJS" } ]; +}) +``` + +The most generic data representation is an array of arrays. To sate the grid, +the columns must be objects whose `field` property is the stringified number: + +```js +import { ref } from "vue"; +import { utils } from 'xlsx'; + +/* generate row and column data */ +function ws_to_vte(ws) { + /* create an array of arrays */ + const rows = utils.sheet_to_json(ws, { header: 1 }); + + /* create column array */ + const range = utils.decode_range(ws["!ref"]||"A1"); + const columns = Array.from({ length: range.e.c + 1 }, (_, i) => ({ + field: String(i), // VTE will access row["0"], row["1"], etc + label: utils.encode_col(i), // the column labels will be A, B, etc + })); + + return { rows, columns }; +} + +const rows = ref([]); +const columns = ref([]); + +/* update refs */ +function update_refs(ws) { + const data = ws_to_vte(ws); + rows.value = data.rows; + columns.value = data.columns; +} +``` + +In the other direction, a worksheet can be generated with `aoa_to_sheet`: + +```js +import { utils } from 'xlsx'; + +const rows = ref([]); + +function vte_to_ws(rows) { + return utils.aoa_to_sheet(rows.value); +} +``` + +#### VTE Demo + +
Complete Example (click to show) + +1) Create a new ViteJS App using the Vue + TypeScript template: + +```bash +npm create vite@latest sheetjs-vue -- --template vue-ts +cd sheetjs-vue +``` + +2) Install dependencies: + +```bash +npm i +npm i -S https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz vue3-table-lite +``` + +3) Download [`src/App.vue`](pathname:///vtl/App.vue) and replace the contents: + +```bash +cd src +rm -f App.vue +curl -LO https://docs.sheetjs.com/vtl/App.vue +cd .. +``` + +4) run `npm run dev`. When you load the dev page in the browser, it will try +to fetch and load the data. + +
diff --git a/docz/docs/03-demos/18-engines.md b/docz/docs/03-demos/18-engines.md index 031e0ad..355754c 100644 --- a/docz/docs/03-demos/18-engines.md +++ b/docz/docs/03-demos/18-engines.md @@ -434,7 +434,7 @@ ready, it will read the hardcoded test file and print the contents as CSV. 5) Run the script using the Hermes standalone binary: -``` +```bash hermes xlsx.hermes.js ``` @@ -540,6 +540,93 @@ to `SheetJSwift.xlsx`. That file can be verified by opening in Excel / Numbers. +## JerryScript + +JerryScript is a lightweight JavaScript engine designed for use in low-memory +environments like microcontrollers. As part of the build suite, the project +generates a C library and a standalone CLI tool. + +The simplest way to interact with the engine is to pass Base64 strings. + +:::note + +While applications should link against the official libraries, the standalone tool +is useful for verifying functionality. + +::: + +:::caution + +This demo requires a much larger heap size than is normally used in JerryScript +deployments! In local testing, the following sizes were needed: + +- 8192 (8M) for +- 65536 (64M) for + +This works on a Raspberry Pi. + +::: + +
Complete Example (click to show) + +Due to limitations of the standalone binary, this demo will encode a test file +as a Base64 string and directly add it to an amalgamated script. + +0) Build the library and command line tool with required options: + +```bash +git clone --depth=1 https://github.com/jerryscript-project/jerryscript.git +cd jerryscript +python tools/build.py --error-messages=ON --logging=ON --mem-heap=8192 --cpointer-32bit=ON +``` + +1) Download the standalone script, shim, and test file: + + + +2) Bundle the test file and create `payload.js`: + +```bash +node -e "fs.writeFileSync('payload.js', 'var payload = \"' + fs.readFileSync('pres.xlsx').toString('base64') + '\";')" +``` + +3) Create support scripts: + +- `global.js` creates a `global` variable and defines a fake `console`: + +```js title="global.js" +var global = (function(){ return this; }).call(null); +var console = { log: function(x) { print(x); } }; +``` + +- `jerry.js` will call `XLSX.read` and `XLSX.utils.sheet_to_csv`: + +```js title="jerry.js" +/* sheetjs (C) 2013-present SheetJS -- http://sheetjs.com */ +var wb = XLSX.read(payload, {type:'base64'}); +console.log(XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]])); +``` + +4) Create the amalgamation `xlsx.jerry.js`: + +```bash +cat global.js xlsx.full.min.js payload.js jerry.js > xlsx.jerry.js +``` + +The final script defines `global` before loading the standalone library. Once +ready, it will read the hardcoded test file and print the contents as CSV. + +5) Run the script using the `jerry` standalone binary: + +```bash +build/bin/jerry xlsx.jerry.js; echo $? +``` + +
## QuickJS diff --git a/docz/docs/03-demos/21-react.md b/docz/docs/03-demos/21-react.md index c016e1e..9823f80 100644 --- a/docz/docs/03-demos/21-react.md +++ b/docz/docs/03-demos/21-react.md @@ -1,5 +1,5 @@ --- -sidebar_position: 20 +sidebar_position: 21 title: ReactJS --- @@ -38,7 +38,7 @@ Typically, some users will create a spreadsheet with source data that should be loaded into the site. This sheet will have known columns. For example, our [presidents sheet](https://sheetjs.com/pres.xlsx) has "Name" / "Index" columns: -![`pres.xlsx` data](pathname:///react/pres.png) +![`pres.xlsx` data](pathname:///pres.png) This naturally maps to an array of typed objects, as in the TS example below: diff --git a/docz/docs/03-demos/22-vue.md b/docz/docs/03-demos/22-vue.md new file mode 100644 index 0000000..925c4c8 --- /dev/null +++ b/docz/docs/03-demos/22-vue.md @@ -0,0 +1,184 @@ +--- +sidebar_position: 22 +title: VueJS +--- + +[VueJS](https://vuejs.org/) is a JS library for building user interfaces. + +This demo tries to cover common Vue data flow ideas and strategies. Single-File +Components (SFC) and VueJS familiarity is assumed. + +Other demos cover general VueJS deployments, including: + +- [Static Site Generation powered by NuxtJS](./content#nuxtjs) +- [iOS and Android applications powered by Quasar](./mobile#quasar) +- [`vue3-table-lite` UI component](./grid#vue3-table-lite) + + +## Installation + +[The "Frameworks" section](../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. For example, our +[presidents sheet](https://sheetjs.com/pres.xlsx) has "Name" / "Index" columns: + +![`pres.xlsx` data](pathname:///pres.png) + +This naturally maps to an array of typed objects, as in the TS example below: + +```ts +import { read, utils } from 'xlsx'; + +interface President { + Name: string; + Index: number; +} + +const f = await (await fetch("https://sheetjs.com/pres.xlsx")).arrayBuffer(); +const wb = read(f); +const data = utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]); +console.log(data); +``` + +`data` will be an array of objects: + +```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 } +] +``` + +A component will typically map over the data. The following example generates +a TABLE with a row for each President: + +```html title="src/SheetJSVueAoO.vue" + + + +``` + +### 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` function generates HTML that is aware of merges and other +worksheet features. VueJS `v-html` attribute allows assignment of `innerHTML` +attribute, effectively inserting the code into the page: + +```html title="src/SheetJSVueHTML.vue" + + + +``` + +### Rows and Columns + +Some data grids and UI components split worksheet state in two parts: an array +of column attribute objects and an array of row objects. The former is used to +generate column headings and for indexing into the row objects. + +The safest approach is to use an array of arrays for state and to generate +column objects that map to A1-style column headers. + +The [Vue Table Lite demo](./grid#rows-and-columns-bindings) uses this approach +with the following column and row structure: + +```js +/* rows are generated with a simple array of arrays */ +rows.value = utils.sheet_to_json(worksheet, { header: 1 }); + +/* column objects are generated based on the worksheet range */ +const range = utils.decode_range(ws["!ref"]||"A1"); +columns.value = Array.from({ length: range.e.c + 1 }, (_, i) => ({ + /* for an array of arrays, the keys are "0", "1", "2", ... */ + field: String(i), + /* column labels: encode_col translates 0 -> "A", 1 -> "B", 2 -> "C", ... */ + label: XLSX.utils.encode_col(i) +})); +``` + + +## Legacy Deployments + +[The Standalone Scripts](../getting-started/installation/standalone) play nice +with legacy deployments that do not use a bundler. + +The legacy demos show a simple VueJS component. It is written in ES5 syntax. +The pages are not minified and "View Source" should be used to inspect. + +- [VueJS version 2](pathname:///vue/index2.html) +- [VueJS version 3](pathname:///vue/index3.html) + +There is a shared component [`SheetJS-vue.js`](pathname:///vue/SheetJS-vue.js) + +:::caution + +The entire demo is designed to run in Internet Explorer and does not reflect +modern design patterns. + +::: \ No newline at end of file diff --git a/docz/docs/03-demos/index.md b/docz/docs/03-demos/index.md index 74dc5e7..43fd816 100644 --- a/docz/docs/03-demos/index.md +++ b/docz/docs/03-demos/index.md @@ -18,18 +18,18 @@ The demo projects include small runnable examples and short explainers. ### Frameworks -- [`Angular.JS`](./legacy#angularjs) - [`Angular 2+ and Ionic`](https://github.com/SheetJS/SheetJS/tree/master/demos/angular2/) -- [`Knockout`](./legacy#knockout) - [`React`](./react) -- [`VueJS`](https://github.com/SheetJS/SheetJS/tree/master/demos/vue/) +- [`VueJS`](./vue) +- [`Angular.JS`](./legacy#angularjs) +- [`Knockout`](./legacy#knockout) ### Front-End UI Components - [`canvas-datagrid`](./grid#canvas-datagrid) -- [`x-spreadsheet`](https://github.com/SheetJS/SheetJS/tree/master/demos/xspreadsheet/) -- [`react-data-grid`](https://github.com/SheetJS/SheetJS/tree/master/demos/react/modify/) -- [`vue3-table-light`](https://github.com/SheetJS/SheetJS/tree/master/demos/vue/modify/) +- [`x-spreadsheet`](./grid#x-spreadsheet) +- [`react-data-grid`](./grid#react-data-grid) +- [`vue3-table-lite`](./grid#vue3-table-lite) - [`angular-ui-grid`](./grid#angular-ui-grid) ### Platforms and Integrations diff --git a/docz/static/browserify/app.js b/docz/static/browserify/app.js index 8590e78..cd71fff 100644 --- a/docz/static/browserify/app.js +++ b/docz/static/browserify/app.js @@ -1,4 +1,4 @@ -/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ +/* sheetjs (C) 2013-present SheetJS -- http://sheetjs.com */ var XLSX = require('xlsx'); /*jshint browser:true */ /*global require */ diff --git a/docz/static/browserify/index.html b/docz/static/browserify/index.html index 453c59a..34e0480 100644 --- a/docz/static/browserify/index.html +++ b/docz/static/browserify/index.html @@ -1,5 +1,5 @@ - + diff --git a/docz/static/browserify/xlsxworker.js b/docz/static/browserify/xlsxworker.js index c5cea24..dbb3518 100644 --- a/docz/static/browserify/xlsxworker.js +++ b/docz/static/browserify/xlsxworker.js @@ -1,4 +1,4 @@ -/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ +/* sheetjs (C) 2013-present SheetJS -- http://sheetjs.com */ var XLSX = require('xlsx'); postMessage({t:"ready"}); diff --git a/docz/static/cdg/index.html b/docz/static/cdg/index.html index 1cf2a45..1dd157c 100644 --- a/docz/static/cdg/index.html +++ b/docz/static/cdg/index.html @@ -1,5 +1,5 @@ - + diff --git a/docz/static/knockout/knockout.html b/docz/static/knockout/knockout.html index 611408d..2678c55 100644 --- a/docz/static/knockout/knockout.html +++ b/docz/static/knockout/knockout.html @@ -1,5 +1,5 @@ - + diff --git a/docz/static/react/pres.png b/docz/static/pres.png similarity index 100% rename from docz/static/react/pres.png rename to docz/static/pres.png diff --git a/docz/static/react/index.html b/docz/static/react/index.html index d75e8d4..55b7a83 100644 --- a/docz/static/react/index.html +++ b/docz/static/react/index.html @@ -3,156 +3,156 @@ - - SheetJS React Demo - - - - - - - + + SheetJS React Demo + + + + + + + - -
- + /* React 18 uses ReactDOM.createRoot; < 18 should use ReactDOM.render */ + const root_elt = document.getElementById('app'); + if(typeof ReactDOM.createRoot !== "undefined") { + const root = ReactDOM.createRoot(root_elt); + root.render(); + } else { + ReactDOM.render(, root_elt); + } + \ No newline at end of file diff --git a/docz/static/vtl/App.vue b/docz/static/vtl/App.vue new file mode 100644 index 0000000..52513d1 --- /dev/null +++ b/docz/static/vtl/App.vue @@ -0,0 +1,219 @@ + + + + + + diff --git a/docz/static/vue/SheetJS-vue.js b/docz/static/vue/SheetJS-vue.js new file mode 100644 index 0000000..ba805b0 --- /dev/null +++ b/docz/static/vue/SheetJS-vue.js @@ -0,0 +1,60 @@ +/* sheetjs (C) 2013-present SheetJS -- http://sheetjs.com */ +var SheetJSFT = [ + "xlsx", "xlsb", "xlsm", "xls", "xml", "csv", "txt", "ods", "fods", "uos", "sylk", "dif", "dbf", "prn", "qpw", "123", "wb*", "wq*", "html", "htm", "numbers" +].map(function(x) { return "." + x; }).join(","); + +var SJSTemplate = [ + '
', + '', + '
', + '', + '
', + '
', + '
' +].join(""); +var component_struct = { + template: SJSTemplate, + methods: { + onchange: function(evt) { + var files = evt.target.files; + if (!files || files.length == 0) return; + + var file = files[0]; + + var reader = new FileReader(); + reader.onload = function (e) { + // get data + var bytes = new Uint8Array(e.target.result); + + /* read workbook */ + var wb = XLSX.read(bytes); + + /* grab first sheet */ + var wsname = wb.SheetNames[0]; + var ws = wb.Sheets[wsname]; + + /* generate HTML */ + var HTML = XLSX.utils.sheet_to_html(ws); + + /* update table */ + document.getElementById('out-table').innerHTML = HTML; + /* show export button */ + document.getElementById('export-table').style.visibility = "visible"; + }; + + reader.readAsArrayBuffer(file); + }, + onexport: function(evt) { + /* generate workbook object from table */ + var wb = XLSX.utils.table_to_book(document.getElementById('out-table').getElementsByTagName("TABLE")[0]); + /* generate file and force a download*/ + XLSX.writeFile(wb, "sheetjs.xlsx"); + } + } +}; +if(Vue.component) { + Vue.component('html-preview', component_struct); +} else { + var app = Vue.createApp({}); + app.component('html-preview', component_struct); +} diff --git a/docz/static/vue/index2.html b/docz/static/vue/index2.html new file mode 100644 index 0000000..654517e --- /dev/null +++ b/docz/static/vue/index2.html @@ -0,0 +1,56 @@ + + + + + + SheetJS + VueJS2 + + + + + + + + + + + + +
+SheetJS + VueJS2 demo
+
+This demo shows a sample Vue component "html-preview" that:
+- displays a file input that accepts a spreadsheet file
+- draws the first worksheet of a submitted file as HTML
+- presents an export button to generate XLSX files
+
+Sample Spreadsheet
+
+ + +
+ +
+ + + + + diff --git a/docz/static/vue/index3.html b/docz/static/vue/index3.html new file mode 100644 index 0000000..a2bdfae --- /dev/null +++ b/docz/static/vue/index3.html @@ -0,0 +1,56 @@ + + + + + + SheetJS + VueJS3 + + + + + + + + + + + + +
+SheetJS + VueJS3 demo
+
+This demo shows a sample Vue component "html-preview" that:
+- displays a file input that accepts a spreadsheet file
+- draws the first worksheet of a submitted file as HTML
+- presents an export button to generate XLSX files
+
+Sample Spreadsheet
+
+ + +
+ +
+ + + + + diff --git a/docz/static/xspreadsheet/index.html b/docz/static/xspreadsheet/index.html new file mode 100644 index 0000000..b18cda7 --- /dev/null +++ b/docz/static/xspreadsheet/index.html @@ -0,0 +1,142 @@ + + + + + + +SheetJS + x-spreadsheet Live Demo + + + + + +
+SheetJS Data Preview Live Demo
+
+x-spreadsheet component library
+
+Source Code Repo
+Issues?  Something look weird?  Click here and report an issue
+
+
Drop a spreadsheet file here to see sheet data
+ ... or click here to select a file + +
+

+
+
+ + + + + + + +