@svgrid/enterprise 3.1.1 → 3.1.3

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.
Files changed (37) hide show
  1. package/dist/SvSheet.svelte +7 -1
  2. package/dist/cdn/svgrid-enterprise.svelte-external.js +10535 -10333
  3. package/dist/designer/assets/{index-DkhD2kIe.js → index-CScGnzuX.js} +312 -312
  4. package/dist/designer/assets/{src-Mu7AGqT8.js → src-DL33yzkY.js} +3 -3
  5. package/dist/designer/assets/validate-YxSrBF1H.js +1 -0
  6. package/dist/designer/index.html +2 -2
  7. package/dist/index.d.ts +2 -2
  8. package/dist/index.js +1 -1
  9. package/dist/license.js +2 -2
  10. package/dist/node/studio.js +16 -4
  11. package/dist/server/index.d.ts +1 -0
  12. package/dist/server/index.js +1 -0
  13. package/dist/server/server-row-model.d.ts +9 -0
  14. package/dist/server/server-row-model.js +120 -3
  15. package/dist/server/worker-data-source.d.ts +62 -0
  16. package/dist/server/worker-data-source.js +133 -0
  17. package/dist/studio/emit-project.js +8 -3
  18. package/dist/sveltekit/in-memory.d.ts +21 -1
  19. package/dist/sveltekit/in-memory.js +153 -105
  20. package/dist/sveltekit/index.d.ts +1 -1
  21. package/dist/version.d.ts +14 -1
  22. package/dist/version.js +14 -1
  23. package/dist/watermark.js +6 -3
  24. package/dist/wc/sv-sheet-element.js +18 -13
  25. package/dist/wc/{validate-BqDthkNr.js → validate-JAuMsk6Z.js} +36 -36
  26. package/dist/worker/columnar.d.ts +42 -0
  27. package/dist/worker/columnar.js +410 -0
  28. package/dist/worker/index.d.ts +12 -0
  29. package/dist/worker/index.js +12 -0
  30. package/dist/worker/infer-schema.d.ts +21 -0
  31. package/dist/worker/infer-schema.js +34 -0
  32. package/dist/worker/protocol.d.ts +73 -0
  33. package/dist/worker/protocol.js +14 -0
  34. package/dist/worker/serve.d.ts +44 -0
  35. package/dist/worker/serve.js +100 -0
  36. package/package.json +7 -3
  37. package/dist/designer/assets/validate-C3B8QKsM.js +0 -1
@@ -1,6 +1,6 @@
1
1
  const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./jszip.min-CX2fPs3O.js","./rolldown-runtime-Dd_uD5pT.js","./pdfmake-BpIYFHoG.js","./vfs_fonts-BV-Ul9v2.js","./src-CITpcm6b.js","./chart-export-B6bkQ3X8.js"])))=>i.map(i=>d[i]);
2
- import{i as e,n as t}from"./rolldown-runtime-Dd_uD5pT.js";import{a as n,c as r,d as i,i as a,l as o,n as s,o as c,s as l,t as u,u as d}from"./export-format-DGscOjS9.js";import{t as f}from"./preload-helper-HclGiUj8.js";var p={arrows:[`↓`,`→`,`↑`],traffic:[`🔴`,`🟡`,`🟢`],triangles:[`▼`,`◆`,`▲`]};function m(e){let t=1/0,n=-1/0,r=!1;for(let i of e){if(i==null||i===``)continue;let e=Number(i);Number.isFinite(e)&&(r=!0,e<t&&(t=e),e>n&&(n=e))}return r?{min:t,max:n}:null}function h(e,t,n){let r=0;for(let e=0;e<t.length;e+=1)n>=t[e]&&(r=e+1);return e[Math.min(e.length-1,Math.max(0,r))]??e[e.length-1]}function g(e){return e<0?0:e>1?1:e}function _(e){let t=/^#?([0-9a-f]{6})$/i.exec(e.trim());if(!t)return null;let n=parseInt(t[1],16);return[n>>16&255,n>>8&255,n&255]}function v(e){return`#`+e.map(e=>Math.round(g(e/255)*255).toString(16).padStart(2,`0`)).join(``)}function y(e){let t=_(e);if(!t)return null;let n=t.map(e=>{let t=e/255;return t<=.03928?t/12.92:((t+.055)/1.055)**2.4});return .2126*n[0]+.7152*n[1]+.0722*n[2]>.45?`#1e293b`:`#ffffff`}function b(e,t,n){let r=_(e),i=_(t);if(!r||!i)return e;let a=g(n);return v([r[0]+(i[0]-r[0])*a,r[1]+(i[1]-r[1])*a,r[2]+(i[2]-r[2])*a])}function x(e,t){let n=_(e);return n?`rgba(${n[0]}, ${n[1]}, ${n[2]}, ${g(t).toFixed(3)})`:e}function ee(e,t){let n=[...e].sort((e,t)=>e.offset-t.offset);if(n.length===0)return`#000000`;if(t<=n[0].offset)return n[0].color;let r=n[n.length-1];if(t>=r.offset)return r.color;for(let e=0;e<n.length-1;e+=1){let r=n[e],i=n[e+1];if(t>=r.offset&&t<=i.offset){let e=i.offset-r.offset||1;return b(r.color,i.color,(t-r.offset)/e)}}return r.color}function te(e,t){if(e.stops&&e.stops.length>=2)return ee(e.stops,t);let n=e.min??`#ffffff`,r=e.max??`#000000`;return e.mid?t<=.5?b(n,e.mid,t/.5):b(e.mid,r,(t-.5)/.5):b(n,r,t)}function S(e,t,n,r){let i;if(e.compareColumn){let r=Number(n?.[e.compareColumn]);if(!Number.isFinite(r)||r===0)return null;i=g(t/r)}else if(e.type===`colorScale`&&e.zeroCentred){let n=e.minValue??r?.min??t,a=e.maxValue??r?.max??t;i=g(.5+t/(Math.max(Math.abs(n),Math.abs(a))||1)/2)}else{let n=r?.min??t,a=r?.max??t,o,s;if(e.bounds===`percent`){let t=a-n;o=n+(e.minValue??0)/100*t,s=n+(e.maxValue??100)/100*t}else o=e.minValue??n,s=e.maxValue??a;i=s===o?.5:g((t-o)/(s-o))}return e.type===`colorScale`&&e.reverse&&(i=1-i),i}function ne(e,t,n,r,i){let a={};for(let o of r){if(o.columns&&!o.columns.includes(n))continue;let r=Number(e);if(o.type===`rule`){if(o.when({value:e,row:t})){if(o.background&&(a.background=o.background,!o.color)){let e=y(o.background);e&&(a.color=e)}o.color&&(a.color=o.color),o.fontWeight!=null&&(a.fontWeight=o.fontWeight),o.icon&&(a.icon=o.icon)}continue}if(!(e==null||e===``||!Number.isFinite(r))){if(o.type===`colorScale`){let n=S(o,r,t,i);if(n==null)continue;if(o.mode===`alpha`){let[e,t]=o.alphaBounds??[.05,.85];a.background=x(o.base??`#2563eb`,e+(t-e)*n)}else{a.background=te(o,n);let e=y(a.background);e&&(a.color=e)}o.tooltip===`value`?a.title=String(e):o.tooltip===`percent`&&(a.title=`${Math.round(n*100)}%`)}else if(o.type===`dataBar`){let e;if(o.compareColumn){let n=S(o,r,t,i);if(n==null)continue;e=n*100}else if(o.bounds===`percent`){let n=S(o,r,t,i);if(n==null)continue;e=n*100}else{let t=o.minValue??Math.min(0,i?.min??0),n=(o.maxValue??i?.max??r)-t||1;e=g((r-t)/n)*100}a.dataBar={percent:e,color:r<0?o.negativeColor??`#ef4444`:o.color,fromRight:!1,gradient:o.gradient},o.showValue===!1&&(a.color=`transparent`)}else if(o.type===`iconSet`){let e=p[o.set??`arrows`];a.icon=h(e,o.thresholds,r),o.iconOnly&&(a.iconOnly=!0)}}}return a}function C(e){return(e.type===`colorScale`||e.type===`dataBar`)&&!(`compareColumn`in e&&e.compareColumn)}function re(e){return e.some(C)}var w=new Set([]),T=`SVENTERPRISE-`;function ie(e,t){return e===`suite`||t===`grid`}function E(e){if(!e)return null;let t=e.split(`-`);if(t.length<3)return null;let n=t[t.length-2];if(n==null)return null;if(/^\d{6}$/.test(n)){let e=Number(n.slice(0,4)),t=Number(n.slice(4,6));return t<1||t>12?null:new Date(Date.UTC(e,t,1)-1)}if(/^\d{8}$/.test(n)){let e=Number(n.slice(0,4)),t=Number(n.slice(4,6)),r=Number(n.slice(6,8));if(t<1||t>12||r<1||r>31)return null;let i=new Date(Date.UTC(e,t-1,r,23,59,59,999));return i.getUTCMonth()===t-1?i:null}return null}function D(e,t=new Date){if(e==null||e===``)return{status:`unset`,valid:!1,edition:`suite`};if(!e.startsWith(`SVENTERPRISE-`))return{status:`invalid`,valid:!1,edition:`suite`};if(w.has(e))return{status:`revoked`,valid:!1,edition:`suite`};let n=E(e)??void 0,r=n?t.getTime()>n.getTime():void 0,i=e.startsWith(`SVENTERPRISE-DEV`)?`dev`:e.startsWith(`SVENTERPRISE-EVAL`)?`eval`:`licensed`;return{status:i,valid:!0,edition:i===`licensed`&&e.startsWith(`SVENTERPRISE-GRID-`)?`grid`:`suite`,expiresAt:n,expired:r}}var O=`data-svgrid-enterprise-watermark`,k=`data-svgrid-enterprise-nudged`,ae=`https://svgrid.com`,A=`www.svgrid.com`,j=5e3,M=700,oe=!1,N=null;function P(){se(),!(typeof document>`u`||typeof window>`u`)&&(queueMicrotask(()=>ce()),N||(N=new MutationObserver(()=>ce()),N.observe(document.body,{childList:!0,subtree:!0})))}function se(){oe||(oe=!0,!(typeof console>`u`)&&console.log(`%c @svgrid/enterprise %c User is using a Commercial version which requires a license.
3
- Contact sales@jqwidgets.com for details or visit the license page: https://svgrid.com/pricing/`,`background:#4f46e5;color:#fff;padding:2px 6px;border-radius:3px;font-weight:600`,`color:inherit`))}function ce(){if(typeof document>`u`)return;let e=document.querySelectorAll(`.sv-grid-root, [role="grid"]`);if(e.length===0){de();return}document.querySelectorAll(`[${O}="fixed"]`).forEach(e=>e.remove());let t=new Set;e.forEach(e=>{let n=le(e);n&&t.add(n)}),t.forEach(ue)}function le(e){let t=e.closest(`.sv-grid-root`);if(t)return t;let n=e;for(;n&&/^(TABLE|THEAD|TBODY|TFOOT|TR|COLGROUP)$/.test(n.tagName);)n=n.parentElement;return n}function ue(e){if(e.hasAttribute(k))return;e.setAttribute(k,`1`),getComputedStyle(e).position===`static`&&(e.style.position=`relative`);let t=fe(`grid`);me(t,!1),e.appendChild(t),pe(t)}function de(){if(typeof document>`u`||document.querySelector(`[${O}="fixed"]`))return;let e=fe(`fixed`);me(e,!0),document.body.appendChild(e),pe(e)}function fe(e){let t=document.createElement(`a`);return t.setAttribute(O,e),t.href=ae,t.target=`_blank`,t.rel=`noopener noreferrer`,t.textContent=A,t.title=`Unlicensed @svgrid/enterprise. Contact sales@jqwidgets.com or visit www.svgrid.com.`,t}function pe(e){if(typeof window>`u`){e.remove();return}window.setTimeout(()=>{if(typeof window>`u`){e.remove();return}e.style.opacity=`0`,window.setTimeout(()=>e.remove(),M)},j)}function me(e,t){Object.assign(e.style,{position:t?`fixed`:`absolute`,bottom:t?`12px`:`6px`,right:t?`12px`:`8px`,zIndex:`2147483647`,background:`rgba(15,23,42,0.85)`,color:`#fff`,padding:t?`6px 10px`:`4px 8px`,borderRadius:t?`4px`:`3px`,fontFamily:`-apple-system, "Segoe UI", Roboto, sans-serif`,fontSize:t?`11px`:`10px`,lineHeight:`1.2`,textDecoration:`none`,boxShadow:t?`0 2px 12px rgba(0,0,0,0.35)`:`0 1px 4px rgba(0,0,0,0.3)`,border:`1px solid rgba(255,255,255,0.18)`,pointerEvents:`auto`,letterSpacing:`0.02em`,opacity:`1`,transition:`opacity ${M}ms ease`})}var he=`data-svgrid-enterprise-upgrade`,ge=`https://svgrid.com/pricing`,_e=`https://svgrid.com/pricing?ref=in-app&utm_source=svgrid-enterprise&utm_medium=upgrade-prompt`,ve=!1;function F(e,t){if(ve||typeof document>`u`||typeof window>`u`||document.querySelector(`[${he}]`))return;ve=!0;let n=ye(e,t?.expired===!0);document.body.appendChild(n),requestAnimationFrame(()=>{n.style.opacity=`1`,n.style.transform=`translateY(0)`})}function I(e){e.style.opacity=`0`,e.style.transform=`translateY(8px)`,window.setTimeout(()=>e.remove(),220)}function ye(e,t=!1){let n=document.createElement(`div`);n.setAttribute(he,`1`),n.setAttribute(`role`,`dialog`),n.setAttribute(`aria-label`,t?`Your trial has ended`:`Unlock SvGrid Pro`),Object.assign(n.style,{position:`fixed`,bottom:`16px`,right:`16px`,zIndex:`2147483646`,width:`320px`,maxWidth:`calc(100vw - 32px)`,boxSizing:`border-box`,padding:`16px 16px 14px`,background:`#0f172a`,color:`#e2e8f0`,borderRadius:`12px`,border:`1px solid rgba(99,102,241,0.4)`,boxShadow:`0 12px 40px rgba(0,0,0,0.45)`,fontFamily:`-apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif`,fontSize:`13px`,lineHeight:`1.45`,opacity:`0`,transform:`translateY(8px)`,transition:`opacity 220ms ease, transform 220ms ease`});let r=e?`<strong style="color:#fff">${be(e?String(e):`This`)}</strong> is a Pro feature.`:`You just used a <strong style="color:#fff">Pro</strong> feature.`,i=t?`TRIAL ENDED`:`PRO`,a=t?`Your trial has ended`:`Unlock SvGrid Pro`,o=t?`${r} Your evaluation period is over - everything still works,
2
+ import{i as e,n as t}from"./rolldown-runtime-Dd_uD5pT.js";import{a as n,c as r,d as i,i as a,l as o,n as s,o as c,s as l,t as u,u as d}from"./export-format-DGscOjS9.js";import{t as f}from"./preload-helper-HclGiUj8.js";var p={arrows:[`↓`,`→`,`↑`],traffic:[`🔴`,`🟡`,`🟢`],triangles:[`▼`,`◆`,`▲`]};function m(e){let t=1/0,n=-1/0,r=!1;for(let i of e){if(i==null||i===``)continue;let e=Number(i);Number.isFinite(e)&&(r=!0,e<t&&(t=e),e>n&&(n=e))}return r?{min:t,max:n}:null}function h(e,t,n){let r=0;for(let e=0;e<t.length;e+=1)n>=t[e]&&(r=e+1);return e[Math.min(e.length-1,Math.max(0,r))]??e[e.length-1]}function g(e){return e<0?0:e>1?1:e}function _(e){let t=/^#?([0-9a-f]{6})$/i.exec(e.trim());if(!t)return null;let n=parseInt(t[1],16);return[n>>16&255,n>>8&255,n&255]}function v(e){return`#`+e.map(e=>Math.round(g(e/255)*255).toString(16).padStart(2,`0`)).join(``)}function y(e){let t=_(e);if(!t)return null;let n=t.map(e=>{let t=e/255;return t<=.03928?t/12.92:((t+.055)/1.055)**2.4});return .2126*n[0]+.7152*n[1]+.0722*n[2]>.45?`#1e293b`:`#ffffff`}function b(e,t,n){let r=_(e),i=_(t);if(!r||!i)return e;let a=g(n);return v([r[0]+(i[0]-r[0])*a,r[1]+(i[1]-r[1])*a,r[2]+(i[2]-r[2])*a])}function x(e,t){let n=_(e);return n?`rgba(${n[0]}, ${n[1]}, ${n[2]}, ${g(t).toFixed(3)})`:e}function ee(e,t){let n=[...e].sort((e,t)=>e.offset-t.offset);if(n.length===0)return`#000000`;if(t<=n[0].offset)return n[0].color;let r=n[n.length-1];if(t>=r.offset)return r.color;for(let e=0;e<n.length-1;e+=1){let r=n[e],i=n[e+1];if(t>=r.offset&&t<=i.offset){let e=i.offset-r.offset||1;return b(r.color,i.color,(t-r.offset)/e)}}return r.color}function te(e,t){if(e.stops&&e.stops.length>=2)return ee(e.stops,t);let n=e.min??`#ffffff`,r=e.max??`#000000`;return e.mid?t<=.5?b(n,e.mid,t/.5):b(e.mid,r,(t-.5)/.5):b(n,r,t)}function S(e,t,n,r){let i;if(e.compareColumn){let r=Number(n?.[e.compareColumn]);if(!Number.isFinite(r)||r===0)return null;i=g(t/r)}else if(e.type===`colorScale`&&e.zeroCentred){let n=e.minValue??r?.min??t,a=e.maxValue??r?.max??t;i=g(.5+t/(Math.max(Math.abs(n),Math.abs(a))||1)/2)}else{let n=r?.min??t,a=r?.max??t,o,s;if(e.bounds===`percent`){let t=a-n;o=n+(e.minValue??0)/100*t,s=n+(e.maxValue??100)/100*t}else o=e.minValue??n,s=e.maxValue??a;i=s===o?.5:g((t-o)/(s-o))}return e.type===`colorScale`&&e.reverse&&(i=1-i),i}function ne(e,t,n,r,i){let a={};for(let o of r){if(o.columns&&!o.columns.includes(n))continue;let r=Number(e);if(o.type===`rule`){if(o.when({value:e,row:t})){if(o.background&&(a.background=o.background,!o.color)){let e=y(o.background);e&&(a.color=e)}o.color&&(a.color=o.color),o.fontWeight!=null&&(a.fontWeight=o.fontWeight),o.icon&&(a.icon=o.icon)}continue}if(!(e==null||e===``||!Number.isFinite(r))){if(o.type===`colorScale`){let n=S(o,r,t,i);if(n==null)continue;if(o.mode===`alpha`){let[e,t]=o.alphaBounds??[.05,.85];a.background=x(o.base??`#2563eb`,e+(t-e)*n)}else{a.background=te(o,n);let e=y(a.background);e&&(a.color=e)}o.tooltip===`value`?a.title=String(e):o.tooltip===`percent`&&(a.title=`${Math.round(n*100)}%`)}else if(o.type===`dataBar`){let e;if(o.compareColumn){let n=S(o,r,t,i);if(n==null)continue;e=n*100}else if(o.bounds===`percent`){let n=S(o,r,t,i);if(n==null)continue;e=n*100}else{let t=o.minValue??Math.min(0,i?.min??0),n=(o.maxValue??i?.max??r)-t||1;e=g((r-t)/n)*100}a.dataBar={percent:e,color:r<0?o.negativeColor??`#ef4444`:o.color,fromRight:!1,gradient:o.gradient},o.showValue===!1&&(a.color=`transparent`)}else if(o.type===`iconSet`){let e=p[o.set??`arrows`];a.icon=h(e,o.thresholds,r),o.iconOnly&&(a.iconOnly=!0)}}}return a}function C(e){return(e.type===`colorScale`||e.type===`dataBar`)&&!(`compareColumn`in e&&e.compareColumn)}function re(e){return e.some(C)}var w=new Set([]),T=`SVENTERPRISE-`;function ie(e,t){return e===`suite`||t===`grid`}function E(e){if(!e)return null;let t=e.split(`-`);if(t.length<3)return null;let n=t[t.length-2];if(n==null)return null;if(/^\d{6}$/.test(n)){let e=Number(n.slice(0,4)),t=Number(n.slice(4,6));return t<1||t>12?null:new Date(Date.UTC(e,t,1)-1)}if(/^\d{8}$/.test(n)){let e=Number(n.slice(0,4)),t=Number(n.slice(4,6)),r=Number(n.slice(6,8));if(t<1||t>12||r<1||r>31)return null;let i=new Date(Date.UTC(e,t-1,r,23,59,59,999));return i.getUTCMonth()===t-1?i:null}return null}function D(e,t=new Date){if(e==null||e===``)return{status:`unset`,valid:!1,edition:`suite`};if(!e.startsWith(`SVENTERPRISE-`))return{status:`invalid`,valid:!1,edition:`suite`};if(w.has(e))return{status:`revoked`,valid:!1,edition:`suite`};let n=E(e)??void 0,r=n?t.getTime()>n.getTime():void 0,i=e.startsWith(`SVENTERPRISE-DEV`)?`dev`:e.startsWith(`SVENTERPRISE-EVAL`)?`eval`:`licensed`;return{status:i,valid:!0,edition:i===`licensed`&&e.startsWith(`SVENTERPRISE-GRID-`)?`grid`:`suite`,expiresAt:n,expired:r}}var O=`data-svgrid-enterprise-watermark`,k=`data-svgrid-enterprise-nudged`,ae=`https://svgrid.com/pricing/?utm_source=svgrid-enterprise&utm_medium=watermark`,A=`www.svgrid.com`,j=5e3,M=700,oe=!1,N=null;function P(){se(),!(typeof document>`u`||typeof window>`u`)&&(queueMicrotask(()=>ce()),N||(N=new MutationObserver(()=>ce()),N.observe(document.body,{childList:!0,subtree:!0})))}function se(){oe||(oe=!0,!(typeof console>`u`)&&console.log(`%c @svgrid/enterprise %c User is using a Commercial version which requires a license.
3
+ Contact sales@jqwidgets.com for details or visit the license page: https://svgrid.com/pricing/?utm_source=svgrid-enterprise&utm_medium=console`,`background:#4f46e5;color:#fff;padding:2px 6px;border-radius:3px;font-weight:600`,`color:inherit`))}function ce(){if(typeof document>`u`)return;let e=document.querySelectorAll(`.sv-grid-root, [role="grid"]`);if(e.length===0){de();return}document.querySelectorAll(`[${O}="fixed"]`).forEach(e=>e.remove());let t=new Set;e.forEach(e=>{let n=le(e);n&&t.add(n)}),t.forEach(ue)}function le(e){let t=e.closest(`.sv-grid-root`);if(t)return t;let n=e;for(;n&&/^(TABLE|THEAD|TBODY|TFOOT|TR|COLGROUP)$/.test(n.tagName);)n=n.parentElement;return n}function ue(e){if(e.hasAttribute(k))return;e.setAttribute(k,`1`),getComputedStyle(e).position===`static`&&(e.style.position=`relative`);let t=fe(`grid`);me(t,!1),e.appendChild(t),pe(t)}function de(){if(typeof document>`u`||document.querySelector(`[${O}="fixed"]`))return;let e=fe(`fixed`);me(e,!0),document.body.appendChild(e),pe(e)}function fe(e){let t=document.createElement(`a`);return t.setAttribute(O,e),t.href=ae,t.target=`_blank`,t.rel=`noopener noreferrer`,t.textContent=A,t.title=`Unlicensed @svgrid/enterprise. Contact sales@jqwidgets.com or visit www.svgrid.com.`,t}function pe(e){if(typeof window>`u`){e.remove();return}window.setTimeout(()=>{if(typeof window>`u`){e.remove();return}e.style.opacity=`0`,window.setTimeout(()=>e.remove(),M)},j)}function me(e,t){Object.assign(e.style,{position:t?`fixed`:`absolute`,bottom:t?`12px`:`6px`,right:t?`12px`:`8px`,zIndex:`2147483647`,background:`rgba(15,23,42,0.85)`,color:`#fff`,padding:t?`6px 10px`:`4px 8px`,borderRadius:t?`4px`:`3px`,fontFamily:`-apple-system, "Segoe UI", Roboto, sans-serif`,fontSize:t?`11px`:`10px`,lineHeight:`1.2`,textDecoration:`none`,boxShadow:t?`0 2px 12px rgba(0,0,0,0.35)`:`0 1px 4px rgba(0,0,0,0.3)`,border:`1px solid rgba(255,255,255,0.18)`,pointerEvents:`auto`,letterSpacing:`0.02em`,opacity:`1`,transition:`opacity ${M}ms ease`})}var he=`data-svgrid-enterprise-upgrade`,ge=`https://svgrid.com/pricing`,_e=`https://svgrid.com/pricing?ref=in-app&utm_source=svgrid-enterprise&utm_medium=upgrade-prompt`,ve=!1;function F(e,t){if(ve||typeof document>`u`||typeof window>`u`||document.querySelector(`[${he}]`))return;ve=!0;let n=ye(e,t?.expired===!0);document.body.appendChild(n),requestAnimationFrame(()=>{n.style.opacity=`1`,n.style.transform=`translateY(0)`})}function I(e){e.style.opacity=`0`,e.style.transform=`translateY(8px)`,window.setTimeout(()=>e.remove(),220)}function ye(e,t=!1){let n=document.createElement(`div`);n.setAttribute(he,`1`),n.setAttribute(`role`,`dialog`),n.setAttribute(`aria-label`,t?`Your trial has ended`:`Unlock SvGrid Pro`),Object.assign(n.style,{position:`fixed`,bottom:`16px`,right:`16px`,zIndex:`2147483646`,width:`320px`,maxWidth:`calc(100vw - 32px)`,boxSizing:`border-box`,padding:`16px 16px 14px`,background:`#0f172a`,color:`#e2e8f0`,borderRadius:`12px`,border:`1px solid rgba(99,102,241,0.4)`,boxShadow:`0 12px 40px rgba(0,0,0,0.45)`,fontFamily:`-apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif`,fontSize:`13px`,lineHeight:`1.45`,opacity:`0`,transform:`translateY(8px)`,transition:`opacity 220ms ease, transform 220ms ease`});let r=e?`<strong style="color:#fff">${be(e?String(e):`This`)}</strong> is a Pro feature.`:`You just used a <strong style="color:#fff">Pro</strong> feature.`,i=t?`TRIAL ENDED`:`PRO`,a=t?`Your trial has ended`:`Unlock SvGrid Pro`,o=t?`${r} Your evaluation period is over - everything still works,
4
4
  but this notice stays until a licence key is set.`:`${r} It runs in evaluation with a watermark - start a free trial
5
5
  to remove it and ship to production.`;return n.innerHTML=`
6
6
  <button type="button" data-act="x" aria-label="Dismiss"
@@ -25,7 +25,7 @@ Contact sales@jqwidgets.com for details or visit the license page: https://svgri
25
25
  <p style="margin:10px 0 0;font-size:11px;color:#64748b;">
26
26
  Already licensed? Call <code style="color:#94a3b8;">setLicenseKey()</code> at startup to hide this.
27
27
  </p>
28
- `,n.querySelector(`[data-act="x"]`)?.addEventListener(`click`,()=>I(n)),n.querySelector(`[data-act="trial"]`)?.addEventListener(`click`,()=>I(n)),n.querySelector(`[data-act="pricing"]`)?.addEventListener(`click`,()=>I(n)),n}function be(e){return e.replace(/&/g,`&amp;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`).replace(/"/g,`&quot;`)}var L=null,xe=!1,Se=!1,Ce=new Set;function R(e){if(Se)return;Se=!0;let t=e.expiresAt?` on ${e.expiresAt.toISOString().slice(0,10)}`:``;console.info(`@svgrid/enterprise: your evaluation license expired${t}. Everything still works, but the watermark and upgrade notice stay until a license key is set. Contact sales@jqwidgets.com or see https://svgrid.com/pricing`)}function we(){return L!=null}function Te(e){let t=D(L);if(t.valid&&!t.expired)return;let n=t.valid&&t.expired===!0;P(),n&&R(t),F(e,{expired:n})}var Ee={grid:`the enterprise grid`,spreadsheet:`the spreadsheet`,studio:`the Studio`};function De(e){Ce.has(e)||(Ce.add(e),console.info(`@svgrid/enterprise: your Grid license does not cover ${Ee[e]}. Everything still works, but the watermark and upgrade notice stay until the license is upgraded to Suite. Contact sales@jqwidgets.com or see https://svgrid.com/pricing`))}function Oe(e,t){let n=D(L),r=n.valid&&ie(n.edition,e);if(r&&!n.expired)return;let i=n.valid&&n.expired!==!0&&!r;P(),i?De(e):n.valid&&n.expired===!0&&R(n),F(t,{expired:n.valid&&n.expired===!0})}function ke(e){let t=D(L);switch(t.status){case`unset`:P(),F(e);return;case`invalid`:throw Error(`@svgrid/enterprise: invalid license key format (expected "${T}..." prefix).`);case`revoked`:throw Error(`@svgrid/enterprise: this license key has been revoked. Contact sales@jqwidgets.com for a replacement.`);case`dev`:case`eval`:if(t.expired){P(),R(t),F(e,{expired:!0});return}xe||=(console.info(`@svgrid/enterprise: using a development / evaluation license. Not for production use.`),!0);return;case`licensed`:return}}var Ae=!1;function je(){if(Ae)return;if(typeof window>`u`)throw Error(`@svgrid/enterprise: installSmartShim() requires a browser environment`);let e=window.Smart??{Utilities:{}};e.Utilities=e.Utilities??{},typeof e.Utilities.Assign!=`function`&&(e.Utilities.Assign=(t,n)=>{e.Utilities[t]=n}),(!e.Utilities.Core||typeof e.Utilities.Core.toDash!=`function`)&&(e.Utilities.Core={toDash:e=>e.replace(/[A-Z]/g,e=>`-`+e.toLowerCase())}),window.Smart=e,Ae=!0}var Me=/[\x00-\x08\x0B\x0C\x0E-\x1F]/g;function z(e){return e.replace(Me,``).replace(/&/g,`&amp;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`).replace(/"/g,`&quot;`)}function Ne(e){let t=(e,t=2)=>String(e).padStart(t,`0`);return`${e.getFullYear()}-${t(e.getMonth()+1)}-${t(e.getDate())}T${t(e.getHours())}:${t(e.getMinutes())}:${t(e.getSeconds())}.000`}async function Pe(e,t,n,r={}){let o=Math.max(1,r.chunkRows??5e3),s=n.length,c=r.rawValues===!0,l=r.cellVisual,u=r.precisionSafe===!0,f=new Map,p=[`<Style ss:ID="sHeader"><Font ss:Bold="1"/><Interior ss:Color="#F2F2F2" ss:Pattern="Solid"/></Style>`],m=e=>e===`right`?`Right`:e===`center`?`Center`:`Left`,h=e=>{let t=e.align&&e.align!==`left`;if(!e.numFmt&&!e.fill&&!e.color&&!e.bold&&!t)return;let n=`${e.numFmt??``}|${e.fill??``}|${e.color??``}|${e.bold?`b`:``}|${e.align??``}`,r=f.get(n);if(r)return r;let i=`s${f.size+1}`,a=[];return t&&a.push(`<Alignment ss:Horizontal="${m(e.align)}"/>`),(e.color||e.bold)&&a.push(`<Font${e.color?` ss:Color="${e.color}"`:``}${e.bold?` ss:Bold="1"`:``}/>`),e.fill&&a.push(`<Interior ss:Color="${e.fill}" ss:Pattern="Solid"/>`),e.numFmt&&a.push(`<NumberFormat ss:Format="${z(e.numFmt)}"/>`),p.push(`<Style ss:ID="${i}">${a.join(``)}</Style>`),f.set(n,i),i};function g(e,t,n,r){let o=e.link?.(t)||void 0,s=l?.(n,r),f=t=>h({numFmt:t,fill:s?.fill,color:s?.color,bold:s?.bold,align:e.align});if(e.exportValue){let n=e.exportValue(t),r=n==null?``:String(n);return{type:`String`,value:s?.icon?`${s.icon} ${r}`:r,styleId:f(),href:o}}let p=t[e.field];if(s?.icon){let t=c?String(p??``):a(p,e.format);return{type:`String`,value:`${s.icon} ${t}`,styleId:f(),href:o}}let m=e=>u&&Math.abs(e)>=0x38d7ea4c68000;if(c){let e=p==null?``:String(p);return typeof p==`number`&&Number.isFinite(p)&&!m(p)?{type:`Number`,value:e,styleId:f(),href:o}:{type:`String`,value:e,styleId:f(),href:o}}let g=i(p,e.format);if(g.ok){let t=d(e.format);return g.value instanceof Date?{type:`DateTime`,value:Ne(g.value),styleId:f(t),href:o}:m(g.value)?{type:`String`,value:String(g.value),styleId:f(),href:o}:{type:`Number`,value:String(g.value),styleId:f(t),href:o}}return{type:`String`,value:a(p,e.format),styleId:f(),href:o}}let _=e=>`<Cell${e.styleId?` ss:StyleID="${e.styleId}"`:``}${e.href?` ss:HRef="${z(e.href)}"`:``}><Data ss:Type="${e.type}">${z(e.value)}</Data></Cell>`,v=r.widths?r.widths.map(e=>`<Column ss:Width="${Math.round(e*.75)}"/>`).join(``):``,y=Math.max(0,Math.floor(r.freezeColumns??0)),b=r.freezeHeader||y>0?`<WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel"><FreezePanes/><FrozenNoSplit/>`+(r.freezeHeader?`<SplitHorizontal>1</SplitHorizontal><TopRowBottomPane>1</TopRowBottomPane>`:``)+(y>0?`<SplitVertical>${y}</SplitVertical><LeftColumnRightPane>${y}</LeftColumnRightPane>`:``)+`<ActivePane>2</ActivePane></WorksheetOptions>`:``,x=[`<Row>${t.map(e=>`<Cell ss:StyleID="sHeader"><Data ss:Type="String">${z(e.header??e.field)}</Data></Cell>`).join(``)}</Row>`];for(let e=0;e<s;e++){if(r.signal?.aborted)throw new DOMException(`Export aborted`,`AbortError`);let i=n[e],a=t.map((t,n)=>_(g(t,i,e,n))).join(``);x.push(`<Row>${a}</Row>`),e>0&&e%o===0&&(r.onProgress?.({phase:`serialize`,ratio:e/s,row:e,total:s}),await new Promise(e=>setTimeout(e,0)))}return r.onProgress?.({phase:`serialize`,ratio:1,row:s,total:s}),`<?xml version="1.0"?>
28
+ `,n.querySelector(`[data-act="x"]`)?.addEventListener(`click`,()=>I(n)),n.querySelector(`[data-act="trial"]`)?.addEventListener(`click`,()=>I(n)),n.querySelector(`[data-act="pricing"]`)?.addEventListener(`click`,()=>I(n)),n}function be(e){return e.replace(/&/g,`&amp;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`).replace(/"/g,`&quot;`)}var L=null,xe=!1,Se=!1,Ce=new Set;function R(e){if(Se)return;Se=!0;let t=e.expiresAt?` on ${e.expiresAt.toISOString().slice(0,10)}`:``;console.info(`@svgrid/enterprise: your evaluation license expired${t}. Everything still works, but the watermark and upgrade notice stay until a license key is set. Contact sales@jqwidgets.com or see https://svgrid.com/pricing/?utm_source=svgrid-enterprise&utm_medium=console`)}function we(){return L!=null}function Te(e){let t=D(L);if(t.valid&&!t.expired)return;let n=t.valid&&t.expired===!0;P(),n&&R(t),F(e,{expired:n})}var Ee={grid:`the enterprise grid`,spreadsheet:`the spreadsheet`,studio:`the Studio`};function De(e){Ce.has(e)||(Ce.add(e),console.info(`@svgrid/enterprise: your Grid license does not cover ${Ee[e]}. Everything still works, but the watermark and upgrade notice stay until the license is upgraded to Suite. Contact sales@jqwidgets.com or see https://svgrid.com/pricing/?utm_source=svgrid-enterprise&utm_medium=console`))}function Oe(e,t){let n=D(L),r=n.valid&&ie(n.edition,e);if(r&&!n.expired)return;let i=n.valid&&n.expired!==!0&&!r;P(),i?De(e):n.valid&&n.expired===!0&&R(n),F(t,{expired:n.valid&&n.expired===!0})}function ke(e){let t=D(L);switch(t.status){case`unset`:P(),F(e);return;case`invalid`:throw Error(`@svgrid/enterprise: invalid license key format (expected "${T}..." prefix).`);case`revoked`:throw Error(`@svgrid/enterprise: this license key has been revoked. Contact sales@jqwidgets.com for a replacement.`);case`dev`:case`eval`:if(t.expired){P(),R(t),F(e,{expired:!0});return}xe||=(console.info(`@svgrid/enterprise: using a development / evaluation license. Not for production use.`),!0);return;case`licensed`:return}}var Ae=!1;function je(){if(Ae)return;if(typeof window>`u`)throw Error(`@svgrid/enterprise: installSmartShim() requires a browser environment`);let e=window.Smart??{Utilities:{}};e.Utilities=e.Utilities??{},typeof e.Utilities.Assign!=`function`&&(e.Utilities.Assign=(t,n)=>{e.Utilities[t]=n}),(!e.Utilities.Core||typeof e.Utilities.Core.toDash!=`function`)&&(e.Utilities.Core={toDash:e=>e.replace(/[A-Z]/g,e=>`-`+e.toLowerCase())}),window.Smart=e,Ae=!0}var Me=/[\x00-\x08\x0B\x0C\x0E-\x1F]/g;function z(e){return e.replace(Me,``).replace(/&/g,`&amp;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`).replace(/"/g,`&quot;`)}function Ne(e){let t=(e,t=2)=>String(e).padStart(t,`0`);return`${e.getFullYear()}-${t(e.getMonth()+1)}-${t(e.getDate())}T${t(e.getHours())}:${t(e.getMinutes())}:${t(e.getSeconds())}.000`}async function Pe(e,t,n,r={}){let o=Math.max(1,r.chunkRows??5e3),s=n.length,c=r.rawValues===!0,l=r.cellVisual,u=r.precisionSafe===!0,f=new Map,p=[`<Style ss:ID="sHeader"><Font ss:Bold="1"/><Interior ss:Color="#F2F2F2" ss:Pattern="Solid"/></Style>`],m=e=>e===`right`?`Right`:e===`center`?`Center`:`Left`,h=e=>{let t=e.align&&e.align!==`left`;if(!e.numFmt&&!e.fill&&!e.color&&!e.bold&&!t)return;let n=`${e.numFmt??``}|${e.fill??``}|${e.color??``}|${e.bold?`b`:``}|${e.align??``}`,r=f.get(n);if(r)return r;let i=`s${f.size+1}`,a=[];return t&&a.push(`<Alignment ss:Horizontal="${m(e.align)}"/>`),(e.color||e.bold)&&a.push(`<Font${e.color?` ss:Color="${e.color}"`:``}${e.bold?` ss:Bold="1"`:``}/>`),e.fill&&a.push(`<Interior ss:Color="${e.fill}" ss:Pattern="Solid"/>`),e.numFmt&&a.push(`<NumberFormat ss:Format="${z(e.numFmt)}"/>`),p.push(`<Style ss:ID="${i}">${a.join(``)}</Style>`),f.set(n,i),i};function g(e,t,n,r){let o=e.link?.(t)||void 0,s=l?.(n,r),f=t=>h({numFmt:t,fill:s?.fill,color:s?.color,bold:s?.bold,align:e.align});if(e.exportValue){let n=e.exportValue(t),r=n==null?``:String(n);return{type:`String`,value:s?.icon?`${s.icon} ${r}`:r,styleId:f(),href:o}}let p=t[e.field];if(s?.icon){let t=c?String(p??``):a(p,e.format);return{type:`String`,value:`${s.icon} ${t}`,styleId:f(),href:o}}let m=e=>u&&Math.abs(e)>=0x38d7ea4c68000;if(c){let e=p==null?``:String(p);return typeof p==`number`&&Number.isFinite(p)&&!m(p)?{type:`Number`,value:e,styleId:f(),href:o}:{type:`String`,value:e,styleId:f(),href:o}}let g=i(p,e.format);if(g.ok){let t=d(e.format);return g.value instanceof Date?{type:`DateTime`,value:Ne(g.value),styleId:f(t),href:o}:m(g.value)?{type:`String`,value:String(g.value),styleId:f(),href:o}:{type:`Number`,value:String(g.value),styleId:f(t),href:o}}return{type:`String`,value:a(p,e.format),styleId:f(),href:o}}let _=e=>`<Cell${e.styleId?` ss:StyleID="${e.styleId}"`:``}${e.href?` ss:HRef="${z(e.href)}"`:``}><Data ss:Type="${e.type}">${z(e.value)}</Data></Cell>`,v=r.widths?r.widths.map(e=>`<Column ss:Width="${Math.round(e*.75)}"/>`).join(``):``,y=Math.max(0,Math.floor(r.freezeColumns??0)),b=r.freezeHeader||y>0?`<WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel"><FreezePanes/><FrozenNoSplit/>`+(r.freezeHeader?`<SplitHorizontal>1</SplitHorizontal><TopRowBottomPane>1</TopRowBottomPane>`:``)+(y>0?`<SplitVertical>${y}</SplitVertical><LeftColumnRightPane>${y}</LeftColumnRightPane>`:``)+`<ActivePane>2</ActivePane></WorksheetOptions>`:``,x=[`<Row>${t.map(e=>`<Cell ss:StyleID="sHeader"><Data ss:Type="String">${z(e.header??e.field)}</Data></Cell>`).join(``)}</Row>`];for(let e=0;e<s;e++){if(r.signal?.aborted)throw new DOMException(`Export aborted`,`AbortError`);let i=n[e],a=t.map((t,n)=>_(g(t,i,e,n))).join(``);x.push(`<Row>${a}</Row>`),e>0&&e%o===0&&(r.onProgress?.({phase:`serialize`,ratio:e/s,row:e,total:s}),await new Promise(e=>setTimeout(e,0)))}return r.onProgress?.({phase:`serialize`,ratio:1,row:s,total:s}),`<?xml version="1.0"?>
29
29
  <?mso-application progid="Excel.Sheet"?>
30
30
  <Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:html="http://www.w3.org/TR/REC-html40"><Styles>${p.join(``)}</Styles><Worksheet ss:Name="${z(e.slice(0,31)||`Sheet1`)}"><Table>${v}${x.join(``)}</Table>`+b+`</Worksheet></Workbook>`}var Fe={"&":`&amp;`,"<":`&lt;`,">":`&gt;`,'"':`&quot;`,"'":`&apos;`},Ie=/[\x00-\x08\x0B\x0C\x0E-\x1F]/g;function B(e){return e.replace(Ie,``).replace(/[&<>"']/g,e=>Fe[e])}function V(e){let t=e,n=``;do n=String.fromCharCode(65+t%26)+n,t=Math.floor(t/26)-1;while(t>=0);return n}function H(e){if(!e)return null;let t=/^#?([0-9a-f]{6})$/i.exec(e.trim());return t?`FF`+t[1].toUpperCase():null}function Le(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 Re(e){if(e instanceof Date)return e;let t=String(e).trim(),n=/^(\d{4})-(\d{2})-(\d{2})$/.exec(t);return n?new Date(Number(n[1]),Number(n[2])-1,Number(n[3])):new Date(t)}var ze=`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
31
31
  <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>`,Be=`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
@@ -0,0 +1 @@
1
+ import{n as e}from"./server-block-cache-CXJKkJpy.js";var t=10,n=1e3,r=`https://svgrid.com/docs/getting-started/3-data-and-columns/`;function i(e,t=[]){for(let n of e)n.columns?.length?i(n.columns,t):t.push(n);return t}function a(a){let s=[],c=i(a.columns??[]),l=[],u=a.data??[],d=Math.min(u.length,n);for(let n=0;n<d&&l.length<t;n+=1){let t=u[n];e(t)||l.push(t)}if(l.length&&!a.serverGroup){let e=new Set;for(let t of l)if(t&&typeof t==`object`)for(let n of Object.keys(t))e.add(n);for(let t of c){let n=t.field;if(!n||t.fieldFn||e.has(n))continue;let i=o(n,[...e]);s.push(`[svgrid] Column field "${n}" does not exist on your row data, so that column renders empty.${i?` Did you mean "${i}"?`:``} Available keys: ${[...e].slice(0,12).join(`, `)}. See ${r}`)}}let f=new Map;for(let e of c){let t=e.id??e.field;t&&f.set(t,(f.get(t)??0)+1)}for(let[e,t]of f)t>1&&s.push(`[svgrid] ${t} columns share the id "${e}". Column state (sorting, filtering, pinning, width) is keyed by id, so they will act as one. Give each an explicit \`id\`. See ${r}`);let p=a.pageable===void 0&&a.showPagination===void 0;a.pageSize!==void 0&&p&&s.push("[svgrid] `pageSize` is set but pagination was never turned on, so it has no effect and every row renders. Add `pageable` to switch the pager on."),!(a.sortable===!0||a.features?.rowSortingFeature)&&c.some(e=>e.sortable===!0)&&s.push("[svgrid] A column sets `sortable: true`, but sorting is not enabled on the grid, so its header does nothing. Add `sortable` to <SvGrid> (it registers the sorting feature for you).");let m=new Set;for(let e of c){let t=e.id??e.field;t&&m.add(t)}for(let e of a.groupBy??[]){if(m.has(e))continue;let t=o(e,[...m]);s.push(`[svgrid] \`groupBy\` refers to column "${e}", which does not exist, so that grouping level is ignored.${t?` Did you mean "${t}"?`:``} Column ids: ${[...m].slice(0,12).join(`, `)}`)}let h=a.treeData?.column;if(h&&!m.has(h)&&s.push(`[svgrid] \`treeData.column\` refers to column "${h}", which does not exist, so the expander falls back to the first visible column.`),l.length&&a.treeData){let e=new Set;for(let t of l)if(t&&typeof t==`object`)for(let n of Object.keys(t))e.add(n);let t=a.treeData.parentField;if(t&&!e.has(t)){let n=o(t,[...e]);s.push(`[svgrid] \`treeData.parentField\` is "${t}", which is not on your row data, so every row becomes a root and no hierarchy appears.${n?` Did you mean "${n}"?`:``}`)}let n=a.treeData.idField;n&&!e.has(n)&&s.push(`[svgrid] \`treeData.idField\` is "${n}", which is not on your row data, so parent lookups cannot match and the tree stays flat.`)}return a.gantt&&a.treeData&&s.push("[svgrid] `gantt` and `treeData` are both set. The Gantt builds its own work-breakdown tree from `gantt.parentField` and needs every descendant row, but `treeData` hides collapsed children from the view, so summary bars will under-report. Remove `treeData` and set `gantt.parentField` instead."),(a.initialColumnPinning?.left?.length??0)+(a.initialColumnPinning?.right?.length??0)>0&&a.columnVirtualization!==!1&&s.push("[svgrid] `initialColumnPinning` is set while column virtualization is on (its default), so the pinned columns will not stick - the virtualizer recycles column nodes. Add `columnVirtualization={false}`."),a.externalPagination===!0&&a.rowCount===void 0&&s.push("[svgrid] `externalPagination` is on but `rowCount` is not set, so the pager cannot know how many pages exist. Pass the server total as `rowCount`."),a.externalSort===!0&&!a.onSortingChange&&s.push("[svgrid] `externalSort` is on but there is no `onSortingChange` handler, so clicking a header changes nothing - the grid stopped sorting and nobody is listening. Add `onSortingChange` and re-fetch in your handler."),a.externalFilter===!0&&!a.onFiltersChange&&s.push("[svgrid] `externalFilter` is on but there is no `onFiltersChange` handler, so filtering the grid changes nothing. Add `onFiltersChange` and re-fetch in your handler."),s}function o(e,t){let n,r=1/0;for(let i of t){let t=s(e.toLowerCase(),i.toLowerCase());t<r&&(r=t,n=i)}let i=Math.min(3,Math.floor(e.length/3)+1);return r<=i?n:void 0}function s(e,t){if(e===t)return 0;let n=Array(t.length+1);for(let e=0;e<=t.length;e++)n[e]=e;for(let r=1;r<=e.length;r++){let i=n[0];n[0]=r;for(let a=1;a<=t.length;a++){let o=Math.min(n[a]+1,n[a-1]+1,i+(e[r-1]===t[a-1]?0:1));i=n[a],n[a]=o}}return n[t.length]}export{a as validateGridConfig};
@@ -4,13 +4,13 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>SvGrid Studio - Designer</title>
7
- <script type="module" crossorigin src="./assets/index-DkhD2kIe.js"></script>
7
+ <script type="module" crossorigin src="./assets/index-CScGnzuX.js"></script>
8
8
  <link rel="modulepreload" crossorigin href="./assets/rolldown-runtime-Dd_uD5pT.js">
9
9
  <link rel="modulepreload" crossorigin href="./assets/disclose-version-CIm4S9xS.js">
10
10
  <link rel="modulepreload" crossorigin href="./assets/cell-formatting-BWrW_O0n.js">
11
11
  <link rel="modulepreload" crossorigin href="./assets/export-format-DGscOjS9.js">
12
12
  <link rel="modulepreload" crossorigin href="./assets/preload-helper-HclGiUj8.js">
13
- <link rel="modulepreload" crossorigin href="./assets/src-Mu7AGqT8.js">
13
+ <link rel="modulepreload" crossorigin href="./assets/src-DL33yzkY.js">
14
14
  <link rel="modulepreload" crossorigin href="./assets/editor-contract-Bpoa7A5g.js">
15
15
  <link rel="modulepreload" crossorigin href="./assets/date-format-B8JbEtIG.js">
16
16
  <link rel="modulepreload" crossorigin href="./assets/list-option-BP_dWS66.js">
package/dist/index.d.ts CHANGED
@@ -122,8 +122,8 @@ export { dismissUnlicensedNudge } from './watermark.js';
122
122
  export { showUpgradePrompt, dismissUpgradePrompt, type EnterpriseFeatureLabel, } from './upgrade-prompt.js';
123
123
  export { createPivotModel, pivotAggregators, filterCollapsedPivotRows, type PivotAggregator, type PivotAggregatorId, type PivotConfig, type PivotResult, type PivotRow, type PivotRowKind, type PivotValueConfig, } from './pivot.js';
124
124
  export { titleCase, resolveIdField, schemaToColumns, schemaToFormFields, isFieldHidden, validateField, applyComputed, validateEntity, type EntitySchema, type EntityField, type EntityFieldType, type EntityHooks, type FormFieldDescriptor, type FormLayout, type FormSection, type StudioEditorType, type StandardSchemaV1, type StandardSchemaResult, type ValidationOp, type ValidationRuleSpec, } from './schema.js';
125
- export { planQuery, coerce, createInMemoryDataSource, createKitDataSource, createKitHandlers, createSqlDataSource, planToSql, BUILTIN_AGGREGATORS, type QueryPlan, type PlanPredicate, type PlanOp, type PlanAggregate, type PlanOptions, type KitDataSourceOptions, type KitHandlerOptions, type KitScope, type KitHandlers, type KitMessage, type SqlDialect, type SqlPlan, type SqlExecutor, type SqlDataSourceConfig, type WritableDataSource, } from './sveltekit/index.js';
126
- export { createServerRowModel, serverRowModelRows, serverRowModelNav, serverGroupText, defaultServerGroupMessages, resolveServerGroupMessages, type ServerGroupMessages, GRAND_TOTAL_ROW_ID, GROUP_TOTAL_ROW_ID_PREFIX, type ServerRowModel, type ServerRowModelOptions, type ServerRowModelState, type ServerRowModelGridRow, type ServerRowModelDisplayRow, type ServerLevelParams, type ServerLevelState, type RefreshOptions, type ServerTransaction, type ServerTransactionResult, type ServerTransactionStatus, type ServerRowModelPaginationOptions, type ServerRowModelPagination, createServerSelectionModel, buildPivotResultColumns, type PivotResultColumnOptions, adaptCallbackDatasource, toCallbackDatasource, fromCallbackRequest, toCallbackRequest, fromCallbackFilterModel, toCallbackFilterModel, fromCallbackSelectionState, toCallbackSelectionState, isCallbackSelectionState, type CallbackSelectionState, type CallbackGroupSelectionState, type SelectionStateMapping, type CallbackServerRequest, type CallbackColumnFilter, type CallbackGetRowsParams, type CallbackDatasource, type ServerSelectionModel, type ServerSelectionModelOptions, type ServerSelectionState, type ServerGroupSelectionNode, type ServerSelectionGroupMode, createServerGroupModel, serverGroupRows, serverGroupNav, enableServerRowModel, SvGroupCell, SvRowGroupPanel, type ServerGroupController, type ServerGroupControllerOptions, type ServerGroupState, type ServerGroupGridRow, } from './server/index.js';
125
+ export { planQuery, coerce, createInMemoryDataSource, createKitDataSource, createKitHandlers, createSqlDataSource, planToSql, BUILTIN_AGGREGATORS, type QueryPlan, type PlanPredicate, type PlanOp, type PlanAggregate, type PlanOptions, type KitDataSourceOptions, type KitHandlerOptions, type KitScope, type KitHandlers, type KitMessage, type SqlDialect, type SqlPlan, type SqlExecutor, type SqlDataSourceConfig, type WritableDataSource, type InMemoryDataSourceOptions, } from './sveltekit/index.js';
126
+ export { createServerRowModel, serverRowModelRows, serverRowModelNav, serverGroupText, defaultServerGroupMessages, resolveServerGroupMessages, type ServerGroupMessages, GRAND_TOTAL_ROW_ID, GROUP_TOTAL_ROW_ID_PREFIX, type ServerRowModel, type ServerRowModelOptions, type ServerRowModelState, type ServerRowModelGridRow, type ServerRowModelDisplayRow, type ServerLevelParams, type ServerLevelState, type RefreshOptions, type ServerTransaction, type ServerTransactionResult, type ServerTransactionStatus, type ServerRowModelPaginationOptions, type ServerRowModelPagination, createServerSelectionModel, buildPivotResultColumns, type PivotResultColumnOptions, adaptCallbackDatasource, toCallbackDatasource, fromCallbackRequest, toCallbackRequest, fromCallbackFilterModel, toCallbackFilterModel, fromCallbackSelectionState, toCallbackSelectionState, isCallbackSelectionState, type CallbackSelectionState, type CallbackGroupSelectionState, type SelectionStateMapping, type CallbackServerRequest, type CallbackColumnFilter, type CallbackGetRowsParams, type CallbackDatasource, type ServerSelectionModel, type ServerSelectionModelOptions, type ServerSelectionState, type ServerGroupSelectionNode, type ServerSelectionGroupMode, createServerGroupModel, serverGroupRows, serverGroupNav, createWorkerDataSource, type WorkerDataSource, type WorkerDataSourceOptions, type WorkerLike, enableServerRowModel, SvGroupCell, SvRowGroupPanel, type ServerGroupController, type ServerGroupControllerOptions, type ServerGroupState, type ServerGroupGridRow, } from './server/index.js';
127
127
  export { createSupabaseDataSource, createRestDataSource, offsetLimitAdapter, dummyJsonAdapter, jsonServerAdapter, introspectSupabaseTable, listSupabaseTables, createSupabaseRealtime, createRelationLookup, createSupabaseAuth, aggregateRows, chartFieldsFromSchema, normalizeFilters, buildEntitySchema, pickLabelField, linkRelationLabels, type SupabaseDataSourceConfig, type SupabaseClientLike, type RestDataSourceConfig, type RestAdapter, type OffsetLimitOptions, type IntrospectSupabaseOptions, type IntrospectedColumn, type ColumnReference, type NormalizedFilter, type NormalizedPredicate, type SupabaseRealtimeConfig, type SupabaseRealtimeClientLike, type SupabaseRealtimeHandle, type RealtimeChannelLike, type RealtimeChange, type RelationLookup, type RelationLookupConfig, type RelationOption, type SupabaseAuthConfig, type SupabaseAuthController, type SupabaseAuthClientLike, type AuthState, type AuthUser, withEntityRules, withRelationLabels, reduceValue, kpiSeries, sparklinePoints, seriesDelta, formatKpiValue, dashboardFromSchema, type AggregateReduce, type AggregateRequest, type AggregateBucket, type AggregateSource, type DashboardSpec, type DashboardWidget, type KpiWidget, type ChartWidget, type RelationLabelConfig, } from './sources/index.js';
128
128
  export { buildInitialValues, controlKind, editMode, evalValidationRules, fieldState, sectionVisible, hasFieldConditions, rowId, stripHiddenValues, toSubmitValues, validateAll, visibleFormFields, type EditMode, type ControlKind, type FieldState, } from './edit-panel.js';
129
129
  export { default as SvGridEditPanel } from './SvGridEditPanel.svelte';
package/dist/index.js CHANGED
@@ -151,7 +151,7 @@ export { titleCase, resolveIdField, schemaToColumns, schemaToFormFields, isField
151
151
  export { planQuery, coerce, createInMemoryDataSource, createKitDataSource, createKitHandlers, createSqlDataSource, planToSql, BUILTIN_AGGREGATORS, } from './sveltekit/index.js';
152
152
  // Server-Side Row Model: lazy server-side grouping and tree data over the
153
153
  // free grid's datasource contract. Also available as '@svgrid/enterprise/server'.
154
- export { createServerRowModel, serverRowModelRows, serverRowModelNav, serverGroupText, defaultServerGroupMessages, resolveServerGroupMessages, GRAND_TOTAL_ROW_ID, GROUP_TOTAL_ROW_ID_PREFIX, createServerSelectionModel, buildPivotResultColumns, adaptCallbackDatasource, toCallbackDatasource, fromCallbackRequest, toCallbackRequest, fromCallbackFilterModel, toCallbackFilterModel, fromCallbackSelectionState, toCallbackSelectionState, isCallbackSelectionState, createServerGroupModel, serverGroupRows, serverGroupNav, enableServerRowModel, SvGroupCell, SvRowGroupPanel, } from './server/index.js';
154
+ export { createServerRowModel, serverRowModelRows, serverRowModelNav, serverGroupText, defaultServerGroupMessages, resolveServerGroupMessages, GRAND_TOTAL_ROW_ID, GROUP_TOTAL_ROW_ID_PREFIX, createServerSelectionModel, buildPivotResultColumns, adaptCallbackDatasource, toCallbackDatasource, fromCallbackRequest, toCallbackRequest, fromCallbackFilterModel, toCallbackFilterModel, fromCallbackSelectionState, toCallbackSelectionState, isCallbackSelectionState, createServerGroupModel, serverGroupRows, serverGroupNav, createWorkerDataSource, enableServerRowModel, SvGroupCell, SvRowGroupPanel, } from './server/index.js';
155
155
  export { createSupabaseDataSource, createRestDataSource, offsetLimitAdapter, dummyJsonAdapter, jsonServerAdapter, introspectSupabaseTable, listSupabaseTables, createSupabaseRealtime, createRelationLookup, createSupabaseAuth, aggregateRows, chartFieldsFromSchema, normalizeFilters, buildEntitySchema, pickLabelField, linkRelationLabels, withEntityRules, withRelationLabels, reduceValue, kpiSeries, sparklinePoints, seriesDelta, formatKpiValue, dashboardFromSchema, } from './sources/index.js';
156
156
  export { buildInitialValues, controlKind, editMode, evalValidationRules, fieldState, sectionVisible, hasFieldConditions, rowId, stripHiddenValues, toSubmitValues, validateAll, visibleFormFields, } from './edit-panel.js';
157
157
  export { default as SvGridEditPanel } from './SvGridEditPanel.svelte';
package/dist/license.js CHANGED
@@ -49,7 +49,7 @@ function noticeExpired(info) {
49
49
  // eslint-disable-next-line no-console
50
50
  console.info(`@svgrid/enterprise: your evaluation license expired${on}. Everything still ` +
51
51
  'works, but the watermark and upgrade notice stay until a license key is set. ' +
52
- 'Contact sales@jqwidgets.com or see https://svgrid.com/pricing');
52
+ 'Contact sales@jqwidgets.com or see https://svgrid.com/pricing/?utm_source=svgrid-enterprise&utm_medium=console');
53
53
  }
54
54
  export function setLicenseKey(key) {
55
55
  if (typeof key !== 'string' || key.length === 0) {
@@ -132,7 +132,7 @@ function noticeEdition(product) {
132
132
  console.info(`@svgrid/enterprise: your Grid license does not cover ${PRODUCT_LABEL[product]}. ` +
133
133
  'Everything still works, but the watermark and upgrade notice stay until the ' +
134
134
  'license is upgraded to Suite. Contact sales@jqwidgets.com or see ' +
135
- 'https://svgrid.com/pricing');
135
+ 'https://svgrid.com/pricing/?utm_source=svgrid-enterprise&utm_medium=console');
136
136
  }
137
137
  /**
138
138
  * True when the current key covers `product`. Use it to hide a Suite-only entry
@@ -16045,7 +16045,20 @@ function hasFieldConditions(schema) {
16045
16045
  *
16046
16046
  * `version.test.ts` asserts this matches `package.json`, so the two cannot drift.
16047
16047
  */
16048
- var SVGRID_VERSION = "3.1.1";
16048
+ var SVGRID_VERSION = "3.1.3";
16049
+ /**
16050
+ * The version of `@svgrid/grid`, which releases on its own line: enterprise is
16051
+ * on 3.1.x while the grid is on 3.0.x.
16052
+ *
16053
+ * A scaffolded app depends on BOTH packages, and pinning the grid to this
16054
+ * package's version asked npm for `@svgrid/grid@^3.1.1`, which has never been
16055
+ * published. Every `svgrid-studio init` therefore produced an app whose very
16056
+ * next step, `npm install`, failed with ERESOLVE. Found 2026-10-05 by
16057
+ * scaffolding one and running the install.
16058
+ *
16059
+ * `version.test.ts` asserts this matches packages/grid/package.json.
16060
+ */
16061
+ var GRID_VERSION = "3.0.8";
16049
16062
  //#endregion
16050
16063
  //#region src/studio/emit-project.ts
16051
16064
  var has = (blocks, kind) => blocks.some((b) => b.config.kind === kind);
@@ -20902,10 +20915,9 @@ function svelteConfig(plan) {
20902
20915
  /** The runtime npm deps the generated source imports, keyed by package -> range.
20903
20916
  * One source of truth for package.json AND the fragment-mode dependency report. */
20904
20917
  function runtimeDeps(project, allSource) {
20905
- const svgrid = `^${SVGRID_VERSION}`;
20906
20918
  const dependencies = {
20907
- "@svgrid/grid": svgrid,
20908
- "@svgrid/enterprise": svgrid
20919
+ "@svgrid/grid": `^${GRID_VERSION}`,
20920
+ "@svgrid/enterprise": `^${SVGRID_VERSION}`
20909
20921
  };
20910
20922
  if (allSource.includes("from '@supabase/supabase-js'")) dependencies["@supabase/supabase-js"] = "^2.45.0";
20911
20923
  if (allSource.includes("import pg from 'pg'")) dependencies["pg"] = "^8.11.0";
@@ -16,6 +16,7 @@ export { adaptCallbackDatasource, toCallbackDatasource, fromCallbackRequest, toC
16
16
  export { createServerGroupModel, serverGroupRows, serverGroupNav, type ServerGroupController, type ServerGroupControllerOptions, type ServerGroupState, type ServerGroupGridRow, } from './server-group-model.js';
17
17
  export { createServerSelectionModel, type ServerSelectionModel, type ServerSelectionModelOptions, type ServerSelectionState, type ServerGroupSelectionNode, type ServerSelectionGroupMode, } from './server-selection.js';
18
18
  export { buildPivotResultColumns, type PivotResultColumnOptions, } from './server-pivot.js';
19
+ export { createWorkerDataSource, type WorkerDataSource, type WorkerDataSourceOptions, type WorkerLike, } from './worker-data-source.js';
19
20
  export { enableServerRowModel } from './enable.js';
20
21
  export { defaultServerGroupMessages, resolveServerGroupMessages, type ServerGroupMessages, } from './messages.js';
21
22
  export { default as SvGroupCell } from './SvGroupCell.svelte';
@@ -18,6 +18,7 @@ export { adaptCallbackDatasource, toCallbackDatasource, fromCallbackRequest, toC
18
18
  export { createServerGroupModel, serverGroupRows, serverGroupNav, } from './server-group-model.js';
19
19
  export { createServerSelectionModel, } from './server-selection.js';
20
20
  export { buildPivotResultColumns, } from './server-pivot.js';
21
+ export { createWorkerDataSource, } from './worker-data-source.js';
21
22
  export { enableServerRowModel } from './enable.js';
22
23
  export { defaultServerGroupMessages, resolveServerGroupMessages, } from './messages.js';
23
24
  export { default as SvGroupCell } from './SvGroupCell.svelte';
@@ -169,6 +169,15 @@ export type ServerRowModelOptions<TData> = {
169
169
  * grid's pinned rows so it stays in view.
170
170
  */
171
171
  grandTotalRow?: 'top' | 'bottom' | 'pinnedTop' | 'pinnedBottom';
172
+ /**
173
+ * Milliseconds to keep the rows on screen after a sort, a filter or a
174
+ * regroup while the new answer loads. If its first block lands in that
175
+ * time, the grid goes straight from the old rows to the new ones: no
176
+ * frame of skeletons between them, and one update instead of two. A fast
177
+ * source (a worker, a local database) never shows a skeleton; a slow one
178
+ * shows them once the time is up. Default 0: skeletons at once.
179
+ */
180
+ keepRowsWhileLoading?: number;
172
181
  /** Drop a group's cached children when it is collapsed. Default false. */
173
182
  purgeClosedGroups?: boolean;
174
183
  /**
@@ -368,10 +368,53 @@ export function createServerRowModel(source, options) {
368
368
  }
369
369
  }
370
370
  }
371
- // ---------------------------------------------------------- flatten
371
+ const leafRuns = new WeakMap();
372
+ function leafRun(store, rows) {
373
+ if (openDetails.size)
374
+ return null;
375
+ const prev = leafRuns.get(store);
376
+ if (prev && prev.rows === rows)
377
+ return prev;
378
+ const n = rows.length;
379
+ // Same length (a block landed, a row was patched): update the kept
380
+ // arrays in place. The flatten only ever copies out of them.
381
+ const inPlace = !!prev && prev.rows.length === n;
382
+ const display = inPlace ? prev.display : new Array(n);
383
+ const grid = inPlace ? prev.grid : new Array(n);
384
+ const old = prev?.rows;
385
+ const oldLength = old ? old.length : 0;
386
+ for (let i = 0; i < n; i += 1) {
387
+ const child = rows[i];
388
+ if (i < oldLength && old[i] === child) {
389
+ if (!inPlace) {
390
+ display[i] = prev.display[i];
391
+ grid[i] = prev.grid[i];
392
+ }
393
+ continue;
394
+ }
395
+ const ph = rowPlaceholderState(child);
396
+ if (ph) {
397
+ const d = ph === 'failed' ? FAILED_ROW : LOADING_ROW;
398
+ display[i] = d;
399
+ grid[i] = toGridRow(d);
400
+ continue;
401
+ }
402
+ if (child.kind !== 'leaf') {
403
+ // Written in place up to here, so the kept run is no longer whole.
404
+ leafRuns.delete(store);
405
+ return null;
406
+ }
407
+ const d = { kind: 'leaf', id: child.id, level: store.level, route: store.route, data: child.data };
408
+ display[i] = d;
409
+ grid[i] = toGridRow(d, child.data);
410
+ }
411
+ const run = { rows, display, grid };
412
+ leafRuns.set(store, run);
413
+ return run;
414
+ }
372
415
  function flatten() {
373
- const display = [];
374
- const grid = [];
416
+ let display = [];
417
+ let grid = [];
375
418
  segments = [];
376
419
  const pushRow = (d, data) => {
377
420
  display.push(d);
@@ -392,6 +435,28 @@ export function createServerRowModel(source, options) {
392
435
  };
393
436
  const walk = (store, from = 0, to = Number.POSITIVE_INFINITY) => {
394
437
  const rows = store.cache.rows();
438
+ const run = store.loadMore ? null : leafRun(store, rows);
439
+ if (run) {
440
+ // A level of leaves maps one to one: copy the range out of the run.
441
+ const end = Math.min(rows.length, to);
442
+ if (end > from) {
443
+ segments.push({ store, displayStart: display.length, storeStart: from, length: end - from });
444
+ const { display: d, grid: g } = run;
445
+ if (display.length === 0) {
446
+ // The common flat case: the whole list is this run. A slice is a
447
+ // block copy; a push per row was the rest of the flatten's cost.
448
+ display = d.slice(from, end);
449
+ grid = g.slice(from, end);
450
+ }
451
+ else {
452
+ for (let i = from; i < end; i += 1) {
453
+ display.push(d[i]);
454
+ grid.push(g[i]);
455
+ }
456
+ }
457
+ }
458
+ return;
459
+ }
395
460
  const end = Math.min(rows.length, to, store.loadMore ? loadedPrefix(rows) : Number.POSITIVE_INFINITY);
396
461
  let segStart = from;
397
462
  let dispStart = display.length;
@@ -606,6 +671,34 @@ export function createServerRowModel(source, options) {
606
671
  pagination: pagination(),
607
672
  };
608
673
  }
674
+ // `keepRowsWhileLoading`: after a sort, a filter or a regroup, the rows on
675
+ // screen stay until the new answer's first block lands or the time runs
676
+ // out. `holdUntil` is that deadline, 0 when nothing is held.
677
+ let holdUntil = 0;
678
+ let holdTimer = null;
679
+ let held = false;
680
+ function holdRows() {
681
+ const ms = options.keepRowsWhileLoading ?? 0;
682
+ if (ms > 0 && current.displayRows.length > 0)
683
+ holdUntil = Date.now() + ms;
684
+ }
685
+ /** Whether the rows on screen should stay a little longer. */
686
+ function holding() {
687
+ if (!holdUntil)
688
+ return false;
689
+ const root = stores.get(routeKey([]));
690
+ // A failed block ends the hold too: its Retry is the answer to show.
691
+ const rootAnswered = !!root && root.cache.getCacheState().some((b) => b.status !== 'loading');
692
+ let pending = false;
693
+ for (const s of stores.values())
694
+ if (s.refreshPending)
695
+ pending = true;
696
+ if (Date.now() >= holdUntil || rootError || (rootAnswered && !pending)) {
697
+ holdUntil = 0;
698
+ return false;
699
+ }
700
+ return true;
701
+ }
609
702
  function scheduleEmit() {
610
703
  if (disposed || emitScheduled)
611
704
  return;
@@ -614,7 +707,25 @@ export function createServerRowModel(source, options) {
614
707
  emitScheduled = false;
615
708
  if (disposed)
616
709
  return;
710
+ if (holding()) {
711
+ held = true;
712
+ holdTimer ?? (holdTimer = setTimeout(() => {
713
+ holdTimer = null;
714
+ scheduleEmit();
715
+ }, Math.max(0, holdUntil - Date.now())));
716
+ return;
717
+ }
718
+ if (holdTimer) {
719
+ clearTimeout(holdTimer);
720
+ holdTimer = null;
721
+ }
617
722
  current = buildState();
723
+ // While rows were held the grid kept reporting positions in the old
724
+ // list, mapped through the old segments; map them through the new.
725
+ if (held) {
726
+ held = false;
727
+ applyViewport();
728
+ }
618
729
  options.onChange?.(current);
619
730
  for (const notify of subscribers)
620
731
  notify();
@@ -749,6 +860,7 @@ export function createServerRowModel(source, options) {
749
860
  }
750
861
  function setSort(next) {
751
862
  sortModel = next;
863
+ holdRows();
752
864
  for (const store of storesAffectedBySort(next)) {
753
865
  if (options.clientSideSort && sortLocally(store))
754
866
  continue;
@@ -759,6 +871,7 @@ export function createServerRowModel(source, options) {
759
871
  }
760
872
  function setFilter(next) {
761
873
  const previous = filterModel;
874
+ holdRows();
762
875
  filterModel = Array.isArray(next.columns)
763
876
  ? { global: next.global, columns: toServerFilterColumns(next) }
764
877
  : next;
@@ -1212,6 +1325,7 @@ export function createServerRowModel(source, options) {
1212
1325
  expanded.clear();
1213
1326
  seenGroups.clear();
1214
1327
  }
1328
+ holdRows();
1215
1329
  rebuild();
1216
1330
  },
1217
1331
  toggleGroup(row) {
@@ -1439,6 +1553,9 @@ export function createServerRowModel(source, options) {
1439
1553
  if (asyncTimer)
1440
1554
  clearTimeout(asyncTimer);
1441
1555
  asyncTimer = null;
1556
+ if (holdTimer)
1557
+ clearTimeout(holdTimer);
1558
+ holdTimer = null;
1442
1559
  asyncQueue.length = 0;
1443
1560
  for (const s of stores.values())
1444
1561
  s.cache.dispose();
@@ -0,0 +1,62 @@
1
+ /**
2
+ * A `ServerDataSource` whose rows live in a Web Worker.
3
+ *
4
+ * Sorting, filtering, grouping and aggregating a few hundred thousand rows
5
+ * takes long enough on the main thread that scrolling and typing stop while
6
+ * it runs. This moves that work into a worker and lets the grid treat the
7
+ * worker as a server: `createServerRowModel` (or the free
8
+ * `createServerDataSource`) asks for one block of rows at a time, the worker
9
+ * answers with just that block, and the full array never crosses back.
10
+ *
11
+ * Inside the worker the requests run through `createInMemoryDataSource`, the
12
+ * reference implementation of the datasource contract, so the answers are the
13
+ * ones every other backend is tested against.
14
+ *
15
+ * ```ts
16
+ * // grid.worker.ts
17
+ * import { serveWorkerDataSource } from '@svgrid/enterprise/worker'
18
+ * serveWorkerDataSource({ rows: () => fetch('/orders.json').then((r) => r.json()) })
19
+ *
20
+ * // App.svelte
21
+ * const worker = new Worker(new URL('./grid.worker.ts', import.meta.url), { type: 'module' })
22
+ * const ctl = createServerRowModel(createWorkerDataSource(worker), { groupBy: ['region'] })
23
+ * ```
24
+ *
25
+ * What it cannot do: run your functions. A worker receives data, not code,
26
+ * so a column's `valueGetter`, `comparator` or custom filter function never
27
+ * reaches it. Sorting and filtering go by field value, as with any server.
28
+ */
29
+ import type { RowData } from '@svgrid/grid';
30
+ import type { ServerDataSource } from '@svgrid/grid/server';
31
+ import type { EntitySchema } from '../schema.js';
32
+ import type { AggregateBucket, AggregateRequest } from '../sources/aggregate.js';
33
+ /** What `createWorkerDataSource` needs from a `Worker`. A `MessagePort` fits too. */
34
+ export type WorkerLike = {
35
+ postMessage(message: unknown): void;
36
+ addEventListener(type: string, listener: (event: MessageEvent) => void): void;
37
+ removeEventListener(type: string, listener: (event: MessageEvent) => void): void;
38
+ terminate?(): void;
39
+ };
40
+ export type WorkerDataSourceOptions<TData extends RowData> = {
41
+ /**
42
+ * Rows to copy into the worker. Copying is structured cloning on the main
43
+ * thread, so for a large dataset prefer loading it inside the worker
44
+ * (`serveWorkerDataSource({ rows })`) and leave this out.
45
+ */
46
+ rows?: ReadonlyArray<TData>;
47
+ /** Sent with `rows`. Default: the worker's own, or one read off the rows. */
48
+ schema?: EntitySchema<TData>;
49
+ /** The row id field, when the schema is inferred. */
50
+ idField?: string;
51
+ };
52
+ export type WorkerDataSource<TData extends RowData> = Required<Pick<ServerDataSource<TData>, 'getRows' | 'createRow' | 'updateRow' | 'deleteRow' | 'updateWhere'>> & {
53
+ /** Group and reduce in the worker, for `SvSchemaChart` and dashboards. */
54
+ getAggregate(request: AggregateRequest): Promise<AggregateBucket[]>;
55
+ /** Settles once the worker holds rows: with the row count, or the loader's error. */
56
+ readonly ready: Promise<number>;
57
+ /** Replace the worker's rows. Resolves with the new count. */
58
+ setRows(rows: ReadonlyArray<TData>, schema?: EntitySchema<TData>): Promise<number>;
59
+ /** Reject what is pending and terminate the worker. The row model's `dispose()` calls it. */
60
+ destroy(): void;
61
+ };
62
+ export declare function createWorkerDataSource<TData extends RowData>(worker: WorkerLike, options?: WorkerDataSourceOptions<TData>): WorkerDataSource<TData>;
@@ -0,0 +1,133 @@
1
+ import { CHANNEL, fromWorkerError, isChannelMessage, } from '../worker/protocol.js';
2
+ import { nudgeServerRowModel } from './enable.js';
3
+ function abortReason(signal) {
4
+ return signal.reason ?? new DOMException('The request was aborted.', 'AbortError');
5
+ }
6
+ export function createWorkerDataSource(worker, options = {}) {
7
+ nudgeServerRowModel();
8
+ let nextId = 1;
9
+ let destroyed = false;
10
+ // Set once the worker cannot answer any more: it failed to start, its
11
+ // loader threw, or `destroy()` ran. Every later call rejects with it.
12
+ let failure = null;
13
+ const pending = new Map();
14
+ let resolveReady;
15
+ let rejectReady;
16
+ const ready = new Promise((resolve, reject) => {
17
+ resolveReady = resolve;
18
+ rejectReady = reject;
19
+ });
20
+ // A source nobody awaited `ready` on must not raise an unhandled rejection.
21
+ ready.catch(() => { });
22
+ function failAll(error) {
23
+ failure ?? (failure = error);
24
+ rejectReady(error);
25
+ for (const p of pending.values())
26
+ p.reject(error);
27
+ pending.clear();
28
+ }
29
+ function onMessage(event) {
30
+ const message = event.data;
31
+ if (!isChannelMessage(message))
32
+ return;
33
+ switch (message.kind) {
34
+ case 'ready':
35
+ resolveReady(message.rowCount);
36
+ break;
37
+ case 'failed':
38
+ failAll(fromWorkerError(message.error));
39
+ break;
40
+ case 'result': {
41
+ const p = pending.get(message.id);
42
+ if (!p)
43
+ return; // cancelled, or answered after destroy
44
+ pending.delete(message.id);
45
+ if (message.ok)
46
+ p.resolve(message.value);
47
+ else
48
+ p.reject(fromWorkerError(message.error));
49
+ break;
50
+ }
51
+ }
52
+ }
53
+ // The worker script failed to load or threw at the top level. Without this
54
+ // every request would wait forever on a worker that is not there.
55
+ function onError(event) {
56
+ const message = event.message || 'The data source worker failed to start.';
57
+ failAll(new Error(message));
58
+ }
59
+ worker.addEventListener('message', onMessage);
60
+ worker.addEventListener('error', onError);
61
+ worker.start?.();
62
+ function send(message) {
63
+ worker.postMessage(message);
64
+ }
65
+ function request(message, signal) {
66
+ if (failure)
67
+ return Promise.reject(failure);
68
+ if (signal?.aborted)
69
+ return Promise.reject(abortReason(signal));
70
+ const id = nextId++;
71
+ return new Promise((resolve, reject) => {
72
+ const onAbort = () => {
73
+ if (!pending.delete(id))
74
+ return;
75
+ send({ channel: CHANNEL, kind: 'cancel', id });
76
+ reject(abortReason(signal));
77
+ };
78
+ pending.set(id, {
79
+ resolve: (value) => {
80
+ signal?.removeEventListener('abort', onAbort);
81
+ resolve(value);
82
+ },
83
+ reject: (error) => {
84
+ signal?.removeEventListener('abort', onAbort);
85
+ reject(error);
86
+ },
87
+ });
88
+ signal?.addEventListener('abort', onAbort, { once: true });
89
+ send(message(id));
90
+ });
91
+ }
92
+ function call(method, args, signal) {
93
+ return request((id) => ({ channel: CHANNEL, kind: 'call', id, method, args }), signal);
94
+ }
95
+ function load(rows, schema) {
96
+ return request((id) => ({
97
+ channel: CHANNEL,
98
+ kind: 'load',
99
+ id,
100
+ rows,
101
+ ...(schema ? { schema: schema } : {}),
102
+ ...(options.idField ? { idField: options.idField } : {}),
103
+ }));
104
+ }
105
+ if (options.rows)
106
+ void load(options.rows, options.schema).catch(failAll);
107
+ return {
108
+ getRows(req) {
109
+ // The signal cannot be cloned, and `parentRow` / `context` are app
110
+ // objects the in-memory source never reads; sending them would only
111
+ // risk a DataCloneError.
112
+ const { signal, parentRow: _parentRow, context: _context, ...plain } = req;
113
+ return call('getRows', [plain], signal);
114
+ },
115
+ createRow: (input) => call('createRow', [input]),
116
+ updateRow: (id, patch) => call('updateRow', [id, patch]),
117
+ deleteRow: (id) => call('deleteRow', [id]),
118
+ updateWhere: (filterModel, patch, selection) => call('updateWhere', [filterModel, patch, selection]),
119
+ getAggregate: (req) => call('getAggregate', [req]),
120
+ ready,
121
+ setRows: (rows, schema) => load(rows, schema ?? options.schema),
122
+ destroy() {
123
+ if (destroyed)
124
+ return;
125
+ destroyed = true;
126
+ failure = new Error('createWorkerDataSource: the source was destroyed');
127
+ failAll(failure);
128
+ worker.removeEventListener('message', onMessage);
129
+ worker.removeEventListener('error', onError);
130
+ worker.terminate?.();
131
+ },
132
+ };
133
+ }