@svgrid/enterprise 3.1.6 → 3.1.8
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/dist/SvGridScheduler.svelte +18 -0
- package/dist/cdn/svgrid-enterprise.svelte-external.js +7970 -7928
- package/dist/designer/assets/{index-Dknv-Eu8.js → index-Obk8sI77.js} +356 -355
- package/dist/designer/assets/{src-D4PRZJYA.js → src-DqHCqori.js} +8 -8
- package/dist/designer/index.html +2 -2
- package/dist/gantt/SvGridGantt.svelte +8 -0
- package/dist/keep-on-screen.d.ts +26 -0
- package/dist/keep-on-screen.js +24 -0
- package/dist/node/studio.js +38 -18
- package/dist/studio/emit-project.js +25 -6
- package/dist/studio/sveltekit3.js +13 -7
- package/dist/studio/ui-components.generated.js +1 -1
- package/dist/upgrade-prompt.d.ts +2 -2
- package/dist/upgrade-prompt.js +31 -26
- package/dist/version.d.ts +2 -2
- package/dist/version.js +2 -2
- package/dist/wc/sv-sheet-element.js +15 -11
- package/package.json +3 -3
|
@@ -1,8 +1,8 @@
|
|
|
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
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 C(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 ne(e){return!(e.type!==`colorScale`&&e.type!==`dataBar`||`compareColumn`in e&&e.compareColumn||e.minValue!=null&&e.maxValue!=null&&(e.bounds??`absolute`)===`absolute`)}function re(e){return e.some(ne)}var w=new Uint32Array([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]),T=(e,t)=>e>>>t|e<<32-t;function ie(e){let t=new TextEncoder().encode(e),n=t.length*8,r=Math.ceil((t.length+9)/64)*64,i=new Uint8Array(r);i.set(t),i[t.length]=128;let a=new DataView(i.buffer);a.setUint32(r-8,Math.floor(n/4294967296)),a.setUint32(r-4,n>>>0);let o=new Uint32Array([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]),s=new Uint32Array(64);for(let e=0;e<r;e+=64){for(let t=0;t<16;t++)s[t]=a.getUint32(e+t*4);for(let e=16;e<64;e++){let t=T(s[e-15],7)^T(s[e-15],18)^s[e-15]>>>3,n=T(s[e-2],17)^T(s[e-2],19)^s[e-2]>>>10;s[e]=s[e-16]+t+s[e-7]+n>>>0}let t=o[0],n=o[1],r=o[2],i=o[3],c=o[4],l=o[5],u=o[6],d=o[7];for(let e=0;e<64;e++){let a=T(c,6)^T(c,11)^T(c,25),o=c&l^~c&u,f=d+a+o+w[e]+s[e]>>>0,p=(T(t,2)^T(t,13)^T(t,22))+(t&n^t&r^n&r)>>>0;d=u,u=l,l=c,c=i+f>>>0,i=r,r=n,n=t,t=f+p>>>0}o[0]=o[0]+t>>>0,o[1]=o[1]+n>>>0,o[2]=o[2]+r>>>0,o[3]=o[3]+i>>>0,o[4]=o[4]+c>>>0,o[5]=o[5]+l>>>0,o[6]=o[6]+u>>>0,o[7]=o[7]+d>>>0}let c=``;for(let e of o)c+=e.toString(16).padStart(8,`0`);return c}function ae(e,t){return e===`suite`||t===`grid`}function E(e,t=new Date){return e==null||e.trim()===``?{status:`unset`,valid:!1,edition:`suite`}:ie(e.trim().toLowerCase())===`dabe98638cdc5760637bb2a741e65680a6ff0fb590d8b1018c9597650486cb10`?{status:`licensed`,valid:!0,edition:`suite`}:{status:`invalid`,valid:!1,edition:`suite`}}var D=new Set([`svgrid.com`,`www.svgrid.com`]);function O(){let e=globalThis.location?.hostname;return typeof e==`string`&&D.has(e.toLowerCase())}var k=`data-svgrid-enterprise-watermark`,A=`data-svgrid-enterprise-nudged`,j=`https://svgrid.com/pricing/?utm_source=svgrid-enterprise&utm_medium=watermark`,M=`www.svgrid.com`,oe=5e3,se=700,ce=!1,N=null;function P(){O()||(de(),!(typeof document>`u`||typeof window>`u`)&&(queueMicrotask(()=>fe()),N||(N=new MutationObserver(le),N.observe(document.body,{childList:!0,subtree:!0}))))}var F=!1;function le(e){for(let t of e){let e=t.target;if(!(e.nodeType===1&&e.closest?.(`.sv-grid-root[${A}]`))){ue();return}}}function ue(){if(F)return;F=!0;let e=()=>{F=!1,fe()};typeof requestAnimationFrame==`function`?requestAnimationFrame(e):setTimeout(e,16)}function de(){ce||(ce=!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 fe(){if(typeof document>`u`)return;let e=document.querySelectorAll(`.sv-grid-root, [role="grid"]`);if(e.length===0){he();return}document.querySelectorAll(`[${k}="fixed"]`).forEach(e=>e.remove());let t=new Set;e.forEach(e=>{let n=pe(e);n&&t.add(n)}),t.forEach(me)}function pe(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 me(e){if(e.hasAttribute(A))return;e.setAttribute(A,`1`),getComputedStyle(e).position===`static`&&(e.style.position=`relative`);let t=ge(`grid`);ve(t,!1),e.appendChild(t),_e(t)}function he(){if(typeof document>`u`||document.querySelector(`[${k}="fixed"]`))return;let e=ge(`fixed`);ve(e,!0),document.body.appendChild(e),_e(e)}function ge(e){let t=document.createElement(`a`);return t.setAttribute(k,e),t.href=j,t.target=`_blank`,t.rel=`noopener noreferrer`,t.textContent=M,t.title=`Unlicensed @svgrid/enterprise. Contact sales@jqwidgets.com or visit www.svgrid.com.`,t}function _e(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(),se)},oe)}function ve(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 ${se}ms ease`})}var ye=`data-svgrid-enterprise-upgrade`,be=`https://svgrid.com/pricing`,xe=`https://svgrid.com/
|
|
4
|
-
|
|
5
|
-
|
|
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 fe(){if(typeof document>`u`)return;let e=document.querySelectorAll(`.sv-grid-root, [role="grid"]`);if(e.length===0){he();return}document.querySelectorAll(`[${k}="fixed"]`).forEach(e=>e.remove());let t=new Set;e.forEach(e=>{let n=pe(e);n&&t.add(n)}),t.forEach(me)}function pe(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 me(e){if(e.hasAttribute(A))return;e.setAttribute(A,`1`),getComputedStyle(e).position===`static`&&(e.style.position=`relative`);let t=ge(`grid`);ve(t,!1),e.appendChild(t),_e(t)}function he(){if(typeof document>`u`||document.querySelector(`[${k}="fixed"]`))return;let e=ge(`fixed`);ve(e,!0),document.body.appendChild(e),_e(e)}function ge(e){let t=document.createElement(`a`);return t.setAttribute(k,e),t.href=j,t.target=`_blank`,t.rel=`noopener noreferrer`,t.textContent=M,t.title=`Unlicensed @svgrid/enterprise. Contact sales@jqwidgets.com or visit www.svgrid.com.`,t}function _e(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(),se)},oe)}function ve(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 ${se}ms ease`})}var ye=`data-svgrid-enterprise-upgrade`,be=`https://svgrid.com/pricing?ref=in-app&utm_source=svgrid-enterprise&utm_medium=upgrade-prompt`,xe=`https://svgrid.com/docs/enterprise/evaluation/?utm_source=svgrid-enterprise&utm_medium=upgrade-prompt`,Se=!1;function I(e,t){if(Se||typeof document>`u`||typeof window>`u`||O()||document.querySelector(`[${ye}]`))return;Se=!0;let n=Ce(e,t?.expired===!0);document.body.appendChild(n),requestAnimationFrame(()=>{n.style.opacity=`1`,n.style.transform=`translateY(0)`})}function L(e){e.style.opacity=`0`,e.style.transform=`translateY(8px)`,window.setTimeout(()=>e.remove(),220)}function Ce(e,t=!1){let n=document.createElement(`div`);n.setAttribute(ye,`1`),n.setAttribute(`role`,`dialog`),n.setAttribute(`aria-label`,t?`Your evaluation has ended`:`SvGrid Enterprise`),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">${we(e?String(e):`This`)}</strong> is part of SvGrid Enterprise.`:`You just used a <strong style="color:#fff">SvGrid Enterprise</strong> feature.`,i=t?`EVALUATION ENDED`:`ENTERPRISE`,a=t?`Your evaluation has ended`:`SvGrid Enterprise`,o=t?`${r} Everything still works, but this notice stays until a
|
|
4
|
+
license key is set.`:`${r} It keeps working as it is, here and in production. A
|
|
5
|
+
license key removes the watermark and this notice.`;return n.innerHTML=`
|
|
6
6
|
<button type="button" data-act="x" aria-label="Dismiss"
|
|
7
7
|
style="position:absolute;top:8px;right:8px;width:24px;height:24px;display:flex;
|
|
8
8
|
align-items:center;justify-content:center;background:transparent;border:0;
|
|
@@ -16,16 +16,16 @@ Contact sales@jqwidgets.com for details or visit the license page: https://svgri
|
|
|
16
16
|
${o}
|
|
17
17
|
</p>
|
|
18
18
|
<div style="display:flex;gap:8px;align-items:center;">
|
|
19
|
-
<a data-act="
|
|
19
|
+
<a data-act="plans" href="${be}" target="_blank" rel="noopener noreferrer"
|
|
20
20
|
style="flex:1;text-align:center;background:#6366f1;color:#fff;font-weight:600;
|
|
21
|
-
text-decoration:none;padding:8px 12px;border-radius:8px;">${t?`Buy a
|
|
22
|
-
<a data-act="
|
|
23
|
-
style="color:#a5b4fc;text-decoration:none;padding:8px 6px;font-weight:600;">
|
|
21
|
+
text-decoration:none;padding:8px 12px;border-radius:8px;">${t?`Buy a license`:`See plans`}</a>
|
|
22
|
+
<a data-act="evaluation" href="${xe}" target="_blank" rel="noopener noreferrer"
|
|
23
|
+
style="color:#a5b4fc;text-decoration:none;padding:8px 6px;font-weight:600;">How evaluation works</a>
|
|
24
24
|
</div>
|
|
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`,()=>L(n)),n.querySelector(`[data-act="
|
|
28
|
+
`,n.querySelector(`[data-act="x"]`)?.addEventListener(`click`,()=>L(n)),n.querySelector(`[data-act="plans"]`)?.addEventListener(`click`,()=>L(n)),n.querySelector(`[data-act="evaluation"]`)?.addEventListener(`click`,()=>L(n)),n}function we(e){return e.replace(/&/g,`&`).replace(/</g,`<`).replace(/>/g,`>`).replace(/"/g,`"`)}var R=null,Te=!1,Ee=!1,De=new Set;function z(e){if(Ee)return;Ee=!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 Oe(e){return e.status===`dev`||e.status===`eval`}var ke=!1;function B(e){ke||e.status!==`invalid`&&e.status!==`revoked`||O()||(ke=!0,console.warn(`@svgrid/enterprise: the license key passed to setLicenseKey() is not valid, so the watermark stays. Copy the key from your order email, or contact sales@jqwidgets.com.`))}function Ae(){return E(R).valid}function je(e){let t=E(R),n=Oe(t)&&t.expired===!0;t.valid&&!n||(B(t),P(),n&&z(t),I(e,{expired:n}))}var Me={grid:`the enterprise grid`,spreadsheet:`the spreadsheet`,studio:`the Studio`};function Ne(e){De.has(e)||(De.add(e),console.info(`@svgrid/enterprise: your Grid license does not cover ${Me[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 Pe(e,t){let n=E(R),r=n.valid&&ae(n.edition,e),i=Oe(n)&&n.expired===!0;if(r&&!i)return;B(n);let a=n.valid&&!i&&!r;P(),a?Ne(e):i&&z(n),I(t,{expired:i})}function Fe(e){let t=E(R);switch(t.status){case`unset`:P(),I(e);return;case`invalid`:case`revoked`:B(t),P(),I(e);return;case`dev`:case`eval`:if(t.expired){P(),z(t),I(e,{expired:!0});return}Te||=(console.info(`@svgrid/enterprise: using a development / evaluation license. Not for production use.`),!0);return;case`licensed`:return}}var Ie=!1;function Le(){if(Ie)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,Ie=!0}var Re=/[\x00-\x08\x0B\x0C\x0E-\x1F]/g;function V(e){return e.replace(Re,``).replace(/&/g,`&`).replace(/</g,`<`).replace(/>/g,`>`).replace(/"/g,`"`)}function ze(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 Be(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="${V(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:ze(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="${V(e.href)}"`:``}><Data ss:Type="${e.type}">${V(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">${V(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="${V(e.slice(0,31)||`Sheet1`)}"><Table>${v}${x.join(``)}</Table>`+b+`</Worksheet></Workbook>`}var Ve={"&":`&`,"<":`<`,">":`>`,'"':`"`,"'":`'`},He=/[\x00-\x08\x0B\x0C\x0E-\x1F]/g;function H(e){return e.replace(He,``).replace(/[&<>"']/g,e=>Ve[e])}function U(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 W(e){if(!e)return null;let t=/^#?([0-9a-f]{6})$/i.exec(e.trim());return t?`FF`+t[1].toUpperCase():null}function Ue(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 We(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 Ge=`<?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>`,Ke=`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
package/dist/designer/index.html
CHANGED
|
@@ -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-
|
|
7
|
+
<script type="module" crossorigin src="./assets/index-Obk8sI77.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-
|
|
13
|
+
<link rel="modulepreload" crossorigin href="./assets/src-DqHCqori.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">
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
type SchedulerDependency,
|
|
44
44
|
} from "../scheduler-dependencies";
|
|
45
45
|
import { criticalPath, slackDays } from "./gantt-critical-path";
|
|
46
|
+
import { keepOnScreen } from "../keep-on-screen";
|
|
46
47
|
import { arrowHeadPath, dependencyArrows, nearestArrow, type BarRect } from "./timeline-arrows";
|
|
47
48
|
import {
|
|
48
49
|
ganttAxis,
|
|
@@ -1786,6 +1787,13 @@
|
|
|
1786
1787
|
menuPos = { x: e.clientX, y: e.clientY };
|
|
1787
1788
|
menuOpen = true;
|
|
1788
1789
|
}
|
|
1790
|
+
// Opened at the pointer: keep the whole menu on screen (keep-on-screen.ts).
|
|
1791
|
+
$effect(() => {
|
|
1792
|
+
if (!menuOpen || !menuPanel || typeof window === "undefined") return;
|
|
1793
|
+
const r = menuPanel.getBoundingClientRect();
|
|
1794
|
+
const fit = keepOnScreen(menuPos, r, { width: window.innerWidth, height: window.innerHeight });
|
|
1795
|
+
if (fit.x !== menuPos.x || fit.y !== menuPos.y) menuPos = fit;
|
|
1796
|
+
});
|
|
1789
1797
|
$effect(() => {
|
|
1790
1798
|
if (!menuOpen) return;
|
|
1791
1799
|
const layer = createDismissableLayer({
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where a pointer-anchored panel (a context menu, the "+N more" list) should
|
|
3
|
+
* sit so all of it is on screen.
|
|
4
|
+
*
|
|
5
|
+
* The scheduler and Gantt menus open at the pointer. A right-click near the
|
|
6
|
+
* bottom or right edge put their lower items outside the viewport, where they
|
|
7
|
+
* could not be clicked. The panel goes above the pointer when it does not fit
|
|
8
|
+
* below it, and is pulled back from the right edge when it does not fit there.
|
|
9
|
+
* The result for a position it returns is that same position, so an effect
|
|
10
|
+
* that writes it back settles after one pass.
|
|
11
|
+
*
|
|
12
|
+
* Internal: not exported from the package index.
|
|
13
|
+
*/
|
|
14
|
+
export declare function keepOnScreen(pos: {
|
|
15
|
+
x: number;
|
|
16
|
+
y: number;
|
|
17
|
+
}, size: {
|
|
18
|
+
width: number;
|
|
19
|
+
height: number;
|
|
20
|
+
}, viewport: {
|
|
21
|
+
width: number;
|
|
22
|
+
height: number;
|
|
23
|
+
}, pad?: number): {
|
|
24
|
+
x: number;
|
|
25
|
+
y: number;
|
|
26
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where a pointer-anchored panel (a context menu, the "+N more" list) should
|
|
3
|
+
* sit so all of it is on screen.
|
|
4
|
+
*
|
|
5
|
+
* The scheduler and Gantt menus open at the pointer. A right-click near the
|
|
6
|
+
* bottom or right edge put their lower items outside the viewport, where they
|
|
7
|
+
* could not be clicked. The panel goes above the pointer when it does not fit
|
|
8
|
+
* below it, and is pulled back from the right edge when it does not fit there.
|
|
9
|
+
* The result for a position it returns is that same position, so an effect
|
|
10
|
+
* that writes it back settles after one pass.
|
|
11
|
+
*
|
|
12
|
+
* Internal: not exported from the package index.
|
|
13
|
+
*/
|
|
14
|
+
export function keepOnScreen(pos, size, viewport, pad = 8) {
|
|
15
|
+
let { x, y } = pos;
|
|
16
|
+
// Above the pointer, but never lower than "bottom edge minus padding": a
|
|
17
|
+
// plain flip of a point within `pad` of the bottom would still overflow by
|
|
18
|
+
// a few pixels and flip again on the next pass.
|
|
19
|
+
if (y + size.height > viewport.height - pad)
|
|
20
|
+
y = Math.max(pad, Math.min(y - size.height, viewport.height - size.height - pad));
|
|
21
|
+
if (x + size.width > viewport.width - pad)
|
|
22
|
+
x = Math.max(pad, viewport.width - size.width - pad);
|
|
23
|
+
return { x, y };
|
|
24
|
+
}
|
package/dist/node/studio.js
CHANGED
|
@@ -2054,7 +2054,7 @@ var SOURCE = /\.(ts|js|svelte)$/;
|
|
|
2054
2054
|
function toSvelteKit3(files) {
|
|
2055
2055
|
const paths = new Set(files.map((f) => f.path));
|
|
2056
2056
|
const adapter = adapterOf(files);
|
|
2057
|
-
const envNames = /* @__PURE__ */ new
|
|
2057
|
+
const envNames = /* @__PURE__ */ new Map();
|
|
2058
2058
|
const out = [];
|
|
2059
2059
|
for (const file of files) {
|
|
2060
2060
|
if (file.path === "svelte.config.js") continue;
|
|
@@ -2090,7 +2090,7 @@ function toSvelteKit3(files) {
|
|
|
2090
2090
|
}
|
|
2091
2091
|
out.push(file);
|
|
2092
2092
|
}
|
|
2093
|
-
if (envNames.size) out.push(envModule([...envNames].sort()));
|
|
2093
|
+
if (envNames.size) out.push(envModule([...envNames].sort(([a], [b]) => a.localeCompare(b))));
|
|
2094
2094
|
return out;
|
|
2095
2095
|
}
|
|
2096
2096
|
function adapterOf(files) {
|
|
@@ -2159,18 +2159,22 @@ function rewriteLibImports(src, paths) {
|
|
|
2159
2159
|
/**
|
|
2160
2160
|
* `import { env } from '$env/dynamic/private'` + `env.X`
|
|
2161
2161
|
* -> `import { X } from '$app/env/private'` + `X`
|
|
2162
|
-
*
|
|
2162
|
+
* and the same for `$env/dynamic/public` -> `$app/env/public` (the Supabase
|
|
2163
|
+
* client reads PUBLIC_SUPABASE_* this way). Every name read is collected so
|
|
2164
|
+
* src/env.ts can declare it, which v3 requires; public ones are declared
|
|
2165
|
+
* `public: true`, or `$app/env/public` would not export them.
|
|
2163
2166
|
*/
|
|
2164
2167
|
function rewriteEnv(src, envNames) {
|
|
2165
|
-
|
|
2168
|
+
const kind = /from\s+['"]\$env\/dynamic\/private['"]/.test(src) ? "private" : /from\s+['"]\$env\/dynamic\/public['"]/.test(src) ? "public" : null;
|
|
2169
|
+
if (!kind) return src;
|
|
2166
2170
|
const used = /* @__PURE__ */ new Set();
|
|
2167
2171
|
const body = src.replace(/(?<![.\w])env\.([A-Z_][A-Z0-9_]*)/g, (_m, name) => {
|
|
2168
2172
|
used.add(name);
|
|
2169
2173
|
return name;
|
|
2170
2174
|
});
|
|
2171
|
-
for (const n of used) envNames.
|
|
2175
|
+
for (const n of used) envNames.set(n, kind === "public" || envNames.get(n) === true);
|
|
2172
2176
|
const names = [...used].sort();
|
|
2173
|
-
return body.replace(
|
|
2177
|
+
return body.replace(new RegExp(`import\\s*\\{\\s*env\\s*\\}\\s*from\\s*(['"])\\$env\\/dynamic\\/${kind}\\1`), names.length ? `import { ${names.join(", ")} } from '$app/env/${kind}'` : "");
|
|
2174
2178
|
}
|
|
2175
2179
|
/**
|
|
2176
2180
|
* Types that moved out of `@sveltejs/kit`, and the deprecated `json` helper.
|
|
@@ -2198,7 +2202,7 @@ function envModule(names) {
|
|
|
2198
2202
|
// SvelteKit 3 reads only the variables declared here. A missing one comes
|
|
2199
2203
|
// through as '' - every read in this app already falls back on that
|
|
2200
2204
|
// (a dev default, '?? ""', or an if), so that is the intended behaviour.
|
|
2201
|
-
export const variables = defineEnvVars({\n${names.map((n) => ` ${n}: { schema: (input) => input ?? '' },`).join("\n")}\n})\n`
|
|
2205
|
+
export const variables = defineEnvVars({\n${names.map(([n, pub]) => ` ${n}: { ${pub ? "public: true, " : ""}schema: (input) => input ?? '' },`).join("\n")}\n})\n`
|
|
2202
2206
|
};
|
|
2203
2207
|
}
|
|
2204
2208
|
//#endregion
|
|
@@ -9297,7 +9301,7 @@ var GENERATED_UI_SURFACE = {
|
|
|
9297
9301
|
"key": "rowNumberWidth",
|
|
9298
9302
|
"label": "Row Number Width",
|
|
9299
9303
|
"type": "number",
|
|
9300
|
-
"description": "Width (px) of the row-number column.
|
|
9304
|
+
"description": "Width (px) of the row-number column. By default it fits the largest row number: 56px up to four digits, then 9px wider per digit (from `data.length`, or `rowCount` on a server-paged grid). Set it to pin a width, for example when a theme uses a much larger font.",
|
|
9301
9305
|
"group": "common"
|
|
9302
9306
|
},
|
|
9303
9307
|
{
|
|
@@ -16341,7 +16345,7 @@ function hasFieldConditions(schema) {
|
|
|
16341
16345
|
*
|
|
16342
16346
|
* `version.test.ts` asserts this matches `package.json`, so the two cannot drift.
|
|
16343
16347
|
*/
|
|
16344
|
-
var SVGRID_VERSION = "3.1.
|
|
16348
|
+
var SVGRID_VERSION = "3.1.8";
|
|
16345
16349
|
/**
|
|
16346
16350
|
* The version of `@svgrid/grid`, which releases on its own line: enterprise is
|
|
16347
16351
|
* on 3.1.x while the grid is on 3.0.x.
|
|
@@ -16354,7 +16358,7 @@ var SVGRID_VERSION = "3.1.6";
|
|
|
16354
16358
|
*
|
|
16355
16359
|
* `version.test.ts` asserts this matches packages/grid/package.json.
|
|
16356
16360
|
*/
|
|
16357
|
-
var GRID_VERSION = "3.0.
|
|
16361
|
+
var GRID_VERSION = "3.0.11";
|
|
16358
16362
|
//#endregion
|
|
16359
16363
|
//#region src/studio/emit-project.ts
|
|
16360
16364
|
var has = (blocks, kind) => blocks.some((b) => b.config.kind === kind);
|
|
@@ -18441,6 +18445,7 @@ function emitSsrGridScreen(schema, screen, routed, accessEnabled, screenIds, byN
|
|
|
18441
18445
|
const facetPanel = screen.blocks.find((b) => b.config.kind === "filter")?.config;
|
|
18442
18446
|
const pageSize = grid.pageSize && grid.pageSize > 0 ? grid.pageSize : 25;
|
|
18443
18447
|
const wantsFilter = grid.filterable !== false;
|
|
18448
|
+
const wantsSort = grid.sortable !== false;
|
|
18444
18449
|
const idField = schema.idField ?? schema.fields.find((f) => f.primaryKey)?.field ?? "id";
|
|
18445
18450
|
const isFormHidden = (f) => f.hidden === true || typeof f.hidden === "object" && !!f.hidden.form;
|
|
18446
18451
|
const editable = schema.fields.filter((f) => f.field !== idField && !f.primaryKey && !f.readonly && !f.computed && !f.formula && !isFormHidden(f));
|
|
@@ -18738,7 +18743,7 @@ ${wantsFilter ? `
|
|
|
18738
18743
|
${facetForm}
|
|
18739
18744
|
<SvGrid
|
|
18740
18745
|
data={data.rows}
|
|
18741
|
-
{columns}
|
|
18746
|
+
{columns}${wantsSort ? "\n sortable" : ""}
|
|
18742
18747
|
externalSort
|
|
18743
18748
|
initialSorting={data.sort}
|
|
18744
18749
|
showPagination
|
|
@@ -21156,13 +21161,28 @@ function randomSecret(bytes = 32) {
|
|
|
21156
21161
|
globalThis.crypto.getRandomValues(buf);
|
|
21157
21162
|
return Array.from(buf, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
21158
21163
|
}
|
|
21164
|
+
/** The Supabase project the app connects to, when the model holds one: the
|
|
21165
|
+
* project-wide connection, else the first Supabase-bound entity's. */
|
|
21166
|
+
function supabaseConnOf(project) {
|
|
21167
|
+
const hit = [project.supabase, ...Object.values(project.dataSources ?? {}).filter((s) => s.kind === "supabase")].find((c) => c?.url && c?.key);
|
|
21168
|
+
return hit ? {
|
|
21169
|
+
url: hit.url,
|
|
21170
|
+
key: hit.key
|
|
21171
|
+
} : null;
|
|
21172
|
+
}
|
|
21159
21173
|
/** A ready-to-run, git-ignored `.env`: the `.env.example` template with a real
|
|
21160
21174
|
* random `SESSION_SECRET` filled in, so the app is secure out of the box (no
|
|
21161
|
-
* hardcoded dev secret)
|
|
21162
|
-
|
|
21175
|
+
* hardcoded dev secret), and the Supabase URL + anon key the model already
|
|
21176
|
+
* holds, so a Supabase app runs as generated instead of failing on an empty
|
|
21177
|
+
* URL. Only emitted when there is something to fill in. */
|
|
21178
|
+
function envDotFile(allSource, project) {
|
|
21163
21179
|
const example = envExample(allSource);
|
|
21164
|
-
if (!example
|
|
21165
|
-
|
|
21180
|
+
if (!example) return null;
|
|
21181
|
+
const supa = allSource.includes("PUBLIC_SUPABASE_URL") ? supabaseConnOf(project) : null;
|
|
21182
|
+
if (!allSource.includes("SESSION_SECRET") && !supa) return null;
|
|
21183
|
+
let env = example.replace("SESSION_SECRET=change-me-to-a-long-random-string", `SESSION_SECRET=${randomSecret()}`);
|
|
21184
|
+
if (supa) env = env.replace(/^PUBLIC_SUPABASE_URL=$/m, `PUBLIC_SUPABASE_URL=${supa.url}`).replace(/^PUBLIC_SUPABASE_ANON_KEY=$/m, `PUBLIC_SUPABASE_ANON_KEY=${supa.key}`);
|
|
21185
|
+
return env;
|
|
21166
21186
|
}
|
|
21167
21187
|
/** A `.env.example` listing the env vars the generated code reads, when any. */
|
|
21168
21188
|
function envExample(allSource) {
|
|
@@ -21448,10 +21468,10 @@ function emitStudioAppBundle(project) {
|
|
|
21448
21468
|
description: "Environment variables the app reads (copy to .env and fill in).",
|
|
21449
21469
|
contents: envExample(allSource)
|
|
21450
21470
|
}] : [],
|
|
21451
|
-
...envDotFile(allSource) ? [{
|
|
21471
|
+
...envDotFile(allSource, project) ? [{
|
|
21452
21472
|
path: ".env",
|
|
21453
|
-
description: "Local env (git-ignored): a real random SESSION_SECRET
|
|
21454
|
-
contents: envDotFile(allSource)
|
|
21473
|
+
description: "Local env (git-ignored): a real random SESSION_SECRET and the Supabase connection the design holds are pre-filled, so the app runs as generated; fill in the rest.",
|
|
21474
|
+
contents: envDotFile(allSource, project)
|
|
21455
21475
|
}] : [],
|
|
21456
21476
|
{
|
|
21457
21477
|
path: "src/app.css",
|
|
@@ -2540,6 +2540,9 @@ function emitSsrGridScreen(schema, screen, routed, accessEnabled, screenIds, byN
|
|
|
2540
2540
|
const facetPanel = screen.blocks.find((b) => b.config.kind === 'filter')?.config;
|
|
2541
2541
|
const pageSize = grid.pageSize && grid.pageSize > 0 ? grid.pageSize : 25;
|
|
2542
2542
|
const wantsFilter = grid.filterable !== false;
|
|
2543
|
+
// externalSort alone only renders the indicator; without `sortable` a header
|
|
2544
|
+
// click never reaches onSortingChange, so the URL (and the load) never sorts.
|
|
2545
|
+
const wantsSort = grid.sortable !== false;
|
|
2543
2546
|
const idField = schema.idField ?? schema.fields.find((f) => f.primaryKey)?.field ?? 'id';
|
|
2544
2547
|
const isFormHidden = (f) => f.hidden === true || (typeof f.hidden === 'object' && !!f.hidden.form);
|
|
2545
2548
|
const editable = schema.fields.filter((f) => f.field !== idField && !f.primaryKey && !f.readonly && !f.computed && !f.formula && !isFormHidden(f));
|
|
@@ -2901,7 +2904,7 @@ ${wantsFilter ? `
|
|
|
2901
2904
|
${facetForm}
|
|
2902
2905
|
<SvGrid
|
|
2903
2906
|
data={data.rows}
|
|
2904
|
-
{columns}
|
|
2907
|
+
{columns}${wantsSort ? '\n sortable' : ''}
|
|
2905
2908
|
externalSort
|
|
2906
2909
|
initialSorting={data.sort}
|
|
2907
2910
|
showPagination
|
|
@@ -5171,14 +5174,30 @@ function randomSecret(bytes = 32) {
|
|
|
5171
5174
|
globalThis.crypto.getRandomValues(buf);
|
|
5172
5175
|
return Array.from(buf, (b) => b.toString(16).padStart(2, '0')).join('');
|
|
5173
5176
|
}
|
|
5177
|
+
/** The Supabase project the app connects to, when the model holds one: the
|
|
5178
|
+
* project-wide connection, else the first Supabase-bound entity's. */
|
|
5179
|
+
function supabaseConnOf(project) {
|
|
5180
|
+
const candidates = [project.supabase, ...Object.values(project.dataSources ?? {}).filter((s) => s.kind === 'supabase')];
|
|
5181
|
+
const hit = candidates.find((c) => c?.url && c?.key);
|
|
5182
|
+
return hit ? { url: hit.url, key: hit.key } : null;
|
|
5183
|
+
}
|
|
5174
5184
|
/** A ready-to-run, git-ignored `.env`: the `.env.example` template with a real
|
|
5175
5185
|
* random `SESSION_SECRET` filled in, so the app is secure out of the box (no
|
|
5176
|
-
* hardcoded dev secret)
|
|
5177
|
-
|
|
5186
|
+
* hardcoded dev secret), and the Supabase URL + anon key the model already
|
|
5187
|
+
* holds, so a Supabase app runs as generated instead of failing on an empty
|
|
5188
|
+
* URL. Only emitted when there is something to fill in. */
|
|
5189
|
+
function envDotFile(allSource, project) {
|
|
5178
5190
|
const example = envExample(allSource);
|
|
5179
|
-
if (!example
|
|
5191
|
+
if (!example)
|
|
5192
|
+
return null;
|
|
5193
|
+
const supa = allSource.includes('PUBLIC_SUPABASE_URL') ? supabaseConnOf(project) : null;
|
|
5194
|
+
if (!allSource.includes('SESSION_SECRET') && !supa)
|
|
5180
5195
|
return null;
|
|
5181
|
-
|
|
5196
|
+
let env = example.replace('SESSION_SECRET=change-me-to-a-long-random-string', `SESSION_SECRET=${randomSecret()}`);
|
|
5197
|
+
// The anon key is public / browser-safe; access is governed by RLS.
|
|
5198
|
+
if (supa)
|
|
5199
|
+
env = env.replace(/^PUBLIC_SUPABASE_URL=$/m, `PUBLIC_SUPABASE_URL=${supa.url}`).replace(/^PUBLIC_SUPABASE_ANON_KEY=$/m, `PUBLIC_SUPABASE_ANON_KEY=${supa.key}`);
|
|
5200
|
+
return env;
|
|
5182
5201
|
}
|
|
5183
5202
|
/** A `.env.example` listing the env vars the generated code reads, when any. */
|
|
5184
5203
|
function envExample(allSource) {
|
|
@@ -5480,7 +5499,7 @@ export function emitStudioAppBundle(project) {
|
|
|
5480
5499
|
rootLayoutModule(project),
|
|
5481
5500
|
...SCAFFOLD_STATIC,
|
|
5482
5501
|
...(envExample(allSource) ? [{ path: '.env.example', description: 'Environment variables the app reads (copy to .env and fill in).', contents: envExample(allSource) }] : []),
|
|
5483
|
-
...(envDotFile(allSource) ? [{ path: '.env', description: 'Local env (git-ignored): a real random SESSION_SECRET
|
|
5502
|
+
...(envDotFile(allSource, project) ? [{ path: '.env', description: 'Local env (git-ignored): a real random SESSION_SECRET and the Supabase connection the design holds are pre-filled, so the app runs as generated; fill in the rest.', contents: envDotFile(allSource, project) }] : []),
|
|
5484
5503
|
{ path: 'src/app.css', description: 'App theme tokens + page styles.', contents: appCss(project) },
|
|
5485
5504
|
// Your styles: a dedicated CSS file the layout imports AFTER app.css, so its rules
|
|
5486
5505
|
// win. Edited in the designer's Styles panel; regenerated from the model.
|
|
@@ -24,7 +24,8 @@ const SOURCE = /\.(ts|js|svelte)$/;
|
|
|
24
24
|
export function toSvelteKit3(files) {
|
|
25
25
|
const paths = new Set(files.map((f) => f.path));
|
|
26
26
|
const adapter = adapterOf(files);
|
|
27
|
-
|
|
27
|
+
// Every env var a source reads, and whether it is public (client-side).
|
|
28
|
+
const envNames = new Map();
|
|
28
29
|
const out = [];
|
|
29
30
|
for (const file of files) {
|
|
30
31
|
// svelte.config.js is gone: its adapter and preprocess move into vite.config.ts.
|
|
@@ -50,7 +51,7 @@ export function toSvelteKit3(files) {
|
|
|
50
51
|
out.push(file);
|
|
51
52
|
}
|
|
52
53
|
if (envNames.size)
|
|
53
|
-
out.push(envModule([...envNames].sort()));
|
|
54
|
+
out.push(envModule([...envNames].sort(([a], [b]) => a.localeCompare(b))));
|
|
54
55
|
return out;
|
|
55
56
|
}
|
|
56
57
|
/* ---------------------------------------------------------------- config */
|
|
@@ -143,10 +144,15 @@ function rewriteLibImports(src, paths) {
|
|
|
143
144
|
/**
|
|
144
145
|
* `import { env } from '$env/dynamic/private'` + `env.X`
|
|
145
146
|
* -> `import { X } from '$app/env/private'` + `X`
|
|
146
|
-
*
|
|
147
|
+
* and the same for `$env/dynamic/public` -> `$app/env/public` (the Supabase
|
|
148
|
+
* client reads PUBLIC_SUPABASE_* this way). Every name read is collected so
|
|
149
|
+
* src/env.ts can declare it, which v3 requires; public ones are declared
|
|
150
|
+
* `public: true`, or `$app/env/public` would not export them.
|
|
147
151
|
*/
|
|
148
152
|
function rewriteEnv(src, envNames) {
|
|
149
|
-
|
|
153
|
+
const kind = /from\s+['"]\$env\/dynamic\/private['"]/.test(src) ? 'private'
|
|
154
|
+
: /from\s+['"]\$env\/dynamic\/public['"]/.test(src) ? 'public' : null;
|
|
155
|
+
if (!kind)
|
|
150
156
|
return src;
|
|
151
157
|
const used = new Set();
|
|
152
158
|
// `(?<![.\w])` keeps `process.env.X` untouched; only the imported `env` changes.
|
|
@@ -155,9 +161,9 @@ function rewriteEnv(src, envNames) {
|
|
|
155
161
|
return name;
|
|
156
162
|
});
|
|
157
163
|
for (const n of used)
|
|
158
|
-
envNames.
|
|
164
|
+
envNames.set(n, kind === 'public' || envNames.get(n) === true);
|
|
159
165
|
const names = [...used].sort();
|
|
160
|
-
return body.replace(
|
|
166
|
+
return body.replace(new RegExp(`import\\s*\\{\\s*env\\s*\\}\\s*from\\s*(['"])\\$env\\/dynamic\\/${kind}\\1`), names.length ? `import { ${names.join(', ')} } from '$app/env/${kind}'` : '');
|
|
161
167
|
}
|
|
162
168
|
/**
|
|
163
169
|
* Types that moved out of `@sveltejs/kit`, and the deprecated `json` helper.
|
|
@@ -181,7 +187,7 @@ function rewriteKitImports(src) {
|
|
|
181
187
|
}
|
|
182
188
|
/* ------------------------------------------------------------------- env */
|
|
183
189
|
function envModule(names) {
|
|
184
|
-
const decls = names.map((n) => ` ${n}: { schema: (input) => input ?? '' },`).join('\n');
|
|
190
|
+
const decls = names.map(([n, pub]) => ` ${n}: { ${pub ? 'public: true, ' : ''}schema: (input) => input ?? '' },`).join('\n');
|
|
185
191
|
return {
|
|
186
192
|
path: 'src/env.ts',
|
|
187
193
|
description: 'Environment variables the app reads (SvelteKit 3 requires declaring them).',
|
|
@@ -7180,7 +7180,7 @@ export const GENERATED_UI_SURFACE = {
|
|
|
7180
7180
|
"key": "rowNumberWidth",
|
|
7181
7181
|
"label": "Row Number Width",
|
|
7182
7182
|
"type": "number",
|
|
7183
|
-
"description": "Width (px) of the row-number column.
|
|
7183
|
+
"description": "Width (px) of the row-number column. By default it fits the largest row number: 56px up to four digits, then 9px wider per digit (from `data.length`, or `rowCount` on a server-paged grid). Set it to pin a width, for example when a theme uses a much larger font.",
|
|
7184
7184
|
"group": "common"
|
|
7185
7185
|
},
|
|
7186
7186
|
{
|
package/dist/upgrade-prompt.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
/** Human-readable labels for the
|
|
1
|
+
/** Human-readable labels for the Enterprise surfaces that gate behind a license. */
|
|
2
2
|
export type EnterpriseFeatureLabel = 'Export' | 'Import' | 'Print' | 'AI assistant' | 'Pivot' | 'Server-side row model' | 'Spreadsheet' | 'Studio';
|
|
3
3
|
/**
|
|
4
4
|
* Show the contextual upgrade prompt for `feature`. No-ops if one has already
|
|
5
5
|
* been shown this session, a card is already up, or we're on the server. Safe
|
|
6
|
-
* to call on every
|
|
6
|
+
* to call on every Enterprise feature invocation - it self-throttles.
|
|
7
7
|
*/
|
|
8
8
|
export declare function showUpgradePrompt(feature?: EnterpriseFeatureLabel | string, opts?: {
|
|
9
9
|
expired?: boolean;
|
package/dist/upgrade-prompt.js
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
// Product-led-growth (PLG) upgrade nudge, shown at the *moment of intent*: the
|
|
2
|
-
// instant a developer actually calls
|
|
3
|
-
//
|
|
2
|
+
// instant a developer actually calls an Enterprise feature (export / import /
|
|
3
|
+
// print / pivot) without a license key set. Unlike the passive corner watermark
|
|
4
4
|
// (watermark.ts), this is a one-click contextual card that names the feature
|
|
5
|
-
// they just used and links
|
|
5
|
+
// they just used and links to the plans.
|
|
6
|
+
//
|
|
7
|
+
// The copy follows the one-key license (2026-10-07): there are no trial keys,
|
|
8
|
+
// unlicensed use simply runs with a watermark, and the product is "SvGrid
|
|
9
|
+
// Enterprise". The card used to say "Unlock SvGrid Pro" and "Start free trial",
|
|
10
|
+
// which promised a trial that does not exist.
|
|
6
11
|
//
|
|
7
12
|
// Rules of the road:
|
|
8
13
|
// - Soft, never blocking. The feature already ran; this only nudges.
|
|
@@ -18,15 +23,15 @@
|
|
|
18
23
|
// bundle, works in any host app regardless of its styling.
|
|
19
24
|
import { isFirstPartySite } from './first-party.js';
|
|
20
25
|
const CARD_ATTR = 'data-svgrid-enterprise-upgrade';
|
|
21
|
-
|
|
22
|
-
// ?ref=in-app lets us measure how many trials start from this exact prompt
|
|
26
|
+
// ?ref=in-app lets us measure how many purchases start from this exact prompt
|
|
23
27
|
// vs. the pricing page itself - the whole point of a moment-of-intent CTA.
|
|
24
|
-
const
|
|
28
|
+
const PLANS_URL = 'https://svgrid.com/pricing?ref=in-app&utm_source=svgrid-enterprise&utm_medium=upgrade-prompt';
|
|
29
|
+
const EVALUATION_URL = 'https://svgrid.com/docs/enterprise/evaluation/?utm_source=svgrid-enterprise&utm_medium=upgrade-prompt';
|
|
25
30
|
let shownThisSession = false;
|
|
26
31
|
/**
|
|
27
32
|
* Show the contextual upgrade prompt for `feature`. No-ops if one has already
|
|
28
33
|
* been shown this session, a card is already up, or we're on the server. Safe
|
|
29
|
-
* to call on every
|
|
34
|
+
* to call on every Enterprise feature invocation - it self-throttles.
|
|
30
35
|
*/
|
|
31
36
|
export function showUpgradePrompt(feature, opts) {
|
|
32
37
|
if (shownThisSession)
|
|
@@ -68,7 +73,7 @@ function buildCard(feature, expired = false) {
|
|
|
68
73
|
const card = document.createElement('div');
|
|
69
74
|
card.setAttribute(CARD_ATTR, '1');
|
|
70
75
|
card.setAttribute('role', 'dialog');
|
|
71
|
-
card.setAttribute('aria-label', expired ? 'Your
|
|
76
|
+
card.setAttribute('aria-label', expired ? 'Your evaluation has ended' : 'SvGrid Enterprise');
|
|
72
77
|
Object.assign(card.style, {
|
|
73
78
|
position: 'fixed',
|
|
74
79
|
bottom: '16px',
|
|
@@ -92,18 +97,18 @@ function buildCard(feature, expired = false) {
|
|
|
92
97
|
});
|
|
93
98
|
const featureName = feature ? String(feature) : 'This';
|
|
94
99
|
const featurePhrase = feature
|
|
95
|
-
? `<strong style="color:#fff">${escapeHtml(featureName)}</strong> is
|
|
96
|
-
: `You just used a <strong style="color:#fff">
|
|
97
|
-
// An expired
|
|
98
|
-
// they already evaluated, so the ask is to convert
|
|
99
|
-
const badge = expired ? '
|
|
100
|
-
const heading = expired ? 'Your
|
|
100
|
+
? `<strong style="color:#fff">${escapeHtml(featureName)}</strong> is part of SvGrid Enterprise.`
|
|
101
|
+
: `You just used a <strong style="color:#fff">SvGrid Enterprise</strong> feature.`;
|
|
102
|
+
// An expired evaluation is a different message from "you never had a
|
|
103
|
+
// license": they already evaluated, so the ask is to convert.
|
|
104
|
+
const badge = expired ? 'EVALUATION ENDED' : 'ENTERPRISE';
|
|
105
|
+
const heading = expired ? 'Your evaluation has ended' : 'SvGrid Enterprise';
|
|
101
106
|
const body = expired
|
|
102
|
-
? `${featurePhrase}
|
|
103
|
-
|
|
104
|
-
: `${featurePhrase} It
|
|
105
|
-
|
|
106
|
-
const cta = expired ? 'Buy a
|
|
107
|
+
? `${featurePhrase} Everything still works, but this notice stays until a
|
|
108
|
+
license key is set.`
|
|
109
|
+
: `${featurePhrase} It keeps working as it is, here and in production. A
|
|
110
|
+
license key removes the watermark and this notice.`;
|
|
111
|
+
const cta = expired ? 'Buy a license' : 'See plans';
|
|
107
112
|
card.innerHTML = `
|
|
108
113
|
<button type="button" data-act="x" aria-label="Dismiss"
|
|
109
114
|
style="position:absolute;top:8px;right:8px;width:24px;height:24px;display:flex;
|
|
@@ -118,21 +123,21 @@ function buildCard(feature, expired = false) {
|
|
|
118
123
|
${body}
|
|
119
124
|
</p>
|
|
120
125
|
<div style="display:flex;gap:8px;align-items:center;">
|
|
121
|
-
<a data-act="
|
|
126
|
+
<a data-act="plans" href="${PLANS_URL}" target="_blank" rel="noopener noreferrer"
|
|
122
127
|
style="flex:1;text-align:center;background:#6366f1;color:#fff;font-weight:600;
|
|
123
128
|
text-decoration:none;padding:8px 12px;border-radius:8px;">${cta}</a>
|
|
124
|
-
<a data-act="
|
|
125
|
-
style="color:#a5b4fc;text-decoration:none;padding:8px 6px;font-weight:600;">
|
|
129
|
+
<a data-act="evaluation" href="${EVALUATION_URL}" target="_blank" rel="noopener noreferrer"
|
|
130
|
+
style="color:#a5b4fc;text-decoration:none;padding:8px 6px;font-weight:600;">How evaluation works</a>
|
|
126
131
|
</div>
|
|
127
132
|
<p style="margin:10px 0 0;font-size:11px;color:#64748b;">
|
|
128
133
|
Already licensed? Call <code style="color:#94a3b8;">setLicenseKey()</code> at startup to hide this.
|
|
129
134
|
</p>
|
|
130
135
|
`;
|
|
131
136
|
card.querySelector('[data-act="x"]')?.addEventListener('click', () => close(card));
|
|
132
|
-
// Clicking through to
|
|
133
|
-
// card, but let the link open in its new tab first.
|
|
134
|
-
card.querySelector('[data-act="
|
|
135
|
-
card.querySelector('[data-act="
|
|
137
|
+
// Clicking through to the plans or the evaluation page also counts as
|
|
138
|
+
// "handled" - close the card, but let the link open in its new tab first.
|
|
139
|
+
card.querySelector('[data-act="plans"]')?.addEventListener('click', () => close(card));
|
|
140
|
+
card.querySelector('[data-act="evaluation"]')?.addEventListener('click', () => close(card));
|
|
136
141
|
return card;
|
|
137
142
|
}
|
|
138
143
|
function escapeHtml(s) {
|
package/dist/version.d.ts
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*
|
|
11
11
|
* `version.test.ts` asserts this matches `package.json`, so the two cannot drift.
|
|
12
12
|
*/
|
|
13
|
-
export declare const SVGRID_VERSION = "3.1.
|
|
13
|
+
export declare const SVGRID_VERSION = "3.1.8";
|
|
14
14
|
/**
|
|
15
15
|
* The version of `@svgrid/grid`, which releases on its own line: enterprise is
|
|
16
16
|
* on 3.1.x while the grid is on 3.0.x.
|
|
@@ -23,4 +23,4 @@ export declare const SVGRID_VERSION = "3.1.6";
|
|
|
23
23
|
*
|
|
24
24
|
* `version.test.ts` asserts this matches packages/grid/package.json.
|
|
25
25
|
*/
|
|
26
|
-
export declare const GRID_VERSION = "3.0.
|
|
26
|
+
export declare const GRID_VERSION = "3.0.11";
|