diff --git a/docz/docs/03-demos/01-frontend/01-react.md b/docz/docs/03-demos/01-frontend/01-react.md index e8faef4..cbb9a0f 100644 --- a/docz/docs/03-demos/01-frontend/01-react.md +++ b/docz/docs/03-demos/01-frontend/01-react.md @@ -16,7 +16,7 @@ Other demos cover general React deployments, including: - [iOS and Android applications powered by React Native](/docs/demos/mobile/reactnative) - [Desktop application powered by React Native Windows + macOS](/docs/demos/desktop/reactnative) - [React Data Grid UI component](/docs/demos/grid#react-data-grid) -- [Glide Data Grid UI component](/docs/demos/grid#glide-data-grid) +- [Glide Data Grid UI component](/docs/demos/grid/gdg) ## Installation diff --git a/docz/docs/03-demos/01-frontend/02-vue.md b/docz/docs/03-demos/01-frontend/02-vue.md index 2217a40..1a5366b 100644 --- a/docz/docs/03-demos/01-frontend/02-vue.md +++ b/docz/docs/03-demos/01-frontend/02-vue.md @@ -118,8 +118,8 @@ function exportFile() { :::note -This demo was last run on 2022 November 11 using `vue@3.2.41`. When running -`npm init`, the package `create-vue@3.4.0` was installed. +This demo was last run on 2023 April 06 using `vue@3.2.47`. When running +`npm init`, the package `create-vue@3.6.1` was installed. ::: @@ -194,8 +194,8 @@ function exportFile() { :::note -This demo was last run on 2022 November 11 using `vue@3.2.41`. When running -`npm init`, the package `create-vue@3.4.0` was installed. +This demo was last run on 2023 April 06 using `vue@3.2.47`. When running +`npm init`, the package `create-vue@3.6.1` was installed. ::: diff --git a/docz/docs/03-demos/02-grid/17-gdg.md b/docz/docs/03-demos/02-grid/17-gdg.md new file mode 100644 index 0000000..2577003 --- /dev/null +++ b/docz/docs/03-demos/02-grid/17-gdg.md @@ -0,0 +1,305 @@ +--- +title: Glide Datagrid +pagination_prev: demos/frontend/index +pagination_next: demos/net/index +--- + +:::note + +This demo was last tested on 2023 February 07 with the ViteJS+React+TypeScript +starter (Vite `4.1.1`, React `18.2.0`) and `@glideapps/glide-data-grid@5.2.1`. + +::: + +## Integration Details + +#### Backing Store + +Under the hood, the `DataEditor` component is designed to call methods and +request data to display in the grid. It is typical to store data *outside* of +component state. A `getCellContent` callback will pull data from the external +backing store, while SheetJS operations will directly act on the store: + +```js +// !! THESE OBJECTS ARE DEFINED OUTSIDE OF THE COMPONENT FUNCTION !! + +// this will store the raw data objects +let data: any[] = []; +// this will store the header names +let header: string[] = []; +``` + +#### Props + +:::note + +This is a high-level overview. The official documentation should be consulted. + +::: + +_Columns_ + +`DataEditor` expects column metadata to be passed through a `columns` prop. This +should be managed in the component state: + +```js +import { useState } from 'react'; +import { DataEditor, GridColumn } from '@glideapps/glide-data-grid'; + +function App() { + // highlight-next-line + const [cols, setCols] = useState([]); // gdg column objects + // ... + return ( <> + // ... + + // ... + ); +} +export default App; +``` + +Each `GridColumn` object expects a `title` representing the display name and an +`id` representing the key to index within the data object. + +_Data_ + +The `DataEditor` component expects a `getCellContent` callback for supplying +data. The callback accepts column and row indices. The column index should be +used to find the header key: + +```js +import { useCallback } from 'react'; +import { DataEditor, GridCellKind, GridCell, Item } from '@glideapps/glide-data-grid'; + +// ... + +function App() { + // ... + // backing data store -> gdg + // highlight-start + const getContent = useCallback((cell: Item): GridCell => { + const [col, row] = cell; + return { + kind: GridCellKind.Text, + // header[col] is the name of the field + displayData: String(data[row]?.[header[col]]??""), + data: data[row]?.[header[col]], + }; + }, []); + // highlight-end + // ... + return ( <> + // ... + + // ... + ); +} +``` + +_Row Count_ + +`DataEditor` also accepts a `rows` property indicating the number of rows. This +is best managed in state: + +```js +import { useState } from 'react'; +import { DataEditor } from '@glideapps/glide-data-grid'; + +function App() { + // highlight-next-line + const [rows, setRows] = useState(0); // number of rows + // ... + return ( <> + // ... + + // ... + ); +} +export default App; +``` + +_Editing Data_ + +The demo uses the `onCellEdited` callback to write back to the data store. + +### Parsing Data + +_SheetJS to Data Store_ + +The raw data objects are readily generated with `sheet_to_json`. The headers +can be pulled by extracting the first row of the worksheet: + +```js +import { utils, WorkBook } from 'xlsx'; + +// ... + +const update_backing_store = (wb: WorkBook) => { + // get first worksheet + const sheet = wb.Sheets[wb.SheetNames[0]]; + + // set data + // highlight-next-line + data = utils.sheet_to_json(sheet); + + // create a range consisting of the first row + const range = utils.decode_range(sheet["!ref"]??"A1"); // original range + range.e.r = range.s.r; // set ending row to starting row (select first row) + + // pull headers + // highlight-next-line + header = utils.sheet_to_json(sheet, {header: 1, range})[0]; +}; + +// ... +``` + +_Data Store to GDG_ + +Scheduling a refresh for the `DataEditor` involves updating the grid column +metadata and row count through the standard state. It also requires a special +`updateCells` call to instruct the grid to mark the cached data as stale: + +```js +import { useRef } from 'react' +import { WorkBook } from 'xlsx' +import { DataEditor, GridColumn, Item, DataEditorRef } from '@glideapps/glide-data-grid' + +function App() { + const ref = useRef(null); // gdg ref + // ... + const parse_wb = (wb: WorkBook) => { + update_backing_store(wb); + + // highlight-start + // update column metadata by pulling from external header keys + setCols(header.map(h => ({title: h, id: h} as GridColumn))); + + // update number of rows + setRows(data.length); + + if(data.length > 0) { + // create an array of the cells that must be updated + let cells = data.map( + (_,R) => Array.from({length:header.length}, (_,C) => ({cell: ([C,R] as Item)})) + ).flat(); + // initiate update using the `ref` attached to the DataEditor + ref.current?.updateCells(cells) + } + // highlight-end + }; + // ... + return ( <> + // ... + + // ... + ); +} +export default App; +``` + +### Writing Data + +`json_to_sheet` works directly on the `data` array: + +```js +const ws = utils.json_to_sheet(data); // easy :) +``` + +Since the editor can change the header titles, it is strongly recommended to +pull column data from the state and rewrite the header row: + +```js +import { utils, writeFileXLSX } from 'xlsx'; + +function App() { + // ... + const exportXLSX = useCallback(() => { + // highlight-start + // generate worksheet using data with the order specified in the columns array + const ws = utils.json_to_sheet(data, {header: cols.map(c => c.id ?? c.title)}); + + // rewrite header row with titles + utils.sheet_add_aoa(ws, [cols.map(c => c.title ?? c.id)], {origin: "A1"}); + // highlight-end + + // create workbook + const wb = utils.book_new(); + utils.book_append_sheet(wb, ws, "Export"); // replace with sheet name + // download file + writeFileXLSX(wb, "sheetjs-gdg.xlsx"); + }, []); + // ... + return ( <> + // ... + // highlight-next-line + + // ... + ); +} +export default App; +``` + +## Demo + +1) Create a new project: + +```bash +npm create vite@latest -- sheetjs-gdg --template react-ts +cd sheetjs-gdg +npm i +``` + +Install SheetJS and Glide Data Grid required dependencies: + +```bash +npm i --save https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz +npm i --save @glideapps/glide-data-grid lodash marked +``` + +Start dev server: + +```bash +npm run dev +``` + +The terminal window will display a URL (typically `http://localhost:5173`). +Open the URL with a web browser. + +2) Download [`App.tsx`](pathname:///gdg/App.tsx) and replace `src/App.tsx`: + +```bash +curl -L -o src/App.tsx https://docs.sheetjs.com/gdg/App.tsx +``` + +Refresh the browser window and a grid should be displayed: + +![glide-data-grid initial view](pathname:///gdg/pre.png) + +3) To test the export functionality, make some changes to the grid data. + +Suppose you believe that 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. By double-clicking on each cell in the +Index column, a cell editor should appear. Decrement each index: + +![glide-data-grid after edits](pathname:///gdg/post.png) + +Click on the "Export" button to create a file! Open the file and verify. diff --git a/docz/docs/03-demos/02-grid/index.md b/docz/docs/03-demos/02-grid/index.md index 80e9d65..c00d9c2 100644 --- a/docz/docs/03-demos/02-grid/index.md +++ b/docz/docs/03-demos/02-grid/index.md @@ -217,307 +217,7 @@ function rdg_to_ws(rows: Row[]): WorkSheet { ### Glide Data Grid -:::note - -This demo was last tested on 2023 February 07 with the ViteJS+React+TypeScript -starter (Vite `4.1.1`, React `18.2.0`) and `@glideapps/glide-data-grid@5.2.1`. - -::: - -#### GDG Demo - -
Complete Example (click to show) - -1) Create a new project: - -```bash -npm create vite@latest -- sheetjs-gdg --template react-ts -cd sheetjs-gdg -npm i -``` - -Install SheetJS and Glide Data Grid required dependencies: - -```bash -npm i --save https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz -npm i --save @glideapps/glide-data-grid lodash marked -``` - -Start dev server: - -```bash -npm run dev -``` - -The terminal window will display a URL (typically `http://localhost:5173`). -Open the URL with a web browser. - -2) Download [`App.tsx`](pathname:///gdg/App.tsx) and replace `src/App.tsx`: - -```bash -curl -L -o src/App.tsx https://docs.sheetjs.com/gdg/App.tsx -``` - -Refresh the browser window and a grid should be displayed: - -![glide-data-grid initial view](pathname:///gdg/pre.png) - -3) To test the export functionality, make some changes to the grid data. - -Suppose you believe that 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. By double-clicking on each cell in the -Index column, a cell editor should appear. Decrement each index: - -![glide-data-grid after edits](pathname:///gdg/post.png) - -Click on the "Export" button to create a file! Open the file and verify. - -
- -#### Backing Store - -Under the hood, the `DataEditor` component is designed to call methods and -request data to display in the grid. It is typical to store data *outside* of -component state. A `getCellContent` callback will pull data from the external -backing store, while SheetJS operations will directly act on the store: - -```js -// !! THESE OBJECTS ARE DEFINED OUTSIDE OF THE COMPONENT FUNCTION !! - -// this will store the raw data objects -let data: any[] = []; -// this will store the header names -let header: string[] = []; -``` - -#### GDG Props - -:::note - -This is a high-level overview. The official documentation should be consulted. - -::: - -_Columns_ - -`DataEditor` expects column metadata to be passed through a `columns` prop. This -should be managed in the component state: - -```js -import { useState } from 'react'; -import { DataEditor, GridColumn } from '@glideapps/glide-data-grid'; - -function App() { - // highlight-next-line - const [cols, setCols] = useState([]); // gdg column objects - // ... - return ( <> - // ... - - // ... - ); -} -export default App; -``` - -Each `GridColumn` object expects a `title` representing the display name and an -`id` representing the key to index within the data object. - -_Data_ - -The `DataEditor` component expects a `getCellContent` callback for supplying -data. The callback accepts column and row indices. The column index should be -used to find the header key: - -```js -import { useCallback } from 'react'; -import { DataEditor, GridCellKind, GridCell, Item } from '@glideapps/glide-data-grid'; - -// ... - -function App() { - // ... - // backing data store -> gdg - // highlight-start - const getContent = useCallback((cell: Item): GridCell => { - const [col, row] = cell; - return { - kind: GridCellKind.Text, - // header[col] is the name of the field - displayData: String(data[row]?.[header[col]]??""), - data: data[row]?.[header[col]], - }; - }, []); - // highlight-end - // ... - return ( <> - // ... - - // ... - ); -} -``` - -_Row Count_ - -`DataEditor` also accepts a `rows` property indicating the number of rows. This -is best managed in state: - -```js -import { useState } from 'react'; -import { DataEditor } from '@glideapps/glide-data-grid'; - -function App() { - // highlight-next-line - const [rows, setRows] = useState(0); // number of rows - // ... - return ( <> - // ... - - // ... - ); -} -export default App; -``` - -_Editing Data_ - -The demo uses the `onCellEdited` callback to write back to the data store. - -#### Parsing Data - -_SheetJS to Data Store_ - -The raw data objects are readily generated with `sheet_to_json`. The headers -can be pulled by extracting the first row of the worksheet: - -```js -import { utils, WorkBook } from 'xlsx'; - -// ... - -const update_backing_store = (wb: WorkBook) => { - // get first worksheet - const sheet = wb.Sheets[wb.SheetNames[0]]; - - // set data - // highlight-next-line - data = utils.sheet_to_json(sheet); - - // create a range consisting of the first row - const range = utils.decode_range(sheet["!ref"]??"A1"); // original range - range.e.r = range.s.r; // set ending row to starting row (select first row) - - // pull headers - // highlight-next-line - header = utils.sheet_to_json(sheet, {header: 1, range})[0]; -}; - -// ... -``` - -_Data Store to GDG_ - -Scheduling a refresh for the `DataEditor` involves updating the grid column -metadata and row count through the standard state. It also requires a special -`updateCells` call to instruct the grid to mark the cached data as stale: - -```js -import { useRef } from 'react' -import { WorkBook } from 'xlsx' -import { DataEditor, GridColumn, Item, DataEditorRef } from '@glideapps/glide-data-grid' - -function App() { - const ref = useRef(null); // gdg ref - // ... - const parse_wb = (wb: WorkBook) => { - update_backing_store(wb); - - // highlight-start - // update column metadata by pulling from external header keys - setCols(header.map(h => ({title: h, id: h} as GridColumn))); - - // update number of rows - setRows(data.length); - - if(data.length > 0) { - // create an array of the cells that must be updated - let cells = data.map( - (_,R) => Array.from({length:header.length}, (_,C) => ({cell: ([C,R] as Item)})) - ).flat(); - // initiate update using the `ref` attached to the DataEditor - ref.current?.updateCells(cells) - } - // highlight-end - }; - // ... - return ( <> - // ... - - // ... - ); -} -export default App; -``` - -#### Writing Data - -`json_to_sheet` works directly on the `data` array: - -```js -const ws = utils.json_to_sheet(data); // easy :) -``` - -Since the editor can change the header titles, it is strongly recommended to -pull column data from the state and rewrite the header row: - -```js -import { utils, writeFileXLSX } from 'xlsx'; - -function App() { - // ... - const exportXLSX = useCallback(() => { - // highlight-start - // generate worksheet using data with the order specified in the columns array - const ws = utils.json_to_sheet(data, {header: cols.map(c => c.id ?? c.title)}); - - // rewrite header row with titles - utils.sheet_add_aoa(ws, [cols.map(c => c.title ?? c.id)], {origin: "A1"}); - // highlight-end - - // create workbook - const wb = utils.book_new(); - utils.book_append_sheet(wb, ws, "Export"); // replace with sheet name - // download file - writeFileXLSX(wb, "sheetjs-gdg.xlsx"); - }, []); - // ... - return ( <> - // ... - // highlight-next-line - - // ... - ); -} -export default App; -``` +**[The exposition has been moved to a separate page.](/docs/demos/grid/gdg)** ### Material UI Data Grid diff --git a/docz/docs/03-demos/03-net/02-server.md b/docz/docs/03-demos/03-net/02-server.md index 68b7b31..ec6a347 100644 --- a/docz/docs/03-demos/03-net/02-server.md +++ b/docz/docs/03-demos/03-net/02-server.md @@ -425,7 +425,7 @@ It should prompt to download `SheetJSNest.xlsx` :::note -This demo was verified on 2022 August 24 using `fastify@4.5.2` +This demo was verified on 2023 April 06 using `fastify@4.15.0` ::: @@ -498,7 +498,7 @@ fastify.get('/', (req, reply) => { 0) Save the following snippet to `SheetJSFastify.js`: -```js +```js title="SheetJSFastify.js" /* load SheetJS Library */ const XLSX = require("xlsx"); /* load fastify and enable body parsing */ diff --git a/docz/docs/03-demos/04-static/02-gatsbyjs.md b/docz/docs/03-demos/04-static/02-gatsbyjs.md index 777f104..e3848d8 100644 --- a/docz/docs/03-demos/04-static/02-gatsbyjs.md +++ b/docz/docs/03-demos/04-static/02-gatsbyjs.md @@ -81,8 +81,8 @@ The following query pulls the `Name` and `Index` fields from each row: :::note -This demo was tested on 2022 November 11 against `create-gatsby@3.0.0`. The -generated project used `gatsby@5.0.0` and `react@18.2.0`. +This demo was tested on 2023 April 06 against `create-gatsby@3.8.0`. The +generated project used `gatsby@5.8.1` and `react@18.2.0`. ::: @@ -121,9 +121,23 @@ npm i --save gatsby-transformer-excel gatsby-source-filesystem `} -5) Edit `gatsby-config.js` and add the following lines to the `plugins` array: +5) Make a `src/data` directory, download , and +move the downloaded file into the new folder: -```js +```bash +mkdir -p src/data +curl -L -o src/data/pres.xlsx https://sheetjs.com/pres.xlsx +``` + +6) Edit `gatsby-config.js` and add the following lines to the `plugins` array: + +```js title="gatsby-config.js" +module.exports = { + siteMetadata: { + title: `sheetjs-gatsby`, + siteUrl: `https://www.yourdomain.tld`, + }, +// highlight-start plugins: [ { resolve: `gatsby-source-filesystem`, @@ -134,18 +148,12 @@ npm i --save gatsby-transformer-excel gatsby-source-filesystem }, `gatsby-transformer-excel`, ], +// highlight-end +} ``` Stop and restart the development server process (`npm run develop`). -6) Make a `src/data` directory, download , and -move the downloaded file into the new folder: - -```bash -mkdir -p src/data -curl -L -o src/data/pres.xlsx https://sheetjs.com/pres.xlsx -``` - ### GraphiQL test 7) Open the GraphiQL editor at `http://localhost:8000/___graphql`. diff --git a/docz/docs/03-demos/04-static/09-nuxtjs.md b/docz/docs/03-demos/04-static/09-nuxtjs.md index 59545b5..5824226 100644 --- a/docz/docs/03-demos/04-static/09-nuxtjs.md +++ b/docz/docs/03-demos/04-static/09-nuxtjs.md @@ -11,7 +11,7 @@ and on-demand server rendering powered by spreadsheets. :::note -This demo was tested on 2022 November 18 against Nuxt Content `v1.15.1`. +This demo was tested on 2023 April 06 against Nuxt Content `v1.15.1`. ::: @@ -87,7 +87,7 @@ neatly with nested `v-for`: :::note The project was generated using `create-nuxt-app v4.0.0`. The generated project -used Nuxt `v2.15.8` and Nuxt Content `v1.15.1`. +used Nuxt `v2.16.3` and Nuxt Content `v1.15.1`. ::: diff --git a/docz/docs/03-demos/09-cloud/10-github.md b/docz/docs/03-demos/09-cloud/10-github.md index 21e87f6..8e98ed4 100644 --- a/docz/docs/03-demos/09-cloud/10-github.md +++ b/docz/docs/03-demos/09-cloud/10-github.md @@ -153,7 +153,7 @@ Deno.writeFileSync(out_file, new TextEncoder().encode(csv)); :::note -This was tested on 2023 February 11 using the GitHub UI. +This was last tested on 2023 April 06 using the GitHub UI. ::: @@ -240,7 +240,13 @@ jobs: 6) Click the `☰` icon and click "Go to Repository" to return to the repo page. -7) Click "Actions" to see the workflows. In the left column, click `flatsheet`. +7) Click "Settings" to see the repository settings. In the left column, click + "Actions" to expand the submenu and click "General". + + Scroll down to "Workflow permissions" and select "Read and write permissions" + if it is not selected. Click "Save". + +8) Click "Actions" to see the workflows. In the left column, click `flatsheet`. This is the page for the action. Every time the action is run, a new entry will be added to the list. @@ -249,12 +255,12 @@ jobs: This will start a new run. After about 30 seconds, a new row should show up in the main area. The icon should be a white `✓` in a green circle. -8) Click "Code" to return to the main view. It should have a file listing that +9) Click "Code" to return to the main view. It should have a file listing that includes `data.xlsx` (downloaded file) and `data.csv` (generated data) Now repeat step 7 to run the action a second time. Click "Code" again. -9) Go to the URL bar and change "github.com" to "flatgithub.com". For example, +10) Go to the URL bar and change "github.com" to "flatgithub.com". For example, if the URL was originally `https://github.com/SheetJS/flat-sheet` , the new URL should be `https://flatgithub.com/SheetJS/flat-sheet` . Press Enter. diff --git a/docz/docs/03-demos/index.md b/docz/docs/03-demos/index.md index 4531085..3afa36d 100644 --- a/docz/docs/03-demos/index.md +++ b/docz/docs/03-demos/index.md @@ -35,7 +35,7 @@ run in the web browser, demos will include interactive examples. - [`canvas-datagrid`](/docs/demos/grid/cdg) - [`x-spreadsheet`](/docs/demos/grid/xs) - [`react-data-grid`](/docs/demos/grid#react-data-grid) -- [`glide-data-grid`](/docs/demos/grid#glide-data-grid) +- [`glide-data-grid`](/docs/demos/grid/gdg) - [`vue3-table-lite`](/docs/demos/grid#vue3-table-lite) - [`angular-ui-grid`](/docs/demos/grid#angular-ui-grid) - [`material ui`](/docs/demos/grid#material-ui-table)