rowpine 0.1.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -23
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,45 +1,51 @@
|
|
|
1
1
|
# rowpine
|
|
2
2
|
|
|
3
|
-
Pivot tables and Excel and PDF export for TanStack Table and shadcn/ui data tables
|
|
3
|
+
**Pivot tables, a pivot designer, and Excel and PDF export for TanStack Table and shadcn/ui data tables.** Works with TanStack Table v8 and v9.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
[Website](https://rowpine.com) · [Demos](https://rowpine.com/examples/) · [Docs](https://rowpine.com/docs/) · [Pricing](https://rowpine.com/pricing.html)
|
|
6
|
+
|
|
7
|
+

|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## Install
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
-
|
|
12
|
+
npm install rowpine
|
|
13
|
+
npx shadcn add https://rowpine.com/r/export-menu.json
|
|
14
|
+
npx shadcn add https://rowpine.com/r/pivot.json
|
|
13
15
|
```
|
|
14
16
|
|
|
17
|
+
This package is the engine: the file writers, the pivot and the license check. The two `shadcn add` lines copy the export menu, the pivot table and the pivot designer into your project as source.
|
|
18
|
+
|
|
15
19
|
## Export
|
|
16
20
|
|
|
17
|
-
Pass the TanStack table you already render. The file matches the screen: visible columns in their order,
|
|
21
|
+
Pass the TanStack table you already render. The file matches the screen: visible columns in their order, every filtered row on every page, the current sort, pinned columns frozen, groups as Excel outline rows with `SUBTOTAL` formulas, typed numbers and dates.
|
|
18
22
|
|
|
19
23
|
```ts
|
|
20
|
-
import { exportCsv, exportPdf, exportXlsx, setLicenseKey } from
|
|
24
|
+
import { exportCsv, exportPdf, exportXlsx, setLicenseKey } from "rowpine"
|
|
21
25
|
|
|
22
26
|
setLicenseKey(import.meta.env.VITE_ROWPINE_KEY)
|
|
23
27
|
|
|
24
|
-
await exportXlsx(table, { fileName:
|
|
25
|
-
await exportPdf(table, { fileName:
|
|
26
|
-
await exportCsv(table, { fileName:
|
|
28
|
+
await exportXlsx(table, { fileName: "orders" })
|
|
29
|
+
await exportPdf(table, { fileName: "orders", title: "Orders" })
|
|
30
|
+
await exportCsv(table, { fileName: "orders" }) // free, no key needed
|
|
27
31
|
```
|
|
28
32
|
|
|
29
|
-
|
|
33
|
+

|
|
34
|
+
|
|
35
|
+
`rows: "all" | "page" | "selected"` picks the rows (default `"all"`: every filtered row on every page). `rowStyle` styles whole rows. `download: false` returns the Blob without saving it.
|
|
30
36
|
|
|
31
37
|
Per-column settings go in `meta.rowpine`:
|
|
32
38
|
|
|
33
39
|
```ts
|
|
34
40
|
{
|
|
35
|
-
accessorKey:
|
|
36
|
-
header:
|
|
37
|
-
aggregationFn:
|
|
41
|
+
accessorKey: "amount",
|
|
42
|
+
header: "Amount",
|
|
43
|
+
aggregationFn: "sum",
|
|
38
44
|
meta: {
|
|
39
45
|
rowpine: {
|
|
40
|
-
numFmt: '"$"#,##0.00',
|
|
46
|
+
numFmt: '"$"#,##0.00', // Excel number format
|
|
41
47
|
format: (v) => money.format(v as number), // PDF text
|
|
42
|
-
cellStyle: (v) => ((v as number) > 5000 ? { fill:
|
|
48
|
+
cellStyle: (v) => ((v as number) > 5000 ? { fill: "#dcfce7" } : undefined),
|
|
43
49
|
},
|
|
44
50
|
},
|
|
45
51
|
}
|
|
@@ -47,15 +53,21 @@ Per-column settings go in `meta.rowpine`:
|
|
|
47
53
|
|
|
48
54
|
Also: `header`, `width`, `align`, `exclude`.
|
|
49
55
|
|
|
56
|
+
## PDF
|
|
57
|
+
|
|
58
|
+
Page size and orientation, a title, headline numbers, a watermark, group rows with their totals, the header row on every page. Wide tables shrink and then split so every column prints.
|
|
59
|
+
|
|
60
|
+

|
|
61
|
+
|
|
50
62
|
## Pivot
|
|
51
63
|
|
|
52
64
|
```ts
|
|
53
|
-
import { createPivot, exportXlsx, pivotRowStyle } from
|
|
65
|
+
import { createPivot, exportXlsx, pivotRowStyle } from "rowpine"
|
|
54
66
|
|
|
55
67
|
const pivot = createPivot(orders, {
|
|
56
|
-
rows: [
|
|
57
|
-
cols: [
|
|
58
|
-
values: [{ field:
|
|
68
|
+
rows: ["region", "country"],
|
|
69
|
+
cols: ["quarter"],
|
|
70
|
+
values: [{ field: "amount", agg: "sum", label: "Amount" }],
|
|
59
71
|
})
|
|
60
72
|
|
|
61
73
|
pivot.data // rows nested through subRows, for useTable / useReactTable
|
|
@@ -63,10 +75,16 @@ pivot.columns // column definitions with accessor functions
|
|
|
63
75
|
await exportXlsx(pivot.table, { rowStyle: pivotRowStyle })
|
|
64
76
|
```
|
|
65
77
|
|
|
66
|
-
Aggregations: `sum`, `avg`, `min`, `max`, `count`, `countDistinct`, `first`, `last`, or a function. Subtotals and grand totals are on by default (`rowSubtotals`, `grandTotalRow`, `grandTotalCol`).
|
|
78
|
+
Aggregations: `sum`, `avg`, `min`, `max`, `count`, `countDistinct`, `first`, `last`, or a function. Subtotals and grand totals are on by default (`rowSubtotals`, `grandTotalRow`, `grandTotalCol`). The pivot designer's layout rules are exported too (`addToWell`, `setAggregatorAt`, `pivotFromLayout` and more), so you can drive a layout from your own UI.
|
|
79
|
+
|
|
80
|
+
## Demos
|
|
81
|
+
|
|
82
|
+
Ten demos play a short story on the live component and end with the exported file. [Open the demos](https://rowpine.com/examples/).
|
|
83
|
+
|
|
84
|
+
[](https://rowpine.com/examples/#/demo/orders-to-excel)
|
|
67
85
|
|
|
68
86
|
## License key
|
|
69
87
|
|
|
70
|
-
|
|
88
|
+
CSV export is free. Excel, PDF and pivots need a key; without one everything still runs, and Excel and PDF files carry one notice line. A key covers every version released during its year of updates, for good. Keys are checked in the browser, with no call to a server. [Pricing](https://rowpine.com/pricing.html).
|
|
71
89
|
|
|
72
90
|
Commercial license: see LICENSE.md.
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
function q(e,n){if(typeof document>"u"||typeof URL>"u"||!URL.createObjectURL)return;let t=URL.createObjectURL(e),o=document.createElement("a");o.href=t,o.download=n,o.rel="noopener",o.style.display="none",document.body.appendChild(o),o.click(),o.remove(),setTimeout(()=>URL.revokeObjectURL(t),1e3)}function ne(e,n){let t=(e??"").trim()||"export";return t.toLowerCase().endsWith(`.${n}`)?t:`${t}.${n}`}function $t(e){return(e.getState?.()??e.store?.state??e.state)?.grouping??[]}function _t(e){return(e.getSortedRowModel?.()??e.getGroupedRowModel?.()??e.getFilteredRowModel?.()??e.getCoreRowModel()).rows}var Ft=new Set(["sum","mean","min","max"]);function ye(e){return e.columnDef.meta?.rowpine??{}}function Mt(e){let n=ye(e).header??(typeof e.columnDef.header=="string"?e.columnDef.header:e.id),t=[];for(let o=e.parent;o;o=o.parent){let r=typeof o.columnDef.header=="string"?o.columnDef.header:"";r&&t.unshift(r)}return[...t,n].join(" / ")}function It(e){let n=e.getStartVisibleLeafColumns??e.getLeftVisibleLeafColumns,t=e.getEndVisibleLeafColumns??e.getRightVisibleLeafColumns;if(n&&t&&e.getCenterVisibleLeafColumns){let o=n.call(e);return{columns:[...o,...e.getCenterVisibleLeafColumns(),...t.call(e)],frozen:o.length}}return{columns:e.getVisibleLeafColumns?.()??e.getAllLeafColumns(),frozen:0}}function Z(e,n={}){let t=It(e),o=t.columns.filter(l=>!ye(l).exclude),r=t.columns.slice(0,t.frozen).filter(l=>!ye(l).exclude).length,i=o.map(l=>{let h=ye(l),P=l.columnDef.aggregationFn;return{id:l.id,header:Mt(l),width:h.width??l.getSize?.()??150,align:h.align,numFmt:h.numFmt,format:h.format,cellStyle:h.cellStyle,subtotal:typeof P=="string"&&(Ft.has(P)||P==="auto")?P:void 0}}),s=new Set($t(e)),u=[],c=(l,h)=>{let P=l.getIsGrouped?.()??!1,L=i.map(k=>l.getValue(k.id)),N=i.map(k=>s.has(k.id)&&(P?k.id!==l.groupingColumnId:h>0)),x={kind:P?"group":"data",depth:h,values:L,blank:N,descendants:0,hasChildren:l.subRows.length>0,original:l.original,style:n.rowStyle?.(l.original)};if(P){let k=String(l.groupingValue??l.getValue(l.groupingColumnId??"")??""),S=i.findIndex(y=>y.id===l.groupingColumnId);S<0&&(S=0),x.labelAt=S,x.label=k,L[S]=k,L.forEach((y,R)=>{R!==S&&typeof y!="number"&&(x.blank[R]=!0)})}return x},m=(l,h)=>{let P=c(l,h);u.push(P);let L=0;for(let N of l.subRows)L+=m(N,h+1);return P.descendants=L,L+1},d=n.rows??"all";if(d==="all")for(let l of _t(e))m(l,0);else{let l=d==="page"?e.getRowModel().rows:e.getSelectedRowModel?.().rows??[];for(let h of l){if(d==="selected"&&h.getIsGrouped?.())continue;let P=c(h,d==="page"?h.depth:0);d==="selected"&&(P.blank=P.blank.map(()=>!1)),u.push(P)}}return{columns:i,rows:u,freezeColumns:r}}function Ve(e,n,t){return n==null||n===""?"":e.format?e.format(n,t):typeof n=="number"?Number.isFinite(n)?n.toLocaleString(void 0,{maximumFractionDigits:2}):"":n instanceof Date?Number.isNaN(n.getTime())?"":n.toLocaleDateString():typeof n=="boolean"?n?"Yes":"No":String(n)}function Xe(e,n,t){return e.align?e.align:typeof n.rows.find(r=>r.kind==="data"&&r.values[t]!=null)?.values[t]=="number"?"right":"left"}var de=e=>String(e).padStart(2,"0");function Dt(e){if(e==null)return"";if(e instanceof Date){if(Number.isNaN(e.getTime()))return"";let n=`${e.getFullYear()}-${de(e.getMonth()+1)}-${de(e.getDate())}`;return e.getHours()||e.getMinutes()||e.getSeconds()?`${n} ${de(e.getHours())}:${de(e.getMinutes())}:${de(e.getSeconds())}`:n}return typeof e=="number"?Number.isFinite(e)?String(e):"":String(e)}function We(e,n){let t=/^[=+\-@\t\r]/.test(e)&&!/^-?\d/.test(e)?`'${e}`:e;return t.includes(n)||/["\r\n]/.test(t)?`"${t.replace(/"/g,'""')}"`:t}function je(e,n={}){let t=Z(e,n),o=n.delimiter??",",r=[t.columns.map(i=>We(i.header,o)).join(o)];for(let i of t.rows)i.kind!=="group"&&r.push(i.values.map(s=>We(Dt(s),o)).join(o));return r.join(`\r
|
|
2
2
|
`)+`\r
|
|
3
|
-
`}async function Ot(e,n={}){let t=je(e,n),o=new Blob([n.bom??!0?"\uFEFF"+t:t],{type:"text/csv;charset=utf-8"});return(n.download??!0)&&q(o,ne(n.fileName,"csv")),o}import{verifyAsync as Nt}from"@noble/ed25519";var Ue="2026-11-
|
|
3
|
+
`}async function Ot(e,n={}){let t=je(e,n),o=new Blob([n.bom??!0?"\uFEFF"+t:t],{type:"text/csv;charset=utf-8"});return(n.download??!0)&&q(o,ne(n.fileName,"csv")),o}import{verifyAsync as Nt}from"@noble/ed25519";var Ue="2026-11-14";var Et="943b6a3625ce15fa7fd62ee65897491f1d4f55fa5430cb253b6db9d0634e6cad",be="Exported with an unlicensed copy of Rowpine. https://rowpine.com/",Ke=null,Le=null,Ae=!1;function zt(e){Ke=e?.trim()||null,Le=null,Ae=!1}function Ge(e){let n=e.replace(/-/g,"+").replace(/_/g,"/")+"=".repeat((4-e.length%4)%4),t=atob(n),o=new Uint8Array(t.length);for(let r=0;r<t.length;r++)o[r]=t.charCodeAt(r);return o}function Bt(e){let n=new Uint8Array(e.length/2);for(let t=0;t<n.length;t++)n[t]=parseInt(e.slice(t*2,t*2+2),16);return n}async function Vt(e,n,t){if(!e)return{licensed:!1,reason:"missing",buildDate:t};let o=e.split(".");if(o.length!==3||o[0]!=="RP1")return{licensed:!1,reason:"malformed",buildDate:t};let r;try{r=JSON.parse(new TextDecoder().decode(Ge(o[1])))}catch{return{licensed:!1,reason:"malformed",buildDate:t}}let i=!1;try{i=await Nt(Ge(o[2]),new TextEncoder().encode(o[1]),Bt(n))}catch{i=!1}return!i||r.v!==1?{licensed:!1,reason:"invalid",buildDate:t}:t<=r.upd?{licensed:!0,payload:r,buildDate:t}:{licensed:!1,reason:"updates-ended",payload:r,buildDate:t}}function He(){return Le??=Vt(Ke,Et,Ue),Le}function Xt(e,n){let t="Get a key at https://rowpine.com/#pricing and pass it to setLicenseKey().";switch(e.reason){case"missing":return`Rowpine: ${n} is running without a license key. It works, and files carry a one-line notice. ${t}`;case"malformed":case"invalid":return`Rowpine: the license key passed to setLicenseKey() is not valid. ${t}`;case"updates-ended":return`Rowpine: this version was built on ${e.buildDate}, after the updates on your key ended (${e.payload?.upd}). Keep the version you have, or renew updates at https://rowpine.com/#pricing.`}}async function oe(e){let n=await He();return n.licensed?!0:(Ae||(Ae=!0,console.warn(Xt(n,e))),!1)}var Wt={"&":"&","<":"<",">":">",'"':""","'":"'"},jt=/[\x00-\x08\x0B\x0C\x0E-\x1F]/g;function j(e){return e.replace(jt,"").replace(/[&<>"']/g,n=>Wt[n])}function Y(e){let n=e,t="";do t=String.fromCharCode(65+n%26)+t,n=Math.floor(n/26)-1;while(n>=0);return t}function we(e){if(!e)return null;let n=/^#?([0-9a-f]{6})$/i.exec(e.trim());return n?"FF"+n[1].toUpperCase():null}function Ut(e){return(Date.UTC(e.getFullYear(),e.getMonth(),e.getDate(),e.getHours(),e.getMinutes(),e.getSeconds(),e.getMilliseconds())-Date.UTC(1899,11,30))/864e5}function Gt(e){if(e instanceof Date)return e;let n=String(e).trim(),t=/^(\d{4})-(\d{2})-(\d{2})$/.exec(n);return t?new Date(Number(t[1]),Number(t[2])-1,Number(t[3])):new Date(n)}var Ye=`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
4
4
|
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/><Default Extension="xml" ContentType="application/xml"/><Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/><Override PartName="/xl/worksheets/sheet1.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/><Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/></Types>`,Kt=`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
5
5
|
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/></Relationships>`;function Ht(e){return e.replace(/[\\/?*[\]:]/g," ").trim().slice(0,31)||"Sheet1"}function Yt(e){return`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
6
6
|
<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"><sheets><sheet name="${j(Ht(e))}" sheetId="1" r:id="rId1"/></sheets></workbook>`}var qt=`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|