This commit is contained in:
SheetJS 2023-04-24 04:50:42 -04:00
parent 76dbfc419c
commit 945adcd104
16 changed files with 366 additions and 170 deletions

@ -120,6 +120,7 @@ ActiveX
Airtable
AlaSQL
AngularJS
AppleScript
ArrayBuffer
Auth
BOM
@ -203,6 +204,7 @@ MVC
MVVM
MacOS
MariaDB
Mathematica
Meridiem
MongoDB
MySQL
@ -220,6 +222,7 @@ Northwind
Nunjucks
Nuxt
NuxtJS
OSA
PPI
PhantomJS
PhoneGap
@ -307,6 +310,7 @@ embeddable
encodings
esbuild
filesystem
frontmatter
globals
iOS
iWork

@ -15,7 +15,7 @@ Other demos cover general VueJS deployments, including:
- [Static Site Generation powered by NuxtJS](/docs/demos/static/nuxtjs)
- [iOS and Android applications powered by Quasar](/docs/demos/mobile/quasar)
- [Desktop application powered by Tauri](/docs/demos/desktop/tauri)
- [`vue3-table-lite` UI component](/docs/demos/grid#vue3-table-lite)
- [`vue3-table-lite` UI component](/docs/demos/grid/vtl)
## Installation
@ -232,8 +232,8 @@ 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 [`vue3-table-lite` demo](/docs/demos/grid#rows-and-columns-bindings) generates rows
and columns objects with the following structure:
The [`vue3-table-lite` demo](/docs/demos/grid/vtl#rows-and-columns-bindings)
generates rows and columns objects with the following structure:
```js
/* rows are generated with a simple array of arrays */

@ -0,0 +1,124 @@
---
title: vue3-table-lite
pagination_prev: demos/frontend/index
pagination_next: demos/net/index
---
:::note
This demo was tested against `vue3-table-lite 1.2.4`, VueJS `3.2.47`, ViteJS
4.3.1, and `@vitejs/plugin-vue` 4.1.0 on 2023 April 24
:::
The demo creates a site that looks like the screenshot below:
![vue3-table-lite screenshot](pathname:///vtl/vtl1.png)
## Integration Details
#### Rows and Columns Bindings
`vue3-table-lite` presents two attribute bindings: an array of column metadata
(`columns`) and an array of objects representing the displayed data (`rows`).
Typically both are `ref` objects:
```html
<script setup lang="ts">
import { ref } from "vue";
import VueTableLite from "vue3-table-lite/ts";
/* rows */
type Row = any[];
const rows = ref<Row[]>([]);
/* columns */
type Column = { field: string; label: string; };
const columns = ref<Column[]>([]);
</script>
<template>
<vue-table-lite :columns="columns" :rows="rows"></vue-table-lite>
</template>
```
These can be mutated through the `value` property in VueJS 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,
columns must be objects whose `field` property is the index converted to string:
```js
import { ref } from "vue";
import { utils } from 'xlsx';
/* generate row and column data */
function ws_to_vtl(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), // vtl 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_vtl(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 vtl_to_ws(rows) {
return utils.aoa_to_sheet(rows.value);
}
```
## Demo
1) Create a new ViteJS App using the VueJS + TypeScript template:
```bash
npm create vite@latest sheetjs-vtl -- --template vue-ts
cd sheetjs-vtl
```
2) Install dependencies:
```bash
npm i -S https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz vue3-table-lite@1.2.4
```
3) Download [`src/App.vue`](pathname:///vtl/App.vue) and replace the contents:
```bash
curl -L -o src/App.vue https://docs.sheetjs.com/vtl/App.vue
```
4) run `npm run dev`. When you load the page in the browser, it will try to
fetch <https://sheetjs.com/pres.numbers> and load the data.

@ -217,122 +217,7 @@ npm i -S https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz @mui/x-data-grid @e
<!-- spellchecker-enable -->
:::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
:::
#### VueJS Demo
<details><summary><b>Complete Example</b> (click to show)</summary>
1) Create a new ViteJS App using the VueJS + 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
curl -L -o src/App.vue https://docs.sheetjs.com/vtl/App.vue
```
4) run `npm run dev`. When you load the page in the browser, it will try to
fetch <https://sheetjs.com/pres.numbers> and load the data.
</details>
#### Rows and Columns Bindings
`vue3-table-lite` presents two attribute bindings: an array of column metadata
(`columns`) and an array of objects representing the displayed data (`rows`).
Typically both are `ref` objects:
```html
<script setup lang="ts">
import { ref } from "vue";
import VueTableLite from "vue3-table-lite/ts";
/* rows */
type Row = any[];
const rows = ref<Row[]>([]);
/* columns */
type Column = { field: string; label: string; };
const columns = ref<Column[]>([]);
</script>
<template>
<vue-table-lite :columns="columns" :rows="rows"></vue-table-lite>
</template>
```
These can be mutated through the `value` property in VueJS 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,
columns must be objects whose `field` property is the index converted to string:
```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);
}
```
**[The exposition has been moved to a separate page.](/docs/demos/grid/vtl)**
## Standard HTML Tables

@ -248,28 +248,4 @@ npx http-server dist
Open a web browser and access the displayed URL (usually http://localhost:8080).
View the page source and confirm that no JS was added to the page. It only
contains the content from the file in an HTML table:
```html
<!DOCTYPE html>
<html>
<body>
<h3>Presidents</h3>
<table>
<thead><tr><th>Name</th><th>Index</th></tr></thead>
<tbody>
<tr>
<td>Bill Clinton</td><td>42</td>
</tr><tr>
<td>GeorgeW Bush</td><td>43</td>
</tr><tr>
<td>Barack Obama</td><td>44</td>
</tr><tr>
<td>Donald Trump</td><td>45</td>
</tr><tr>
<td>Joseph Biden</td><td>46</td>
</tr>
</tbody>
</table>
</body></html>
```
contains the content from the file in an HTML table.

@ -28,6 +28,148 @@ The "Complete Example" creates an app that looks like the screenshots below:
</td></tr></tbody></table>
["Fetching Remote Data"](#fetching-remote-data) uses the built-in `fetch` to
download and parse remote workbook files.
["Native Libraries"](#native-libraries) uses native libraries to read and write
files in the local device.
:::caution
**Before reading this demo, follow the official React Native CLI Guide!**
Development Environment Guide: <https://reactnative.dev/docs/environment-setup>
Follow the instructions for iOS (requires macOS) and for Android. They will
cover installation and system configuration. You should be able to build and run
a sample app in the Android and the iOS (if applicable) simulators.
:::
## Fetching Remote Data
:::info
React Native `0.72.0` will support binary data with `fetch`. For older versions,
[a native library](#native-libraries) can provide support.
:::
React Native 0.72.0 will support binary data with `fetch`:
```js
/* fetch data into an ArrayBuffer */
const ab = await (await fetch("https://sheetjs.com/pres.numbers")).arrayBuffer();
/* parse data */
const wb = XLSX.read(ab);
```
### Fetch Demo
The following demo uses `react-native-table-component` to display the first
worksheet in a simple table.
:::note
This demo was tested on an Intel Mac on 2023 April 24 with RN `0.72.0-rc.1`.
The iOS simulator runs iOS 16.2 on an iPhone SE (3rd generation).
:::
1) Create project:
```bash
npx react-native init SheetJSRNFetch --version="0.72.0-rc.1"
```
2) Install shared dependencies:
```bash
cd SheetJSRNFetch
curl -LO https://oss.sheetjs.com/assets/img/logo.png
npm i -S https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz
npm i -S react-native-table-component@1.2.0 @types/react-native-table-component
```
Refresh iOS project by running `pod install` from the `ios` subfolder:
```bash
cd ios; pod install; cd ..
```
3) Download [`App.tsx`](pathname:///reactnative/App.tsx) and replace:
```bash
curl -LO https://docs.sheetjs.com/reactnative/App.tsx
```
**iOS Testing**
Start the iOS emulator:
```bash
npx react-native run-ios
```
When opened, the app should look like the "Before" screenshot below. After
tapping "Import data from a spreadsheet", the app should show new data:
<table><thead><tr>
<th>Before</th>
<th>After</th>
</tr></thead><tbody><tr><td>
![before screenshot](pathname:///reactnative/iosfetch1.png)
</td><td>
![after screenshot](pathname:///reactnative/iosfetch2.png)
</td></tr></tbody></table>
**Android Testing**
Start the Android emulator:
```bash
npx react-native run-android
```
:::note
When this demo was last tested, the simulator failed with the message
> Unable to load script. Make sure you're either Running Metro ...
The workaround is to launch Metro directly:
```bash
npx react-native start
```
Press `a` in the terminal window and Metro will try to reload the app.
:::
When opened, the app should look like the "Before" screenshot below. After
tapping "Import data from a spreadsheet", the app should show new data:
<table><thead><tr>
<th>Before</th>
<th>After</th>
</tr></thead><tbody><tr><td>
![before screenshot](pathname:///reactnative/andfetch1.png)
</td><td>
![after screenshot](pathname:///reactnative/andfetch2.png)
</td></tr></tbody></table>
## Native Libraries
@ -312,17 +454,9 @@ are not covered here.
This example tries to separate the library-specific functions.
0) **Follow the official React Native CLI Guide!**
Development Environment Guide: <https://reactnative.dev/docs/environment-setup>
Follow the instructions for iOS and for Android. They will cover installation
and system configuration. By the end, you should be able to run the sample app
in the Android and the iOS simulators.
1) Create project:
```
```bash
npx react-native init SheetJSRN --version="0.67.2"
```
@ -332,7 +466,7 @@ npx react-native init SheetJSRN --version="0.67.2"
cd SheetJSRN
curl -LO https://oss.sheetjs.com/assets/img/logo.png
npm i -S https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz
npm i -S react-native-table-component react-native-document-picker
npm i -S react-native-table-component@1.2.0 react-native-document-picker
```
Refresh iOS project by running `pod install` from the `ios` subfolder:

@ -36,7 +36,7 @@ run in the web browser, demos will include interactive examples.
- [`x-spreadsheet`](/docs/demos/grid/xs)
- [`react-data-grid`](/docs/demos/grid/rdg)
- [`glide-data-grid`](/docs/demos/grid/gdg)
- [`vue3-table-lite`](/docs/demos/grid#vue3-table-lite)
- [`vue3-table-lite`](/docs/demos/grid/vtl)
- [`angular-ui-grid`](/docs/demos/grid#angular-ui-grid)
- [`material ui`](/docs/demos/grid#material-ui-table)

@ -644,7 +644,7 @@ export default function App() {
</TabItem>
<TabItem value="vue" label="VueJS">
[`vue3-table-lite`](/docs/demos/grid#vue3-table-lite) is a VueJS 3 data table.
[`vue3-table-lite`](/docs/demos/grid/vtl) is a VueJS 3 data table.
</TabItem>
</Tabs>

@ -162,11 +162,11 @@ The default behavior for all parsers is to generate number cells. Passing the
`cellDates` to true will force the parsers to store dates:
```js
// cell A1 will be { t: 'n', v: 44721 }
var wb_sans_date = XLSX.read("6/9/2022", {type:"binary"});
// cell A1 will be { t: 'n', v: 54337 }
var wb_sans_date = XLSX.read("10/6/2048", {type:"binary"});
// cell A1 will be { t: 'd', v: <Date object representing June 9 2022> }
var wb_with_date = XLSX.read("6/9/2022", {type:"binary", cellDates: true});
// cell A1 will be { t: 'd', v: <Date object representing 2048 October 06> }
var wb_with_date = XLSX.read("10/6/2048", {type:"binary", cellDates: true});
```
When writing, date cells are automatically translated back to numeric cells

@ -262,28 +262,28 @@ git checkout -- .
### Reproduce official builds
4) Run `git log` and search for the commit that matches a particular release
version. For example, version `0.19.1` can be found with:
version. For example, version `0.19.3` can be found with:
```bash
git log | grep -B4 "version bump 0.19.1"
git log | grep -B4 "version bump 0.19.3"
```
The output should look like:
```bash
$ git log | grep -B4 "version bump 0.19.1"
$ git log | grep -B4 "version bump 0.19.3"
# highlight-next-line
commit 51a861900092bfc01b2fa9960d4c932dcbeb6925 <-- this is the commit hash
commit 333e4e40f9c5603bd22a811f54c61c20bc9e17ab <-- this is the commit hash
Author: SheetJS <dev@sheetjs.com>
Date: Thu Nov 17 04:35:34 2022 -0500
Date: Mon Apr 17 23:39:28 2023 -0400
version bump 0.19.1
version bump 0.19.3
```
5) Switch to that commit:
```bash
git checkout 51a861900092bfc01b2fa9960d4c932dcbeb6925
git checkout 333e4e40f9c5603bd22a811f54c61c20bc9e17ab
```
6) Run the full build sequence
@ -301,14 +301,14 @@ The local checksum for the browser script can be computed with:
```bash
$ md5sum dist/xlsx.full.min.js
00b46a9f2d30ddc69780ab8049d6809e dist/xlsx.full.min.js
f5c73b5ddc4b431c909d11c2e1d7a8e0 dist/xlsx.full.min.js
```
The checksum for the CDN version can be computed with:
```bash
$ curl -L https://cdn.sheetjs.com/xlsx-0.19.1/package/dist/xlsx.full.min.js | md5sum -
00b46a9f2d30ddc69780ab8049d6809e -
$ curl -L https://cdn.sheetjs.com/xlsx-0.19.3/package/dist/xlsx.full.min.js | md5sum -
f5c73b5ddc4b431c909d11c2e1d7a8e0 -
```
The two hashes should match.

@ -0,0 +1,73 @@
/* sheetjs (C) SheetJS -- https://sheetjs.com */
import React, { useState, useCallback } from 'react';
import { StyleSheet, Text, Button, Alert, Image, ScrollView } from 'react-native';
import { Table, Row, Rows, TableWrapper } from 'react-native-table-component';
import { read, utils, WorkSheet } from 'xlsx';
const make_width = (ws: WorkSheet): number[] => {
const aoa = utils.sheet_to_json(ws, {header:1}), res: number[] = [];
aoa.forEach((r) => { r.forEach((c, C) => { res[C] = Math.max(res[C]||60, String(c).length * 10); }); });
for(let C = 0; C < res.length; ++C) if(!res[C]) res[C] = 60;
return res;
};
function App(): JSX.Element {
const [data, setData] = useState<any[]>([
"SheetJS".split(""),
[5,4,3,3,7,9,5],
[8,6,7,5,3,0,9]
]);
const [widths, setWidths] = useState<number[]>(Array.from({length:7}, () => 20));
const importFile = useCallback(async() => {
try {
const ab = await (await fetch("https://sheetjs.com/pres.numbers")).arrayBuffer();
const wb = read(ab);
/* convert first worksheet to AOA */
const wsname = wb.SheetNames[0];
const ws = wb.Sheets[wsname];
const data = utils.sheet_to_json(ws, {header:1});
/* update state */
setData(data);
setWidths(make_width(ws));
} catch(err) {
Alert.alert("importFile Error", "Error " + ((err as any).message || err));
}
}, []);
return (
<ScrollView contentContainerStyle={styles.container}>
<Text style={styles.welcome}> </Text>
<Text style={styles.welcome}> <Image source={require("./logo.png")} style={styles.image}/> &nbsp; SheetJS × React Native</Text>
<Button onPress={importFile} title="Import data from a spreadsheet" color="#841584" />
<Text style={styles.bolded}>Current Data</Text>
<ScrollView style={styles.table} horizontal={true} >
<Table style={styles.table}>
<TableWrapper>
<Row data={data[0]} style={styles.thead} textStyle={styles.text} widthArr={widths}/>
</TableWrapper>
<ScrollView>
<TableWrapper>
<Rows data={data.slice(1)} style={styles.tr} textStyle={styles.text} widthArr={widths}/>
</TableWrapper>
</ScrollView>
</Table>
</ScrollView>
</ScrollView>
);
}
const styles = StyleSheet.create({
container: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#F5FCFF' },
welcome: { fontSize: 20, textAlign: 'center', margin: 10 },
bolded: { textAlign: 'center', color: '#333333', marginBottom: 5, fontWeight: "bold" },
thead: { height: 40, backgroundColor: '#f1f8ff' },
tr: { height: 30 },
text: { marginLeft: 5, },
table: { width: "100%" },
image: { height: 16, width: 16 }
});
export default App;

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

BIN
docz/static/vtl/vtl1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB