From 4a9d643d3974798ba37d5c1bd66868ba5a6f5386 Mon Sep 17 00:00:00 2001 From: Joboufra Date: Fri, 15 May 2026 21:39:03 +0200 Subject: [PATCH 1/2] feat: replace xlsx with jszip for Excel export, update next to 16.2.6 --- package-lock.json | 176 +++++++++++++++++++++++----------------------- package.json | 2 +- src/app/page.jsx | 99 ++++++++++++++++++++++++-- 3 files changed, 182 insertions(+), 95 deletions(-) diff --git a/package-lock.json b/package-lock.json index 79562d6..560201c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,10 +13,10 @@ "@fortawesome/react-fontawesome": "^0.2.0", "framer-motion": "^10.16.5", "jsonToTable": "file:", + "jszip": "^3.10.1", "next": "16.2.6", "react": "18.3.1", - "react-dom": "^18", - "xlsx": "^0.18.5" + "react-dom": "^18" }, "devDependencies": { "autoprefixer": "^10.0.1", @@ -1928,13 +1928,6 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/adler-32": { - "version": "1.3.1", - "license": "Apache-2.0", - "engines": { - "node": ">=0.8" - } - }, "node_modules/ajv": { "version": "6.15.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", @@ -2426,17 +2419,6 @@ ], "license": "CC-BY-4.0" }, - "node_modules/cfb": { - "version": "1.2.2", - "license": "Apache-2.0", - "dependencies": { - "adler-32": "~1.3.0", - "crc-32": "~1.2.0" - }, - "engines": { - "node": ">=0.8" - } - }, "node_modules/chalk": { "version": "4.1.2", "dev": true, @@ -2495,13 +2477,6 @@ "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", "license": "MIT" }, - "node_modules/codepage": { - "version": "1.15.0", - "license": "Apache-2.0", - "engines": { - "node": ">=0.8" - } - }, "node_modules/color-convert": { "version": "2.0.1", "dev": true, @@ -2538,15 +2513,11 @@ "dev": true, "license": "MIT" }, - "node_modules/crc-32": { - "version": "1.2.2", - "license": "Apache-2.0", - "bin": { - "crc32": "bin/crc32.njs" - }, - "engines": { - "node": ">=0.8" - } + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" }, "node_modules/cross-spawn": { "version": "7.0.6", @@ -3544,13 +3515,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/frac": { - "version": "1.1.2", - "license": "Apache-2.0", - "engines": { - "node": ">=0.8" - } - }, "node_modules/fraction.js": { "version": "4.3.7", "dev": true, @@ -3898,6 +3862,12 @@ "node": ">= 4" } }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "license": "MIT" + }, "node_modules/import-fresh": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", @@ -3934,7 +3904,6 @@ }, "node_modules/inherits": { "version": "2.0.4", - "dev": true, "license": "ISC" }, "node_modules/internal-slot": { @@ -4491,6 +4460,18 @@ "node": ">=4.0" } }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "license": "(MIT OR GPL-3.0-or-later)", + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -4533,6 +4514,15 @@ "node": ">= 0.8.0" } }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "license": "MIT", + "dependencies": { + "immediate": "~3.0.5" + } + }, "node_modules/lilconfig": { "version": "2.1.0", "dev": true, @@ -4966,6 +4956,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "license": "(MIT AND Zlib)" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -5201,6 +5197,12 @@ "node": ">= 0.8.0" } }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, "node_modules/prop-types": { "version": "15.8.1", "license": "MIT", @@ -5276,6 +5278,27 @@ "pify": "^2.3.0" } }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readable-stream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, "node_modules/readdirp": { "version": "3.6.0", "dev": true, @@ -5418,6 +5441,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, "node_modules/safe-push-apply": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", @@ -5519,6 +5548,12 @@ "node": ">= 0.4" } }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "license": "MIT" + }, "node_modules/sharp": { "version": "0.34.5", "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", @@ -5683,16 +5718,6 @@ "node": ">=0.10.0" } }, - "node_modules/ssf": { - "version": "0.11.2", - "license": "Apache-2.0", - "dependencies": { - "frac": "~1.1.2" - }, - "engines": { - "node": ">=0.8" - } - }, "node_modules/stable-hash": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz", @@ -5714,6 +5739,15 @@ "node": ">= 0.4" } }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/string.prototype.includes": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz", @@ -6337,7 +6371,6 @@ }, "node_modules/util-deprecate": { "version": "1.0.2", - "dev": true, "license": "MIT" }, "node_modules/which": { @@ -6445,44 +6478,11 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/wmf": { - "version": "1.0.2", - "license": "Apache-2.0", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/word": { - "version": "0.3.0", - "license": "Apache-2.0", - "engines": { - "node": ">=0.8" - } - }, "node_modules/wrappy": { "version": "1.0.2", "dev": true, "license": "ISC" }, - "node_modules/xlsx": { - "version": "0.18.5", - "license": "Apache-2.0", - "dependencies": { - "adler-32": "~1.3.0", - "cfb": "~1.2.1", - "codepage": "~1.15.0", - "crc-32": "~1.2.1", - "ssf": "~0.11.2", - "wmf": "~1.0.1", - "word": "~0.3.0" - }, - "bin": { - "xlsx": "bin/xlsx.njs" - }, - "engines": { - "node": ">=0.8" - } - }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", diff --git a/package.json b/package.json index 42a29ef..a83b00e 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "next": "16.2.6", "react": "18.3.1", "react-dom": "^18", - "xlsx": "^0.18.5" + "jszip": "^3.10.1" }, "devDependencies": { "autoprefixer": "^10.0.1", diff --git a/src/app/page.jsx b/src/app/page.jsx index b45742e..7da4e1b 100644 --- a/src/app/page.jsx +++ b/src/app/page.jsx @@ -7,7 +7,7 @@ import HtmlTable from './components/htmlTable'; import Modal from './components/modal'; import NavBar from './components/Navbar'; import Welcome from './components/Welcome'; -import * as XLSX from 'xlsx'; +import JSZip from 'jszip'; export default function Home() { const [jsonInput, setJsonInput] = useState(''); @@ -83,12 +83,99 @@ export default function Home() { document.body.removeChild(link); } - function exportToExcel(data, filename = 'JsonToTable.xlsx') { - const worksheet = XLSX.utils.aoa_to_sheet(data); - const workbook = XLSX.utils.book_new(); - XLSX.utils.book_append_sheet(workbook, worksheet, 'JsonToTable - Joboufra'); + function escapeXml(text) { + return text + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/'/g, '''); + } + + async function exportToExcel(data, filename = 'JsonToTable.xlsx') { + const zip = new JSZip(); + + const sharedStrings = []; + const stringIndex = new Map(); + + function getSstIndex(text) { + const key = text; + if (stringIndex.has(key)) return stringIndex.get(key); + const index = sharedStrings.length; + sharedStrings.push(key); + stringIndex.set(key, index); + return index; + } + + let rowsXml = ''; + data.forEach((row, rowIndex) => { + const r = rowIndex + 1; + let cells = ''; + row.forEach((cell, colIndex) => { + const colLetter = String.fromCharCode(65 + colIndex); + const text = cell ?? ''; + if (text) { + const sstIdx = getSstIndex(text); + cells += `${sstIdx}`; + } else { + cells += ``; + } + }); + rowsXml += `${cells}`; + }); - XLSX.writeFile(workbook, filename); + const sstXml = sharedStrings.map((s) => `${escapeXml(s)}`).join(''); + + zip.file('[Content_Types].xml', ` + + + + + + +`); + + zip.file('_rels/.rels', ` + + +`); + + zip.file('xl/_rels/workbook.xml.rels', ` + + + +`); + + zip.file('xl/workbook.xml', ` + + + + +`); + + const colCount = data.length > 0 ? Math.max(...data.map((r) => r.length)) : 1; + const colRef = String.fromCharCode(64 + colCount); + + zip.file('xl/worksheets/sheet1.xml', ` + + ${rowsXml} + +`); + + zip.file('xl/sharedStrings.xml', ` + + ${sstXml} +`); + + const blob = await zip.generateAsync({ type: 'blob', mimeType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }); + const url = URL.createObjectURL(blob); + const link = document.createElement('a'); + link.href = url; + link.download = filename; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + URL.revokeObjectURL(url); } const handleExport = (format) => { From e891798eb95aa6f498db64d79bc8e2325371dfb4 Mon Sep 17 00:00:00 2001 From: Joboufra Date: Fri, 15 May 2026 22:14:04 +0200 Subject: [PATCH 2/2] revert jszip changes, use xlsx secure fork --- package-lock.json | 103 +++++++--------------------------------------- package.json | 6 +-- src/app/page.jsx | 101 ++++----------------------------------------- 3 files changed, 25 insertions(+), 185 deletions(-) diff --git a/package-lock.json b/package-lock.json index 560201c..1fff50c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,12 +8,12 @@ "name": "jsonToTable", "version": "2.0.0", "dependencies": { + "@e965/xlsx": "^0.20.3", "@fortawesome/fontawesome-svg-core": "^6.4.2", "@fortawesome/free-solid-svg-icons": "^6.4.2", "@fortawesome/react-fontawesome": "^0.2.0", "framer-motion": "^10.16.5", "jsonToTable": "file:", - "jszip": "^3.10.1", "next": "16.2.6", "react": "18.3.1", "react-dom": "^18" @@ -290,6 +290,18 @@ "node": ">=6.9.0" } }, + "node_modules/@e965/xlsx": { + "version": "0.20.3", + "resolved": "https://registry.npmjs.org/@e965/xlsx/-/xlsx-0.20.3.tgz", + "integrity": "sha512-703RN/3OdsRD5mtse2HBX7Um7xwaP9tlswEG6svOtjqokXoX7rJdQj7DyabD2I+xk22RgaIIU+R6BHgkpZGB/w==", + "license": "Apache-2.0", + "bin": { + "xlsx": "bin/xlsx.njs" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/@emnapi/core": { "version": "1.7.1", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.7.1.tgz", @@ -2513,12 +2525,6 @@ "dev": true, "license": "MIT" }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "license": "MIT" - }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -3862,12 +3868,6 @@ "node": ">= 4" } }, - "node_modules/immediate": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", - "license": "MIT" - }, "node_modules/import-fresh": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", @@ -3904,6 +3904,7 @@ }, "node_modules/inherits": { "version": "2.0.4", + "dev": true, "license": "ISC" }, "node_modules/internal-slot": { @@ -4460,18 +4461,6 @@ "node": ">=4.0" } }, - "node_modules/jszip": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", - "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", - "license": "(MIT OR GPL-3.0-or-later)", - "dependencies": { - "lie": "~3.3.0", - "pako": "~1.0.2", - "readable-stream": "~2.3.6", - "setimmediate": "^1.0.5" - } - }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -4514,15 +4503,6 @@ "node": ">= 0.8.0" } }, - "node_modules/lie": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", - "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", - "license": "MIT", - "dependencies": { - "immediate": "~3.0.5" - } - }, "node_modules/lilconfig": { "version": "2.1.0", "dev": true, @@ -4956,12 +4936,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "license": "(MIT AND Zlib)" - }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -5197,12 +5171,6 @@ "node": ">= 0.8.0" } }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "license": "MIT" - }, "node_modules/prop-types": { "version": "15.8.1", "license": "MIT", @@ -5278,27 +5246,6 @@ "pify": "^2.3.0" } }, - "node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/readable-stream/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "license": "MIT" - }, "node_modules/readdirp": { "version": "3.6.0", "dev": true, @@ -5441,12 +5388,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, "node_modules/safe-push-apply": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", @@ -5548,12 +5489,6 @@ "node": ">= 0.4" } }, - "node_modules/setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", - "license": "MIT" - }, "node_modules/sharp": { "version": "0.34.5", "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", @@ -5739,15 +5674,6 @@ "node": ">= 0.4" } }, - "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/string.prototype.includes": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz", @@ -6371,6 +6297,7 @@ }, "node_modules/util-deprecate": { "version": "1.0.2", + "dev": true, "license": "MIT" }, "node_modules/which": { diff --git a/package.json b/package.json index a83b00e..1937437 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "lint": "next lint" }, "dependencies": { + "@e965/xlsx": "^0.20.3", "@fortawesome/fontawesome-svg-core": "^6.4.2", "@fortawesome/free-solid-svg-icons": "^6.4.2", "@fortawesome/react-fontawesome": "^0.2.0", @@ -16,8 +17,7 @@ "jsonToTable": "file:", "next": "16.2.6", "react": "18.3.1", - "react-dom": "^18", - "jszip": "^3.10.1" + "react-dom": "^18" }, "devDependencies": { "autoprefixer": "^10.0.1", @@ -30,4 +30,4 @@ "engines": { "node": ">=20.9.0" } -} \ No newline at end of file +} diff --git a/src/app/page.jsx b/src/app/page.jsx index 7da4e1b..c0bc655 100644 --- a/src/app/page.jsx +++ b/src/app/page.jsx @@ -7,7 +7,7 @@ import HtmlTable from './components/htmlTable'; import Modal from './components/modal'; import NavBar from './components/Navbar'; import Welcome from './components/Welcome'; -import JSZip from 'jszip'; +import * as XLSX from '@e965/xlsx'; export default function Home() { const [jsonInput, setJsonInput] = useState(''); @@ -83,99 +83,12 @@ export default function Home() { document.body.removeChild(link); } - function escapeXml(text) { - return text - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"') - .replace(/'/g, '''); - } - - async function exportToExcel(data, filename = 'JsonToTable.xlsx') { - const zip = new JSZip(); - - const sharedStrings = []; - const stringIndex = new Map(); - - function getSstIndex(text) { - const key = text; - if (stringIndex.has(key)) return stringIndex.get(key); - const index = sharedStrings.length; - sharedStrings.push(key); - stringIndex.set(key, index); - return index; - } - - let rowsXml = ''; - data.forEach((row, rowIndex) => { - const r = rowIndex + 1; - let cells = ''; - row.forEach((cell, colIndex) => { - const colLetter = String.fromCharCode(65 + colIndex); - const text = cell ?? ''; - if (text) { - const sstIdx = getSstIndex(text); - cells += `${sstIdx}`; - } else { - cells += ``; - } - }); - rowsXml += `${cells}`; - }); + function exportToExcel(data, filename = 'JsonToTable.xlsx') { + const worksheet = XLSX.utils.aoa_to_sheet(data); + const workbook = XLSX.utils.book_new(); + XLSX.utils.book_append_sheet(workbook, worksheet, 'JsonToTable - Joboufra'); - const sstXml = sharedStrings.map((s) => `${escapeXml(s)}`).join(''); - - zip.file('[Content_Types].xml', ` - - - - - - -`); - - zip.file('_rels/.rels', ` - - -`); - - zip.file('xl/_rels/workbook.xml.rels', ` - - - -`); - - zip.file('xl/workbook.xml', ` - - - - -`); - - const colCount = data.length > 0 ? Math.max(...data.map((r) => r.length)) : 1; - const colRef = String.fromCharCode(64 + colCount); - - zip.file('xl/worksheets/sheet1.xml', ` - - ${rowsXml} - -`); - - zip.file('xl/sharedStrings.xml', ` - - ${sstXml} -`); - - const blob = await zip.generateAsync({ type: 'blob', mimeType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }); - const url = URL.createObjectURL(blob); - const link = document.createElement('a'); - link.href = url; - link.download = filename; - document.body.appendChild(link); - link.click(); - document.body.removeChild(link); - URL.revokeObjectURL(url); + XLSX.writeFile(workbook, filename); } const handleExport = (format) => { @@ -468,4 +381,4 @@ export default function Home() { )} ); -} +} \ No newline at end of file