@dcs-tech/ui 0.6.0 → 0.7.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 CHANGED
@@ -69,6 +69,33 @@ The table's runtime dependencies (`@tanstack/react-table`, `@tanstack/react-virt
69
69
  `@tanstack/match-sorter-utils`, `exceljs`, `pdfmake` — loaded on the first PDF export —
70
70
  and `react-icons`) install with the package.
71
71
 
72
+ ## Files and the background worker
73
+
74
+ Exports (DataTable, chart images, your own reports) run through one file engine that
75
+ `UIProvider` sets up. Excel and PDF files build in a **background worker**, so a large
76
+ export does not freeze the page.
77
+
78
+ The worker ships as its own file and imports `exceljs` and `pdfmake` by package name, so
79
+ **your bundler must treat it as a worker entry**:
80
+
81
+ - **Vite** and **webpack 5**: nothing to do. They follow the package's
82
+ `new Worker(new URL(…, import.meta.url))` and bundle the worker themselves.
83
+ - **Anything else**: build a worker from `@dcs-tech/ui/file-worker` with your bundler and hand it
84
+ to the engine:
85
+
86
+ ```ts
87
+ // file.worker.ts — bundled by your setup as a module worker
88
+ import '@dcs-tech/ui/file-worker';
89
+ ```
90
+
91
+ ```tsx
92
+ <UIProvider fileEngine={{ createWorker: () => new Worker('/assets/file.worker.js', { type: 'module' }) }}>
93
+ ```
94
+
95
+ If a worker cannot start, the engine builds the same file on the main thread instead.
96
+ `fileEngine={{ workers: 'off' }}` always uses the main thread. Large PDF fonts (a script font)
97
+ belong on the engine, so they reach each worker once: `fileEngine={{ pdfFonts: { fonts, vfs } }}`.
98
+
72
99
  ## Theming
73
100
 
74
101
  Every colour, size and spacing value is a CSS custom property. Override them on
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { A as e, C as t, Cn as n, Dn as r, E as i, En as a, F as o, J as s, L as c, N as l, Nn as u, O as d, P as f, Q as p, R as m, S as h, T as g, Tn as _, Y as v, _ as y, b, c as x, d as S, et as C, ft as w, g as T, h as ee, i as te, j as ne, kn as re, l as ie, r as ae, rt as oe, st as E, ut as se, w as ce, y as le } from "./geometry-ChwYB45B.js";
3
- import { a as ue, c as de, i as fe, l as pe, t as me } from "./fileActions-KSaVGnaE.js";
4
- import { t as he } from "./runFileTask-BClLQjmv.js";
3
+ import { a as ue, l as de, n as fe, o as pe, u as me } from "./fileActions-COf5Q4Eg.js";
4
+ import { t as he } from "./runFileTask--4YjQH7Y.js";
5
5
  import ge, { cloneElement as _e, createContext as ve, forwardRef as ye, useCallback as D, useContext as be, useEffect as O, useId as xe, useLayoutEffect as Se, useMemo as Ce, useRef as k, useState as A, useSyncExternalStore as we } from "react";
6
6
  import { Fragment as Te, jsx as j, jsxs as M } from "react/jsx-runtime";
7
7
  import { createPortal as Ee } from "react-dom";
@@ -505,25 +505,28 @@ var B = class extends Error {
505
505
  }
506
506
  };
507
507
  function it(e) {
508
- let t = [], n = /* @__PURE__ */ new Set(), r = !1, i = 0, a = (r) => {
508
+ let t = [], n = /* @__PURE__ */ new Set(), r = !1, i = 0, a = () => {
509
+ let t = e.create();
510
+ return e.init !== void 0 && t.postMessage(e.init), {
511
+ worker: t,
512
+ started: !1
513
+ };
514
+ }, o = (r) => {
509
515
  n.delete(r), t.length < e.size ? t.push(r) : r.worker.terminate();
510
- }, o = (e) => {
516
+ }, s = (e) => {
511
517
  n.delete(e), e.worker.terminate();
512
518
  };
513
519
  return {
514
520
  get broken() {
515
521
  return r;
516
522
  },
517
- run(s, { signal: c, progress: l }) {
523
+ run(e, { signal: c, progress: l }) {
518
524
  return new Promise((u, d) => {
519
525
  if (r) return d(new B("unavailable", "Workers are unavailable"));
520
526
  if (c.aborted) return d(new DOMException("Aborted", "AbortError"));
521
527
  let f;
522
528
  try {
523
- f = t.pop() ?? {
524
- worker: e.create(),
525
- started: !1
526
- };
529
+ f = t.pop() ?? a();
527
530
  } catch (e) {
528
531
  return r = !0, d(new B("unavailable", `Worker could not be created: ${String(e)}`));
529
532
  }
@@ -534,24 +537,24 @@ function it(e) {
534
537
  let t = e.data;
535
538
  if (t && t.id === p) {
536
539
  if (f.started = !0, t.type === "progress") return l(t.fraction);
537
- m(), a(f), t.type === "done" ? u(t.buffer) : d(Error(t.message));
540
+ m(), o(f), t.type === "done" ? u(t.buffer) : d(Error(t.message));
538
541
  }
539
542
  }, g = (e) => {
540
- e.preventDefault?.(), m(), o(f), f.started ? d(Error(e.message || "The file worker stopped unexpectedly")) : (r = !0, d(new B("unavailable", e.message || "The file worker failed to start")));
543
+ e.preventDefault?.(), m(), s(f), f.started ? d(Error(e.message || "The file worker stopped unexpectedly")) : (r = !0, d(new B("unavailable", e.message || "The file worker failed to start")));
541
544
  }, _ = () => {
542
- m(), o(f), d(/* @__PURE__ */ Error("The file worker sent a message that could not be read"));
545
+ m(), s(f), d(/* @__PURE__ */ Error("The file worker sent a message that could not be read"));
543
546
  }, v = () => {
544
- m(), o(f), d(c.reason ?? new DOMException("Aborted", "AbortError"));
547
+ m(), s(f), d(c.reason ?? new DOMException("Aborted", "AbortError"));
545
548
  };
546
549
  f.worker.addEventListener("message", h), f.worker.addEventListener("error", g), f.worker.addEventListener("messageerror", _), c.addEventListener("abort", v);
547
550
  try {
548
551
  f.worker.postMessage({
549
552
  type: "run",
550
553
  id: p,
551
- task: s
554
+ task: e
552
555
  });
553
556
  } catch (e) {
554
- m(), a(f), d(new B("uncloneable", e instanceof Error ? e.message : String(e)));
557
+ m(), o(f), d(new B("uncloneable", e instanceof Error ? e.message : String(e)));
555
558
  }
556
559
  });
557
560
  },
@@ -566,7 +569,7 @@ var V = class extends Error {
566
569
  constructor(e, t) {
567
570
  super(t), this.name = "FileEngineError", this.code = e;
568
571
  }
569
- }, at = (e, t, n) => fe(e, pe(t.filename) + ue(t.format), t.format, n, t.title ?? t.filename), ot = () => typeof navigator > "u" ? void 0 : navigator.userActivation?.isActive, H = (e) => e instanceof Error ? e.message : String(e), st = () => new Worker(new URL("./assets/fileTask.worker-FQSUtwcz.js", import.meta.url), { type: "module" }), ct = () => typeof Worker < "u", lt = 0;
572
+ }, at = (e, t, n) => ue(e, me(t.filename) + pe(t.format), t.format, n, t.title ?? t.filename), ot = () => typeof navigator > "u" ? void 0 : navigator.userActivation?.isActive, H = (e) => e instanceof Error ? e.message : String(e), st = () => new Worker(new URL("./assets/fileTask.worker-BHT1olUk.js", import.meta.url), { type: "module" }), ct = () => typeof Worker < "u", lt = 0;
570
573
  function ut(e = {}) {
571
574
  let t = Me(e), n = e.deliver ?? at, r = `file-${++lt}-`, i = [], a = 0, o = !1, s = /* @__PURE__ */ new Map(), c = /* @__PURE__ */ new Map(), l = /* @__PURE__ */ new Map(), u = /* @__PURE__ */ new Set(), d = null, f = t.workers === "auto" && (!!e.createWorker || ct()), p = () => {
572
575
  if (!f) return null;
@@ -574,20 +577,30 @@ function ut(e = {}) {
574
577
  let n = typeof navigator < "u" && navigator.hardwareConcurrency ? navigator.hardwareConcurrency : t.concurrency;
575
578
  d = it({
576
579
  size: Math.max(1, Math.min(t.concurrency, n)),
577
- create: e.createWorker ?? st
580
+ create: e.createWorker ?? st,
581
+ ...e.pdfFonts ? { init: {
582
+ type: "init",
583
+ pdfFonts: e.pdfFonts
584
+ } } : {}
578
585
  });
579
586
  }
580
587
  return d;
581
- }, m = async (e, t, n) => {
582
- let r = p(), i;
583
- if (r && !r.broken) try {
584
- i = await r.run(e, n);
585
- } catch (t) {
586
- if (!(t instanceof B)) throw t;
587
- i = await he(e, n);
588
+ }, m = async (t, n, r) => {
589
+ let i = p(), a;
590
+ if (i && !i.broken) try {
591
+ a = await i.run(t, r);
592
+ } catch (n) {
593
+ if (!(n instanceof B)) throw n;
594
+ a = await he(t, {
595
+ ...r,
596
+ pdfFonts: e.pdfFonts
597
+ });
588
598
  }
589
- else i = await he(e, n);
590
- return new Blob([i], { type: me[t] });
599
+ else a = await he(t, {
600
+ ...r,
601
+ pdfFonts: e.pdfFonts
602
+ });
603
+ return new Blob([a], { type: fe[n] });
591
604
  }, h = (e) => i.find((t) => t.id === e), g = () => u.forEach((e) => e()), _ = (e, t) => {
592
605
  i = i.map((n) => n.id === e ? {
593
606
  ...n,
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { t as e } from "./ChartImageMenu-CuuFnW9q.js";
2
+ import { t as e } from "./ChartImageMenu-C6MwKKjc.js";
3
3
  import { n as t } from "./summaryChartData-pNvzaEHp.js";
4
4
  import { jsx as n } from "react/jsx-runtime";
5
5
  // src/components/DataTable/summary/SummaryImage.tsx
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { t as e } from "./ChartImageMenu-CuuFnW9q.js";
2
+ import { t as e } from "./ChartImageMenu-C6MwKKjc.js";
3
3
  import { t } from "./ChartView-nS4f4EU_.js";
4
4
  import { J as n, Tt as r, U as i, ot as a } from "./geometry-ChwYB45B.js";
5
5
  import { n as o, o as s, s as c } from "./scrollArea-DAlVT5U7.js";
@@ -0,0 +1 @@
1
+ const e=()=>new DOMException(`Aborted`,`AbortError`);async function t(t,n){if(n.signal?.aborted)throw e();switch(t.kind){case`xlsx`:return l(t.workbook,n);case`pdf`:return p(t,n);default:throw Error(`Unknown file task: ${t.kind}`)}}const n=globalThis;async function r(){let e=await import(`exceljs`),t=[e.default?.default,e.default,e,n.ExcelJS].find(e=>e&&typeof e.Workbook==`function`);if(!t)throw Error(`ExcelJS did not load`);return t}async function i(){let e=await import(`pdfmake/build/pdfmake.js`),t=[e.default?.default,e.default,e,n.pdfMake].find(e=>e&&typeof e.createPdf==`function`);if(!t)throw Error(`pdfmake did not load`);let r=await import(`pdfmake/build/vfs_fonts.js`);return{pdfMake:t,vfs:[r?.default,r,r?.pdfMake?.vfs,r?.default?.pdfMake?.vfs,t.vfs,n.pdfMake?.vfs].find(e=>e&&e[`Roboto-Regular.ttf`])}}const a=e=>ArrayBuffer.isView(e)?e.buffer.slice(e.byteOffset,e.byteOffset+e.byteLength):e,o=e=>`FF`+e.replace(`#`,``).toUpperCase();function s(e,t){if(t&&((t.bold!==void 0||t.italic!==void 0||t.size||t.color)&&(e.font={...e.font??{},...t.bold===void 0?{}:{bold:t.bold},...t.italic===void 0?{}:{italic:t.italic},...t.size?{size:t.size}:{},...t.color?{color:{argb:o(t.color)}}:{}}),t.fill&&(e.fill={type:`pattern`,pattern:`solid`,fgColor:{argb:o(t.fill)}}),t.align&&(e.alignment={horizontal:t.align,vertical:`middle`}),t.numFmt&&(typeof e.value==`number`||e.value instanceof Date)&&(e.numFmt=t.numFmt),t.borderTop||t.borderBottom)){let n=e=>({style:e.style,...e.color?{color:{argb:o(e.color)}}:{}});e.border={...t.borderTop?{top:n(t.borderTop)}:{},...t.borderBottom?{bottom:n(t.borderBottom)}:{}}}}function c(e,t,n){let r=e.addRow(t.values);t.style?.bold&&(r.font={bold:!0}),t.merge&&n>1&&e.mergeCells(r.number,1,r.number,n);let i=t.merge?1:Math.max(t.values.length,0);for(let e=0;e<i;e++){let n=r.getCell(e+1);s(n,t.style),s(n,t.cells?.[e])}}async function l(t,n){let i=new(await(r())).Workbook,l=Math.max(1,t.sheets.reduce((e,t)=>e+t.rows.length,0)),u=Math.max(1,Math.floor(l/50)),d=0;for(let r of t.sheets){let t=i.addWorksheet(r.name),a=r.columns.length;t.columns=r.columns.map((e,t)=>({key:String(t),width:e.width}));for(let e of r.before??[])c(t,e,a);let f=t.addRow(r.columns.map(e=>e.header));f.font={bold:r.headerStyle?.bold??!0},f.eachCell((e,t)=>{let n=r.columns[t-1]?.align;n&&(e.alignment={horizontal:n,vertical:`middle`}),s(e,r.headerStyle)});let p=f.number;r.freeze?t.views=[{state:`frozen`,ySplit:r.freeze.rows??0,xSplit:r.freeze.cols??0}]:r.freezeHeader!==!1&&(t.views=[{state:`frozen`,ySplit:p}]),r.rows.forEach((i,a)=>{let c=t.addRow(i),f=r.cellStyles?.[a],p=r.stripe&&a%2==1;if(r.columns.forEach((e,t)=>{let n=c.getCell(t+1);e.numFmt&&(typeof n.value==`number`||n.value instanceof Date)&&(n.numFmt=e.numFmt),e.align&&(n.alignment={horizontal:e.align,vertical:`middle`}),p&&(n.fill={type:`pattern`,pattern:`solid`,fgColor:{argb:o(r.stripe)}}),s(n,e.style),s(n,f?.[t])}),++d%u===0){if(n.signal?.aborted)throw e();n.progress(d/l*.9)}}),r.autoFilter&&r.rows.length>0&&(t.autoFilter={from:{row:p,column:1},to:{row:p,column:a}});for(let e of r.after??[])c(t,e,a)}let f=await i.xlsx.writeBuffer();return n.progress(1),a(f)}const u={Roboto:{normal:`Roboto-Regular.ttf`,bold:`Roboto-Medium.ttf`,italics:`Roboto-Italic.ttf`,bolditalics:`Roboto-MediumItalic.ttf`}};function d(e){let t=e.hLineWidth??1,n=e.edgeLineWidth??t;return{hLineWidth:(e,r)=>e===0||e===(r.table.headerRows??0)||e===r.table.body.length?n:t,vLineWidth:()=>e.vLineWidth??1,...e.hLineColor?{hLineColor:()=>e.hLineColor}:{},...e.vLineColor?{vLineColor:()=>e.vLineColor}:{},...e.paddingX===void 0?{}:{paddingLeft:()=>e.paddingX,paddingRight:()=>e.paddingX},...e.paddingY===void 0?{}:{paddingTop:()=>e.paddingY,paddingBottom:()=>e.paddingY}}}function f(e){return(t,n)=>({text:e.text.replace(/\{page\}/g,String(t)).replace(/\{pages\}/g,String(n)),...e.font?{font:e.font}:{},alignment:e.alignment??`center`,fontSize:e.fontSize??8,...e.color?{color:e.color}:{},...e.margin?{margin:e.margin}:{}})}async function p(t,n){let r=n.pdfFonts?{fonts:{...n.pdfFonts.fonts,...t.fonts?.fonts},vfs:n.pdfFonts.vfs||t.fonts?.vfs?{...n.pdfFonts.vfs,...t.fonts?.vfs}:void 0}:t.fonts,a=t.footer?{...t.document,footer:f(t.footer)}:t.document,o=t.tableLayouts?Object.fromEntries(Object.entries(t.tableLayouts).map(([e,t])=>[e,d(t)])):void 0,{pdfMake:s,vfs:c}=await i();if(n.progress(.1),n.signal?.aborted)throw e();let l={...u,...r?.fonts??{}},p=r?.vfs?{...c??{},...r.vfs}:c,m=await new Promise((e,t)=>{try{let n=s.createPdf(a,o,l,p).getStream(),r=[];n.on(`data`,e=>r.push(e)),n.on(`error`,t),n.on(`end`,()=>{let t=new Uint8Array(r.reduce((e,t)=>e+t.byteLength,0)),n=0;for(let e of r)t.set(e,n),n+=e.byteLength;e(t.buffer)}),n.end()}catch(e){t(e)}});return n.progress(1),m}let m;const h=self;h.onmessage=async e=>{if(e.data.type===`init`){m=e.data.pdfFonts;return}let{id:n,task:r}=e.data;try{let e=await t(r,{progress:e=>h.postMessage({type:`progress`,id:n,fraction:e}),pdfFonts:m});h.postMessage({type:`done`,id:n,buffer:e},[e])}catch(e){h.postMessage({type:`error`,id:n,message:e instanceof Error?e.message:String(e)})}};