@canopypay/checkout-sdk 0.3.0 → 0.4.1
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/canopy.global.js +1 -1
- package/dist/index.cjs +467 -1
- package/dist/index.d.cts +59 -1
- package/dist/index.d.ts +59 -1
- package/dist/index.js +467 -1
- package/package.json +2 -2
package/dist/canopy.global.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";(()=>{(function(){"use strict";if(typeof window=="undefined")return;let f="width=460,height=640",y=2500,m="Pay with Canopy",h=500,g=420,v="canopy",b="cnpy_pk_live_";function k(){let e=document.currentScript;if(e&&e.src)try{return new URL(e.src).origin}catch(o){}let n=document.getElementsByTagName("script");for(let o=0;o<n.length;o+=1){let r=n[o].src;if(r&&/\/v1\/(?:[^/]+\/)?canopy\.js(?:[?#].*)?$/.test(r))try{return new URL(r).origin}catch(t){}}return null}function _(e){let n;try{n=new URL(e)}catch(t){return{ok:!1,code:"canopy_origin_invalid"}}if(!((n.pathname===""||n.pathname==="/")&&n.search===""&&n.hash===""))return{ok:!1,code:"canopy_origin_not_bare"};let r=n.hostname==="localhost"||n.hostname==="127.0.0.1";return n.protocol!=="https:"&&!r?{ok:!1,code:"canopy_origin_insecure"}:{ok:!0,origin:n.origin}}function E(e){if(e!==void 0)return _(e);let n=k();return n?{ok:!0,origin:n}:{ok:!1,code:"canopy_origin_undiscoverable"}}function c(e){let n=new URL("/customer-pay",e.origin);return n.searchParams.set("merchant",e.merchant),n.hash="cap="+encodeURIComponent(e.capability||""),n.toString()}function i(e,n,o){if(!e.destroyed)try{e.onEvent(Object.assign({type:n},o))}catch(r){}}function l(e){e.handshakeTimer&&(clearTimeout(e.handshakeTimer),e.handshakeTimer=null),e.resizeObserver&&(e.resizeObserver.disconnect(),e.resizeObserver=null),e.frame&&(e.frame.parentNode&&e.frame.parentNode.removeChild(e.frame),e.frame=null),e.lastHeight=null}function T(e){e.popupPollTimer&&clearInterval(e.popupPollTimer),e.popupPollTimer=setInterval(function(){try{e.popupWin&&e.popupWin.closed&&(e.popupPollTimer&&clearInterval(e.popupPollTimer),e.popupPollTimer=null,e.popupWin=null,i(e,"close",{via:"popup"}))}catch(n){e.popupPollTimer&&clearInterval(e.popupPollTimer),e.popupPollTimer=null}},h)}function p(e,n){if(!e.destroyed){if(!n){i(e,"error",{code:"popup_blocked"});return}if(!e.capability){try{n.close()}catch(o){}i(e,"error",{code:"capability_unavailable"});return}try{n.location.href=c(e)}catch(o){i(e,"error",{code:"popup_navigation_failed"});return}e.popupWin=n,T(e)}}function w(e){let n=document.createElement("button");n.type="button",n.textContent=e.fallbackLabel;let o=n.style;o.background="#1A7A4C",o.color="#FFFFFF",o.border="none",o.borderRadius="8px",o.height="48px",o.padding="0 20px",o.fontSize="16px",o.fontFamily="inherit",o.cursor="pointer",o.maxWidth="100%",o.overflow="hidden",o.textOverflow="ellipsis",o.whiteSpace="nowrap",o.display="inline-block",n.addEventListener("click",function(){let r=window.open("","canopy_checkout",f);p(e,r)}),e.node.appendChild(n),e.fallbackButton=n,i(e,"fallback_offered",{surface:"popup",reason:"iframe_unavailable"})}function O(e){let n=document.createElement("iframe");n.src=c(e),n.style.width="100%",n.style.border="none",n.setAttribute("allow","clipboard-write"),n.setAttribute("title","Canopy checkout"),n.style.height=g+"px",e.node.appendChild(n),e.frame=n,typeof ResizeObserver!="undefined"&&(e.resizeObserver=new ResizeObserver(function(o){for(let r=0;r<o.length;r+=1){let t=Math.round(o[r].contentRect.height);t>0&&t!==e.lastHeight&&(e.lastHeight=t,i(e,"resize",{height:t}))}}),e.resizeObserver.observe(n)),e.handshakeTimer=setTimeout(function(){e.handshakeTimer=null,i(e,"surface_unavailable",{attempted:"iframe"}),l(e),e.surface==="auto"?w(e):i(e,"error",{code:"iframe_blocked"})},e.handshakeTimeoutMs)}function L(e,n){if(n.origin!==e.origin)return;let o=n.data;if(!(!o||o.source!==v)){if(o.type==="ready"){e.handshakeTimer&&(clearTimeout(e.handshakeTimer),e.handshakeTimer=null),i(e,"ready");return}if(o.type==="resize"&&typeof o.height=="number"&&e.frame){e.frame.style.height=o.height+"px";return}if(o.type==="paid"){i(e,"paid",o);return}if(o.type==="close"){i(e,"close");return}}}let s=new WeakMap;function R(e){if(typeof e.merchant!="string"||e.merchant.indexOf(b)!==0){try{(e.onEvent||function(){})({type:"error",code:"invalid_merchant_key"})}catch(a){}return{openNow:function(){},destroy:function(){}}}let n=E(e.canopyOrigin);if(!n.ok){try{(e.onEvent||function(){})({type:"error",code:n.code})}catch(a){}return{openNow:function(){},destroy:function(){}}}let o=typeof e.target=="string"?document.querySelector(e.target):e.target;if(!o)return{openNow:function(){},destroy:function(){}};let r=s.get(o);if(r)return r;let t={node:o,capability:e.capability,merchant:e.merchant,origin:n.origin,surface:e.surface||"popup",handshakeTimeoutMs:e.handshakeTimeoutMs||y,fallbackLabel:e.fallbackLabel||m,onEvent:e.onEvent||function(){},destroyed:!1,messageListener:function(){},handshakeTimer:null,resizeObserver:null,frame:null,fallbackButton:null,lastHeight:null,popupWin:null,popupPollTimer:null};t.messageListener=function(a){L(t,a)},window.addEventListener("message",t.messageListener),(t.surface==="iframe"||t.surface==="auto")&&O(t);let d={openNow:function(a){p(t,a)},destroy:function(){t.destroyed||(t.destroyed=!0,window.removeEventListener("message",t.messageListener),l(t),t.popupPollTimer&&(clearInterval(t.popupPollTimer),t.popupPollTimer=null),t.fallbackButton&&(t.fallbackButton.parentNode&&t.fallbackButton.parentNode.removeChild(t.fallbackButton),t.fallbackButton=null),s.delete(o))}};return s.set(o,d),d}let u=window;u.Canopy&&u.Canopy.__version==="3"||(u.Canopy={mount:R,__version:"3"})})();})();
|
|
1
|
+
"use strict";(()=>{var B="theme";var T=["accent","background","surface","text","muted","border","radius","font"],U=new Map([["accent",{kind:"colour",targets:["--leaf","--primary","--accent","--ring"]}],["background",{kind:"colour",targets:["--paper","--background","background"]}],["surface",{kind:"colour",targets:["--surface","--card","--popover","--secondary"]}],["text",{kind:"colour",targets:["--ink","--foreground","--card-foreground","--popover-foreground","--secondary-foreground"]}],["muted",{kind:"colour",targets:["--ink-muted","--muted-foreground"]}],["border",{kind:"colour",targets:["--line","--border","--input"]}],["radius",{kind:"length",targets:["--radius"]}],["font",{kind:"font",targets:["--font-sans"]}]]),q=/^#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/,Z=/^(rgb|rgba|hsl|hsla)\(([0-9a-z.,%/ +-]*)\)$/,J=/^[+-]?(?:[0-9]{1,4}(?:\.[0-9]{1,4})?|\.[0-9]{1,4})$/,Q=/^[+-]?(?:[0-9]{1,3}(?:\.[0-9]{1,4})?|\.[0-9]{1,4})%$/,ee=/^(?:0|(?:[0-9]{1,4}(?:\.[0-9]{1,4})?|\.[0-9]{1,4})(?:px|rem|em|%))$/,ne=/^[A-Za-z0-9 ,_-]+$/,te=new Map([["transparent",{r:0,g:0,b:0,a:0}],["black",{r:0,g:0,b:0,a:1}],["white",{r:255,g:255,b:255,a:1}],["silver",{r:192,g:192,b:192,a:1}],["gray",{r:128,g:128,b:128,a:1}],["grey",{r:128,g:128,b:128,a:1}],["maroon",{r:128,g:0,b:0,a:1}],["red",{r:255,g:0,b:0,a:1}],["purple",{r:128,g:0,b:128,a:1}],["fuchsia",{r:255,g:0,b:255,a:1}],["magenta",{r:255,g:0,b:255,a:1}],["green",{r:0,g:128,b:0,a:1}],["lime",{r:0,g:255,b:0,a:1}],["olive",{r:128,g:128,b:0,a:1}],["yellow",{r:255,g:255,b:0,a:1}],["navy",{r:0,g:0,b:128,a:1}],["blue",{r:0,g:0,b:255,a:1}],["teal",{r:0,g:128,b:128,a:1}],["aqua",{r:0,g:255,b:255,a:1}],["cyan",{r:0,g:255,b:255,a:1}],["orange",{r:255,g:165,b:0,a:1}],["pink",{r:255,g:192,b:203,a:1}],["brown",{r:165,g:42,b:42,a:1}],["beige",{r:245,g:245,b:220,a:1}],["ivory",{r:255,g:255,b:240,a:1}],["indigo",{r:75,g:0,b:130,a:1}],["violet",{r:238,g:130,b:238,a:1}],["gold",{r:255,g:215,b:0,a:1}],["crimson",{r:220,g:20,b:60,a:1}],["salmon",{r:250,g:128,b:114,a:1}],["khaki",{r:240,g:230,b:140,a:1}],["lavender",{r:230,g:230,b:250,a:1}],["turquoise",{r:64,g:224,b:208,a:1}],["tan",{r:210,g:180,b:140,a:1}],["plum",{r:221,g:160,b:221,a:1}],["orchid",{r:218,g:112,b:214,a:1}],["coral",{r:255,g:127,b:80,a:1}],["tomato",{r:255,g:99,b:71,a:1}],["chocolate",{r:210,g:105,b:30,a:1}],["snow",{r:255,g:250,b:250,a:1}],["linen",{r:250,g:240,b:230,a:1}],["azure",{r:240,g:255,b:255,a:1}],["wheat",{r:245,g:222,b:179,a:1}],["thistle",{r:216,g:191,b:216,a:1}]]),re=new Set(["transparent","currentcolor","inherit","initial","unset","revert","revert-layer"]),oe=new Set(["text","muted","accent"]);function y(t,n,o){return t<n?n:t>o?o:t}function x(t){if(!J.test(t))return null;let n=Number(t);return Number.isFinite(n)?n:null}function v(t){if(!Q.test(t))return null;let n=Number(t.slice(0,t.length-1));return Number.isFinite(n)?n/100:null}function A(t){let n=v(t);if(n!==null)return y(n,0,1)*255;let o=x(t);return o===null?null:y(o,0,255)}function ae(t){let n=v(t);if(n!==null)return y(n,0,1);let o=x(t);return o===null?null:y(o,0,1)}function ie(t){let n=t,o=1;n.endsWith("deg")?n=n.slice(0,n.length-3):n.endsWith("grad")?(n=n.slice(0,n.length-4),o=360/400):n.endsWith("turn")?(n=n.slice(0,n.length-4),o=360):n.endsWith("rad")&&(n=n.slice(0,n.length-3),o=180/Math.PI);let r=x(n);return r===null?null:(r*o%360+360)%360}function C(t,n,o){let r=o;return r<0&&(r+=1),r>1&&(r-=1),r<1/6?t+(n-t)*6*r:r<1/2?n:r<2/3?t+(n-t)*(2/3-r)*6:t}function le(t,n,o,r){if(n===0){let l=o*255;return{r:l,g:l,b:l,a:r}}let u=o<.5?o*(1+n):o+n-o*n,d=2*o-u,s=t/360;return{r:C(d,u,s+1/3)*255,g:C(d,u,s)*255,b:C(d,u,s-1/3)*255,a:r}}function se(t){let n=t.trim();if(n==="")return null;if(n.indexOf(",")>=0){if(n.indexOf("/")>=0)return null;let d=n.split(",").map(function(s){return s.trim()});return d.length!==3&&d.length!==4?null:d}let o=n.split("/");if(o.length>2)return null;let r=o[0].trim().split(/ +/);if(r.length!==3)return null;if(o.length===1)return r;let u=o[1].trim();return u===""||u.indexOf(" ")>=0?null:r.concat([u])}function ue(t){let n=Z.exec(t);if(n===null)return null;let o=n[1],r=se(n[2]);if(r===null)return null;let u=1;if(r.length===4){let c=ae(r[3]);if(c===null)return null;u=c}if(o==="rgb"||o==="rgba"){let c=A(r[0]),f=A(r[1]),h=A(r[2]);return c===null||f===null||h===null?null:{r:c,g:f,b:h,a:u}}let d=ie(r[0]),s=v(r[1]),l=v(r[2]);return d===null||s===null||l===null?null:le(d,y(s,0,1),y(l,0,1),u)}function ce(t){if(!q.test(t))return null;let n=t.slice(1),o=n.length===3||n.length===4,r=o?1:2,u=function(s){let l=n.slice(s*r,s*r+r);return parseInt(o?l+l:l,16)},d=n.length===4||n.length===8;return{r:u(0),g:u(1),b:u(2),a:d?u(3)/255:1}}function R(t){let n=ce(t);if(n!==null)return n;let o=ue(t);if(o!==null)return o;let r=te.get(t.toLowerCase());return r===void 0?null:r}function O(t){let n=t/255;return n<=.03928?n/12.92:Math.pow((n+.055)/1.055,2.4)}function N(t){return .2126*O(t.r)+.7152*O(t.g)+.0722*O(t.b)}function L(t,n){let o=N(t),r=N(n),u=o>r?o:r,d=o>r?r:o;return(u+.05)/(d+.05)}function w(t,n){return t.a>=1?t:{r:t.r*t.a+n.r*(1-t.a),g:t.g*t.a+n.g*(1-t.a),b:t.b*t.a+n.b*(1-t.a),a:1}}var H=3,de={light:[{r:243,g:250,b:246,a:1},{r:255,g:255,b:255,a:1}],dark:[{r:10,g:22,b:40,a:1},{r:26,g:40,b:60,a:1}]},S={r:255,g:255,b:255,a:1};function fe(t,n){let o=n===null?["light","dark"]:[n],r=[];for(let l=0;l<o.length;l+=1){let c=de[o[l]];for(let f=0;f<c.length;f+=1)r.push(c[f])}let u=[],d=["surface","background"];for(let l=0;l<d.length;l+=1){let c=t[d[l]];if(c===void 0)continue;let f=R(c);f!==null&&u.push(f)}if(u.length===0)return r;let s=[];for(let l=0;l<u.length;l+=1){let c=u[l];if(c.a>=1){s.push(c);continue}for(let f=0;f<r.length;f+=1)s.push(w(c,r[f]))}return s}function pe(t,n,o){let r=fe(t,o),u=t.text;if(u!==void 0){let s=R(u),l=1/0;if(s===null)l=0;else for(let c=0;c<r.length;c+=1){let f=r[c],h=L(w(s,f),f);h<l&&(l=h)}l<H&&(delete t.text,n.push({key:"text",code:"variable_contrast_too_low"}))}let d=t.accent;if(d!==void 0){let s=R(d),l=1/0;if(s===null)l=0;else if(s.a>=1)l=L(s,S);else for(let c=0;c<r.length;c+=1){let f=L(w(s,r[c]),S);f<l&&(l=f)}l<H&&(delete t.accent,n.push({key:"accent",code:"variable_contrast_too_low"}))}}function ge(t,n){return t==="colour"?R(n)!==null:t==="length"?ee.test(n):ne.test(n)}function be(t,n){let o=U.get(t);return o===void 0?{code:"unknown_variable",value:""}:typeof n!="string"?{code:"variable_not_a_string",value:""}:n.length>64?{code:"variable_value_too_long",value:""}:o.kind==="colour"&&oe.has(t)&&re.has(n.toLowerCase())?{code:"variable_value_erases_content",value:""}:ge(o.kind,n)?{code:null,value:n}:{code:"variable_value_malformed",value:""}}function j(t,n=null){let o={},r=[];if(t===null||typeof t!="object"||Array.isArray(t))return{accepted:{},declarations:{},rejections:[]};let u=Object.keys(t);for(let s=0;s<u.length;s+=1){let l=u[s];if(s>=12){r.push({key:l,code:"too_many_variables"});break}let c=be(l,t[l]);if(c.code!==null){r.push({key:l,code:c.code});continue}o[l]=c.value}pe(o,r,n);let d={};for(let s of T){let l=o[s];if(l===void 0)continue;let c=U.get(s).targets;for(let f=0;f<c.length;f+=1)d[c[f]]=l}return{accepted:o,declarations:d,rejections:r}}function z(t){return t==="light"||t==="dark"?t:null}var W="5";(function(){"use strict";if(typeof window=="undefined")return;let t="width=460,height=640",n=2500,o="Pay with Canopy",r=500,u=420,d=46,s="canopy",l="cnpy_pk_live_";function c(){let e=document.currentScript;if(e&&e.src)try{return new URL(e.src).origin}catch(i){}let a=document.getElementsByTagName("script");for(let i=0;i<a.length;i+=1){let p=a[i].src;if(p&&/\/v1\/(?:[^/]+\/)?canopy\.js(?:[?#].*)?$/.test(p))try{return new URL(p).origin}catch(b){}}return null}function f(e){let a;try{a=new URL(e)}catch(b){return{ok:!1,code:"canopy_origin_invalid"}}if(!((a.pathname===""||a.pathname==="/")&&a.search===""&&a.hash===""))return{ok:!1,code:"canopy_origin_not_bare"};let p=a.hostname==="localhost"||a.hostname==="127.0.0.1";return a.protocol!=="https:"&&!p?{ok:!1,code:"canopy_origin_insecure"}:{ok:!0,origin:a.origin}}function h(e){if(e!==void 0)return f(e);let a=c();return a?{ok:!0,origin:a}:{ok:!1,code:"canopy_origin_undiscoverable"}}function I(e){let a=new URL("/customer-pay",e.origin);a.searchParams.set("merchant",e.merchant),e.theme!==null&&a.searchParams.set(B,e.theme);for(let i=0;i<T.length;i+=1){let p=T[i],b=e.themeVariables[p];b!==void 0&&a.searchParams.set("v."+p,b)}return a.hash="cap="+encodeURIComponent(e.capability||""),a.toString()}function m(e,a,i){if(!e.destroyed)try{e.onEvent(Object.assign({type:a},i))}catch(p){}}function K(e,a){for(let i=0;i<a.length;i+=1){let p=a[i];m(e,"error",{code:p.code,variable:p.key})}}function M(e){e.handshakeTimer&&(clearTimeout(e.handshakeTimer),e.handshakeTimer=null),e.resizeObserver&&(e.resizeObserver.disconnect(),e.resizeObserver=null),e.frame&&(e.frame.parentNode&&e.frame.parentNode.removeChild(e.frame),e.frame=null),e.lastHeight=null}function G(e){e.popupPollTimer&&clearInterval(e.popupPollTimer),e.popupPollTimer=setInterval(function(){try{e.popupWin&&e.popupWin.closed&&(e.popupPollTimer&&clearInterval(e.popupPollTimer),e.popupPollTimer=null,e.popupWin=null,m(e,"close",{via:"popup"}))}catch(a){e.popupPollTimer&&clearInterval(e.popupPollTimer),e.popupPollTimer=null}},r)}function V(e,a){if(!e.destroyed){if(!a){m(e,"error",{code:"popup_blocked"});return}if(!e.capability){try{a.close()}catch(i){}m(e,"error",{code:"capability_unavailable"});return}try{a.location.href=I(e)}catch(i){m(e,"error",{code:"popup_navigation_failed"});return}e.popupWin=a,G(e)}}function X(e){let a=document.createElement("button");a.type="button",a.textContent=e.fallbackLabel;let i=a.style;i.background="#1A7A4C",i.color="#FFFFFF",i.border="none",i.borderRadius="8px",i.height="48px",i.padding="0 20px",i.fontSize="16px",i.fontFamily="inherit",i.cursor="pointer",i.maxWidth="100%",i.overflow="hidden",i.textOverflow="ellipsis",i.whiteSpace="nowrap",i.display="inline-block",a.addEventListener("click",function(){let p=window.open("","canopy_checkout",t);V(e,p)}),e.node.appendChild(a),e.fallbackButton=a,m(e,"fallback_offered",{surface:"popup",reason:"iframe_unavailable"})}function D(e){let a=document.createElement("iframe");a.src=I(e),a.style.width="100%",a.style.border="none",a.setAttribute("allow","clipboard-write"),a.setAttribute("title","Canopy checkout"),a.style.height=u+"px",e.node.appendChild(a),e.frame=a,typeof ResizeObserver!="undefined"&&(e.resizeObserver=new ResizeObserver(function(i){for(let p=0;p<i.length;p+=1){let b=Math.round(i[p].contentRect.height);b>0&&b!==e.lastHeight&&(e.lastHeight=b,m(e,"resize",{height:b}))}}),e.resizeObserver.observe(a)),e.handshakeTimer=setTimeout(function(){e.handshakeTimer=null,m(e,"surface_unavailable",{attempted:"iframe"}),M(e),e.surface==="auto"?X(e):m(e,"error",{code:"iframe_blocked"})},e.handshakeTimeoutMs)}function $(e,a){if(a.origin!==e.origin)return;let i=a.data;if(!(!i||i.source!==s)){if(i.type==="ready"){e.handshakeTimer&&(clearTimeout(e.handshakeTimer),e.handshakeTimer=null),m(e,"ready");return}if(i.type==="resize"&&typeof i.height=="number"&&e.frame){if(!(i.height>=d))return;e.frame.style.height=i.height+"px";return}if(i.type==="paid"){m(e,"paid",i);return}if(i.type==="close"){m(e,"close");return}}}let E=new WeakMap;function Y(e){if(typeof e.merchant!="string"||e.merchant.indexOf(l)!==0){try{(e.onEvent||function(){})({type:"error",code:"invalid_merchant_key"})}catch(_){}return{openNow:function(){},destroy:function(){}}}let a=h(e.canopyOrigin);if(!a.ok){try{(e.onEvent||function(){})({type:"error",code:a.code})}catch(_){}return{openNow:function(){},destroy:function(){}}}let i=z(e.theme),p=j(e.variables,i),b=typeof e.target=="string"?document.querySelector(e.target):e.target;if(!b)return{openNow:function(){},destroy:function(){}};let P=E.get(b);if(P)return P;let g={node:b,capability:e.capability,merchant:e.merchant,origin:a.origin,theme:i,themeVariables:p.accepted,surface:e.surface||"popup",handshakeTimeoutMs:e.handshakeTimeoutMs||n,fallbackLabel:e.fallbackLabel||o,onEvent:e.onEvent||function(){},destroyed:!1,messageListener:function(){},handshakeTimer:null,resizeObserver:null,frame:null,fallbackButton:null,lastHeight:null,popupWin:null,popupPollTimer:null};g.messageListener=function(_){$(g,_)},window.addEventListener("message",g.messageListener),K(g,p.rejections),(g.surface==="iframe"||g.surface==="auto")&&D(g);let F={openNow:function(_){V(g,_)},destroy:function(){g.destroyed||(g.destroyed=!0,window.removeEventListener("message",g.messageListener),M(g),g.popupPollTimer&&(clearInterval(g.popupPollTimer),g.popupPollTimer=null),g.fallbackButton&&(g.fallbackButton.parentNode&&g.fallbackButton.parentNode.removeChild(g.fallbackButton),g.fallbackButton=null),E.delete(b))}};return E.set(b,F),F}let k=window;k.Canopy&&k.Canopy.__version===W||(k.Canopy={mount:Y,__version:W})})();})();
|
package/dist/index.cjs
CHANGED
|
@@ -25,8 +25,449 @@ __export(src_exports, {
|
|
|
25
25
|
});
|
|
26
26
|
module.exports = __toCommonJS(src_exports);
|
|
27
27
|
|
|
28
|
+
// src/theme.ts
|
|
29
|
+
var THEME_PARAM = "theme";
|
|
30
|
+
var THEME_VARIABLE_PARAM_PREFIX = "v.";
|
|
31
|
+
var MAX_THEME_VARIABLE_VALUE_LENGTH = 64;
|
|
32
|
+
var MAX_THEME_VARIABLE_ENTRIES = 12;
|
|
33
|
+
var CANOPY_THEME_VARIABLES = [
|
|
34
|
+
"accent",
|
|
35
|
+
"background",
|
|
36
|
+
"surface",
|
|
37
|
+
"text",
|
|
38
|
+
"muted",
|
|
39
|
+
"border",
|
|
40
|
+
"radius",
|
|
41
|
+
"font"
|
|
42
|
+
];
|
|
43
|
+
var VARIABLE_TARGETS = /* @__PURE__ */ new Map([
|
|
44
|
+
[
|
|
45
|
+
"accent",
|
|
46
|
+
{
|
|
47
|
+
kind: "colour",
|
|
48
|
+
targets: ["--leaf", "--primary", "--accent", "--ring"]
|
|
49
|
+
}
|
|
50
|
+
],
|
|
51
|
+
[
|
|
52
|
+
"background",
|
|
53
|
+
{
|
|
54
|
+
kind: "colour",
|
|
55
|
+
targets: ["--paper", "--background", "background"]
|
|
56
|
+
}
|
|
57
|
+
],
|
|
58
|
+
[
|
|
59
|
+
"surface",
|
|
60
|
+
{
|
|
61
|
+
kind: "colour",
|
|
62
|
+
targets: ["--surface", "--card", "--popover", "--secondary"]
|
|
63
|
+
}
|
|
64
|
+
],
|
|
65
|
+
[
|
|
66
|
+
"text",
|
|
67
|
+
{
|
|
68
|
+
kind: "colour",
|
|
69
|
+
targets: [
|
|
70
|
+
"--ink",
|
|
71
|
+
"--foreground",
|
|
72
|
+
"--card-foreground",
|
|
73
|
+
"--popover-foreground",
|
|
74
|
+
"--secondary-foreground"
|
|
75
|
+
]
|
|
76
|
+
}
|
|
77
|
+
],
|
|
78
|
+
[
|
|
79
|
+
"muted",
|
|
80
|
+
{
|
|
81
|
+
kind: "colour",
|
|
82
|
+
targets: ["--ink-muted", "--muted-foreground"]
|
|
83
|
+
}
|
|
84
|
+
],
|
|
85
|
+
[
|
|
86
|
+
"border",
|
|
87
|
+
{ kind: "colour", targets: ["--line", "--border", "--input"] }
|
|
88
|
+
],
|
|
89
|
+
["radius", { kind: "length", targets: ["--radius"] }],
|
|
90
|
+
["font", { kind: "font", targets: ["--font-sans"] }]
|
|
91
|
+
]);
|
|
92
|
+
var COLOUR_HEX = /^#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;
|
|
93
|
+
var COLOUR_FUNCTION = /^(rgb|rgba|hsl|hsla)\(([0-9a-z.,%/ +-]*)\)$/;
|
|
94
|
+
var NUMBER = /^[+-]?(?:[0-9]{1,4}(?:\.[0-9]{1,4})?|\.[0-9]{1,4})$/;
|
|
95
|
+
var PERCENT = /^[+-]?(?:[0-9]{1,3}(?:\.[0-9]{1,4})?|\.[0-9]{1,4})%$/;
|
|
96
|
+
var LENGTH = /^(?:0|(?:[0-9]{1,4}(?:\.[0-9]{1,4})?|\.[0-9]{1,4})(?:px|rem|em|%))$/;
|
|
97
|
+
var FONT_FAMILY_LIST = /^[A-Za-z0-9 ,_-]+$/;
|
|
98
|
+
var NAMED_COLOURS = /* @__PURE__ */ new Map([
|
|
99
|
+
["transparent", { r: 0, g: 0, b: 0, a: 0 }],
|
|
100
|
+
["black", { r: 0, g: 0, b: 0, a: 1 }],
|
|
101
|
+
["white", { r: 255, g: 255, b: 255, a: 1 }],
|
|
102
|
+
["silver", { r: 192, g: 192, b: 192, a: 1 }],
|
|
103
|
+
["gray", { r: 128, g: 128, b: 128, a: 1 }],
|
|
104
|
+
["grey", { r: 128, g: 128, b: 128, a: 1 }],
|
|
105
|
+
["maroon", { r: 128, g: 0, b: 0, a: 1 }],
|
|
106
|
+
["red", { r: 255, g: 0, b: 0, a: 1 }],
|
|
107
|
+
["purple", { r: 128, g: 0, b: 128, a: 1 }],
|
|
108
|
+
["fuchsia", { r: 255, g: 0, b: 255, a: 1 }],
|
|
109
|
+
["magenta", { r: 255, g: 0, b: 255, a: 1 }],
|
|
110
|
+
["green", { r: 0, g: 128, b: 0, a: 1 }],
|
|
111
|
+
["lime", { r: 0, g: 255, b: 0, a: 1 }],
|
|
112
|
+
["olive", { r: 128, g: 128, b: 0, a: 1 }],
|
|
113
|
+
["yellow", { r: 255, g: 255, b: 0, a: 1 }],
|
|
114
|
+
["navy", { r: 0, g: 0, b: 128, a: 1 }],
|
|
115
|
+
["blue", { r: 0, g: 0, b: 255, a: 1 }],
|
|
116
|
+
["teal", { r: 0, g: 128, b: 128, a: 1 }],
|
|
117
|
+
["aqua", { r: 0, g: 255, b: 255, a: 1 }],
|
|
118
|
+
["cyan", { r: 0, g: 255, b: 255, a: 1 }],
|
|
119
|
+
["orange", { r: 255, g: 165, b: 0, a: 1 }],
|
|
120
|
+
["pink", { r: 255, g: 192, b: 203, a: 1 }],
|
|
121
|
+
["brown", { r: 165, g: 42, b: 42, a: 1 }],
|
|
122
|
+
["beige", { r: 245, g: 245, b: 220, a: 1 }],
|
|
123
|
+
["ivory", { r: 255, g: 255, b: 240, a: 1 }],
|
|
124
|
+
["indigo", { r: 75, g: 0, b: 130, a: 1 }],
|
|
125
|
+
["violet", { r: 238, g: 130, b: 238, a: 1 }],
|
|
126
|
+
["gold", { r: 255, g: 215, b: 0, a: 1 }],
|
|
127
|
+
["crimson", { r: 220, g: 20, b: 60, a: 1 }],
|
|
128
|
+
["salmon", { r: 250, g: 128, b: 114, a: 1 }],
|
|
129
|
+
["khaki", { r: 240, g: 230, b: 140, a: 1 }],
|
|
130
|
+
["lavender", { r: 230, g: 230, b: 250, a: 1 }],
|
|
131
|
+
["turquoise", { r: 64, g: 224, b: 208, a: 1 }],
|
|
132
|
+
["tan", { r: 210, g: 180, b: 140, a: 1 }],
|
|
133
|
+
["plum", { r: 221, g: 160, b: 221, a: 1 }],
|
|
134
|
+
["orchid", { r: 218, g: 112, b: 214, a: 1 }],
|
|
135
|
+
["coral", { r: 255, g: 127, b: 80, a: 1 }],
|
|
136
|
+
["tomato", { r: 255, g: 99, b: 71, a: 1 }],
|
|
137
|
+
["chocolate", { r: 210, g: 105, b: 30, a: 1 }],
|
|
138
|
+
["snow", { r: 255, g: 250, b: 250, a: 1 }],
|
|
139
|
+
["linen", { r: 250, g: 240, b: 230, a: 1 }],
|
|
140
|
+
["azure", { r: 240, g: 255, b: 255, a: 1 }],
|
|
141
|
+
["wheat", { r: 245, g: 222, b: 179, a: 1 }],
|
|
142
|
+
["thistle", { r: 216, g: 191, b: 216, a: 1 }]
|
|
143
|
+
]);
|
|
144
|
+
var CONTENT_ERASING_COLOURS = /* @__PURE__ */ new Set([
|
|
145
|
+
"transparent",
|
|
146
|
+
"currentcolor",
|
|
147
|
+
"inherit",
|
|
148
|
+
"initial",
|
|
149
|
+
"unset",
|
|
150
|
+
"revert",
|
|
151
|
+
"revert-layer"
|
|
152
|
+
]);
|
|
153
|
+
var FOREGROUND_VARIABLES = /* @__PURE__ */ new Set([
|
|
154
|
+
"text",
|
|
155
|
+
"muted",
|
|
156
|
+
"accent"
|
|
157
|
+
]);
|
|
158
|
+
function clamp(value, low, high) {
|
|
159
|
+
if (value < low) return low;
|
|
160
|
+
if (value > high) return high;
|
|
161
|
+
return value;
|
|
162
|
+
}
|
|
163
|
+
function parseNumber(token) {
|
|
164
|
+
if (!NUMBER.test(token)) return null;
|
|
165
|
+
const value = Number(token);
|
|
166
|
+
return Number.isFinite(value) ? value : null;
|
|
167
|
+
}
|
|
168
|
+
function parsePercent(token) {
|
|
169
|
+
if (!PERCENT.test(token)) return null;
|
|
170
|
+
const value = Number(token.slice(0, token.length - 1));
|
|
171
|
+
return Number.isFinite(value) ? value / 100 : null;
|
|
172
|
+
}
|
|
173
|
+
function parseRgbComponent(token) {
|
|
174
|
+
const percent = parsePercent(token);
|
|
175
|
+
if (percent !== null) return clamp(percent, 0, 1) * 255;
|
|
176
|
+
const number = parseNumber(token);
|
|
177
|
+
if (number === null) return null;
|
|
178
|
+
return clamp(number, 0, 255);
|
|
179
|
+
}
|
|
180
|
+
function parseAlpha(token) {
|
|
181
|
+
const percent = parsePercent(token);
|
|
182
|
+
if (percent !== null) return clamp(percent, 0, 1);
|
|
183
|
+
const number = parseNumber(token);
|
|
184
|
+
if (number === null) return null;
|
|
185
|
+
return clamp(number, 0, 1);
|
|
186
|
+
}
|
|
187
|
+
function parseHue(token) {
|
|
188
|
+
let text = token;
|
|
189
|
+
let scale = 1;
|
|
190
|
+
if (text.endsWith("deg")) text = text.slice(0, text.length - 3);
|
|
191
|
+
else if (text.endsWith("grad")) {
|
|
192
|
+
text = text.slice(0, text.length - 4);
|
|
193
|
+
scale = 360 / 400;
|
|
194
|
+
} else if (text.endsWith("turn")) {
|
|
195
|
+
text = text.slice(0, text.length - 4);
|
|
196
|
+
scale = 360;
|
|
197
|
+
} else if (text.endsWith("rad")) {
|
|
198
|
+
text = text.slice(0, text.length - 3);
|
|
199
|
+
scale = 180 / Math.PI;
|
|
200
|
+
}
|
|
201
|
+
const number = parseNumber(text);
|
|
202
|
+
if (number === null) return null;
|
|
203
|
+
return (number * scale % 360 + 360) % 360;
|
|
204
|
+
}
|
|
205
|
+
function hueToChannel(p, q, tRaw) {
|
|
206
|
+
let t = tRaw;
|
|
207
|
+
if (t < 0) t += 1;
|
|
208
|
+
if (t > 1) t -= 1;
|
|
209
|
+
if (t < 1 / 6) return p + (q - p) * 6 * t;
|
|
210
|
+
if (t < 1 / 2) return q;
|
|
211
|
+
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
|
|
212
|
+
return p;
|
|
213
|
+
}
|
|
214
|
+
function hslToRgb(h, s, l, a) {
|
|
215
|
+
if (s === 0) {
|
|
216
|
+
const grey = l * 255;
|
|
217
|
+
return { r: grey, g: grey, b: grey, a };
|
|
218
|
+
}
|
|
219
|
+
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
|
220
|
+
const p = 2 * l - q;
|
|
221
|
+
const hk = h / 360;
|
|
222
|
+
return {
|
|
223
|
+
r: hueToChannel(p, q, hk + 1 / 3) * 255,
|
|
224
|
+
g: hueToChannel(p, q, hk) * 255,
|
|
225
|
+
b: hueToChannel(p, q, hk - 1 / 3) * 255,
|
|
226
|
+
a
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
function splitColourComponents(body) {
|
|
230
|
+
const trimmed = body.trim();
|
|
231
|
+
if (trimmed === "") return null;
|
|
232
|
+
if (trimmed.indexOf(",") >= 0) {
|
|
233
|
+
if (trimmed.indexOf("/") >= 0) return null;
|
|
234
|
+
const parts = trimmed.split(",").map(function(part) {
|
|
235
|
+
return part.trim();
|
|
236
|
+
});
|
|
237
|
+
if (parts.length !== 3 && parts.length !== 4) return null;
|
|
238
|
+
return parts;
|
|
239
|
+
}
|
|
240
|
+
const slashParts = trimmed.split("/");
|
|
241
|
+
if (slashParts.length > 2) return null;
|
|
242
|
+
const main = slashParts[0].trim().split(/ +/);
|
|
243
|
+
if (main.length !== 3) return null;
|
|
244
|
+
if (slashParts.length === 1) return main;
|
|
245
|
+
const alpha = slashParts[1].trim();
|
|
246
|
+
if (alpha === "" || alpha.indexOf(" ") >= 0) return null;
|
|
247
|
+
return main.concat([alpha]);
|
|
248
|
+
}
|
|
249
|
+
function parseColourFunction(value) {
|
|
250
|
+
const match = COLOUR_FUNCTION.exec(value);
|
|
251
|
+
if (match === null) return null;
|
|
252
|
+
const fn = match[1];
|
|
253
|
+
const parts = splitColourComponents(match[2]);
|
|
254
|
+
if (parts === null) return null;
|
|
255
|
+
let alpha = 1;
|
|
256
|
+
if (parts.length === 4) {
|
|
257
|
+
const parsed = parseAlpha(parts[3]);
|
|
258
|
+
if (parsed === null) return null;
|
|
259
|
+
alpha = parsed;
|
|
260
|
+
}
|
|
261
|
+
if (fn === "rgb" || fn === "rgba") {
|
|
262
|
+
const r = parseRgbComponent(parts[0]);
|
|
263
|
+
const g = parseRgbComponent(parts[1]);
|
|
264
|
+
const b = parseRgbComponent(parts[2]);
|
|
265
|
+
if (r === null || g === null || b === null) return null;
|
|
266
|
+
return { r, g, b, a: alpha };
|
|
267
|
+
}
|
|
268
|
+
const h = parseHue(parts[0]);
|
|
269
|
+
const s = parsePercent(parts[1]);
|
|
270
|
+
const l = parsePercent(parts[2]);
|
|
271
|
+
if (h === null || s === null || l === null) return null;
|
|
272
|
+
return hslToRgb(h, clamp(s, 0, 1), clamp(l, 0, 1), alpha);
|
|
273
|
+
}
|
|
274
|
+
function parseHexColour(value) {
|
|
275
|
+
if (!COLOUR_HEX.test(value)) return null;
|
|
276
|
+
const digits = value.slice(1);
|
|
277
|
+
const short = digits.length === 3 || digits.length === 4;
|
|
278
|
+
const size = short ? 1 : 2;
|
|
279
|
+
const channel = function(index) {
|
|
280
|
+
const part = digits.slice(index * size, index * size + size);
|
|
281
|
+
return parseInt(short ? part + part : part, 16);
|
|
282
|
+
};
|
|
283
|
+
const hasAlpha = digits.length === 4 || digits.length === 8;
|
|
284
|
+
return {
|
|
285
|
+
r: channel(0),
|
|
286
|
+
g: channel(1),
|
|
287
|
+
b: channel(2),
|
|
288
|
+
a: hasAlpha ? channel(3) / 255 : 1
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
function parseColour(value) {
|
|
292
|
+
const hex = parseHexColour(value);
|
|
293
|
+
if (hex !== null) return hex;
|
|
294
|
+
const fn = parseColourFunction(value);
|
|
295
|
+
if (fn !== null) return fn;
|
|
296
|
+
const named = NAMED_COLOURS.get(value.toLowerCase());
|
|
297
|
+
return named === void 0 ? null : named;
|
|
298
|
+
}
|
|
299
|
+
function channelLuminance(component) {
|
|
300
|
+
const s = component / 255;
|
|
301
|
+
return s <= 0.03928 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);
|
|
302
|
+
}
|
|
303
|
+
function relativeLuminance(colour) {
|
|
304
|
+
return 0.2126 * channelLuminance(colour.r) + 0.7152 * channelLuminance(colour.g) + 0.0722 * channelLuminance(colour.b);
|
|
305
|
+
}
|
|
306
|
+
function contrastRatio(a, b) {
|
|
307
|
+
const la = relativeLuminance(a);
|
|
308
|
+
const lb = relativeLuminance(b);
|
|
309
|
+
const light = la > lb ? la : lb;
|
|
310
|
+
const dark = la > lb ? lb : la;
|
|
311
|
+
return (light + 0.05) / (dark + 0.05);
|
|
312
|
+
}
|
|
313
|
+
function composite(fg, bg) {
|
|
314
|
+
if (fg.a >= 1) return fg;
|
|
315
|
+
return {
|
|
316
|
+
r: fg.r * fg.a + bg.r * (1 - fg.a),
|
|
317
|
+
g: fg.g * fg.a + bg.g * (1 - fg.a),
|
|
318
|
+
b: fg.b * fg.a + bg.b * (1 - fg.a),
|
|
319
|
+
a: 1
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
var MIN_THEME_CONTRAST_RATIO = 3;
|
|
323
|
+
var DEFAULT_BACKDROPS = {
|
|
324
|
+
light: [
|
|
325
|
+
{ r: 243, g: 250, b: 246, a: 1 },
|
|
326
|
+
// --paper
|
|
327
|
+
{ r: 255, g: 255, b: 255, a: 1 }
|
|
328
|
+
// --surface (--white)
|
|
329
|
+
],
|
|
330
|
+
dark: [
|
|
331
|
+
{ r: 10, g: 22, b: 40, a: 1 },
|
|
332
|
+
// --background (--navy)
|
|
333
|
+
{ r: 26, g: 40, b: 60, a: 1 }
|
|
334
|
+
// --surface (--navy-mid)
|
|
335
|
+
]
|
|
336
|
+
};
|
|
337
|
+
var ACCENT_FOREGROUND = { r: 255, g: 255, b: 255, a: 1 };
|
|
338
|
+
function backdropCandidates(accepted, forcedTheme) {
|
|
339
|
+
const schemes = forcedTheme === null ? ["light", "dark"] : [forcedTheme];
|
|
340
|
+
const bases = [];
|
|
341
|
+
for (let i = 0; i < schemes.length; i += 1) {
|
|
342
|
+
const scheme = DEFAULT_BACKDROPS[schemes[i]];
|
|
343
|
+
for (let j = 0; j < scheme.length; j += 1) bases.push(scheme[j]);
|
|
344
|
+
}
|
|
345
|
+
const supplied = [];
|
|
346
|
+
const names = ["surface", "background"];
|
|
347
|
+
for (let i = 0; i < names.length; i += 1) {
|
|
348
|
+
const raw = accepted[names[i]];
|
|
349
|
+
if (raw === void 0) continue;
|
|
350
|
+
const parsed = parseColour(raw);
|
|
351
|
+
if (parsed === null) continue;
|
|
352
|
+
supplied.push(parsed);
|
|
353
|
+
}
|
|
354
|
+
if (supplied.length === 0) return bases;
|
|
355
|
+
const out = [];
|
|
356
|
+
for (let i = 0; i < supplied.length; i += 1) {
|
|
357
|
+
const value = supplied[i];
|
|
358
|
+
if (value.a >= 1) {
|
|
359
|
+
out.push(value);
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
362
|
+
for (let j = 0; j < bases.length; j += 1) {
|
|
363
|
+
out.push(composite(value, bases[j]));
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
return out;
|
|
367
|
+
}
|
|
368
|
+
function enforceLegibilityFloor(accepted, rejections, forcedTheme) {
|
|
369
|
+
const backdrops = backdropCandidates(accepted, forcedTheme);
|
|
370
|
+
const text = accepted["text"];
|
|
371
|
+
if (text !== void 0) {
|
|
372
|
+
const parsed = parseColour(text);
|
|
373
|
+
let worst = Infinity;
|
|
374
|
+
if (parsed === null) worst = 0;
|
|
375
|
+
else {
|
|
376
|
+
for (let i = 0; i < backdrops.length; i += 1) {
|
|
377
|
+
const backdrop = backdrops[i];
|
|
378
|
+
const ratio = contrastRatio(composite(parsed, backdrop), backdrop);
|
|
379
|
+
if (ratio < worst) worst = ratio;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
if (worst < MIN_THEME_CONTRAST_RATIO) {
|
|
383
|
+
delete accepted["text"];
|
|
384
|
+
rejections.push({ key: "text", code: "variable_contrast_too_low" });
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
const accent = accepted["accent"];
|
|
388
|
+
if (accent !== void 0) {
|
|
389
|
+
const parsed = parseColour(accent);
|
|
390
|
+
let worst = Infinity;
|
|
391
|
+
if (parsed === null) worst = 0;
|
|
392
|
+
else if (parsed.a >= 1) {
|
|
393
|
+
worst = contrastRatio(parsed, ACCENT_FOREGROUND);
|
|
394
|
+
} else {
|
|
395
|
+
for (let i = 0; i < backdrops.length; i += 1) {
|
|
396
|
+
const ratio = contrastRatio(
|
|
397
|
+
composite(parsed, backdrops[i]),
|
|
398
|
+
ACCENT_FOREGROUND
|
|
399
|
+
);
|
|
400
|
+
if (ratio < worst) worst = ratio;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
if (worst < MIN_THEME_CONTRAST_RATIO) {
|
|
404
|
+
delete accepted["accent"];
|
|
405
|
+
rejections.push({ key: "accent", code: "variable_contrast_too_low" });
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
function matchesKind(kind, value) {
|
|
410
|
+
if (kind === "colour") return parseColour(value) !== null;
|
|
411
|
+
if (kind === "length") return LENGTH.test(value);
|
|
412
|
+
return FONT_FAMILY_LIST.test(value);
|
|
413
|
+
}
|
|
414
|
+
function classifyEntry(key, raw) {
|
|
415
|
+
const spec = VARIABLE_TARGETS.get(key);
|
|
416
|
+
if (spec === void 0) return { code: "unknown_variable", value: "" };
|
|
417
|
+
if (typeof raw !== "string")
|
|
418
|
+
return { code: "variable_not_a_string", value: "" };
|
|
419
|
+
if (raw.length > MAX_THEME_VARIABLE_VALUE_LENGTH)
|
|
420
|
+
return { code: "variable_value_too_long", value: "" };
|
|
421
|
+
if (spec.kind === "colour" && FOREGROUND_VARIABLES.has(key) && CONTENT_ERASING_COLOURS.has(raw.toLowerCase())) {
|
|
422
|
+
return { code: "variable_value_erases_content", value: "" };
|
|
423
|
+
}
|
|
424
|
+
if (!matchesKind(spec.kind, raw))
|
|
425
|
+
return { code: "variable_value_malformed", value: "" };
|
|
426
|
+
return { code: null, value: raw };
|
|
427
|
+
}
|
|
428
|
+
function resolveThemeVariables(raw, forcedTheme = null) {
|
|
429
|
+
const accepted = {};
|
|
430
|
+
const rejections = [];
|
|
431
|
+
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
|
|
432
|
+
return { accepted: {}, declarations: {}, rejections: [] };
|
|
433
|
+
}
|
|
434
|
+
const entries = Object.keys(raw);
|
|
435
|
+
for (let i = 0; i < entries.length; i += 1) {
|
|
436
|
+
const key = entries[i];
|
|
437
|
+
if (i >= MAX_THEME_VARIABLE_ENTRIES) {
|
|
438
|
+
rejections.push({ key, code: "too_many_variables" });
|
|
439
|
+
break;
|
|
440
|
+
}
|
|
441
|
+
const outcome = classifyEntry(key, raw[key]);
|
|
442
|
+
if (outcome.code !== null) {
|
|
443
|
+
rejections.push({ key, code: outcome.code });
|
|
444
|
+
continue;
|
|
445
|
+
}
|
|
446
|
+
accepted[key] = outcome.value;
|
|
447
|
+
}
|
|
448
|
+
enforceLegibilityFloor(accepted, rejections, forcedTheme);
|
|
449
|
+
const declarations = {};
|
|
450
|
+
for (const name of CANOPY_THEME_VARIABLES) {
|
|
451
|
+
const value = accepted[name];
|
|
452
|
+
if (value === void 0) continue;
|
|
453
|
+
const targets = VARIABLE_TARGETS.get(name).targets;
|
|
454
|
+
for (let i = 0; i < targets.length; i += 1) {
|
|
455
|
+
declarations[targets[i]] = value;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
return {
|
|
459
|
+
accepted,
|
|
460
|
+
declarations,
|
|
461
|
+
rejections
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
function normalizeForcedTheme(raw) {
|
|
465
|
+
if (raw === "light" || raw === "dark") return raw;
|
|
466
|
+
return null;
|
|
467
|
+
}
|
|
468
|
+
|
|
28
469
|
// src/loader.ts
|
|
29
|
-
var LOADER_VERSION = "
|
|
470
|
+
var LOADER_VERSION = "5";
|
|
30
471
|
(function() {
|
|
31
472
|
"use strict";
|
|
32
473
|
if (typeof window === "undefined") return;
|
|
@@ -35,6 +476,7 @@ var LOADER_VERSION = "3";
|
|
|
35
476
|
const DEFAULT_FALLBACK_LABEL = "Pay with Canopy";
|
|
36
477
|
const POPUP_POLL_INTERVAL_MS = 500;
|
|
37
478
|
const INITIAL_FRAME_HEIGHT_PX = 420;
|
|
479
|
+
const MIN_FRAME_HEIGHT_PX = 46;
|
|
38
480
|
const MESSAGE_SOURCE = "canopy";
|
|
39
481
|
const PUBLISHABLE_KEY_PREFIX = "cnpy_pk_live_";
|
|
40
482
|
function resolveOrigin() {
|
|
@@ -87,6 +529,15 @@ var LOADER_VERSION = "3";
|
|
|
87
529
|
function buildCheckoutUrl(internal) {
|
|
88
530
|
const url = new URL("/customer-pay", internal.origin);
|
|
89
531
|
url.searchParams.set("merchant", internal.merchant);
|
|
532
|
+
if (internal.theme !== null) {
|
|
533
|
+
url.searchParams.set(THEME_PARAM, internal.theme);
|
|
534
|
+
}
|
|
535
|
+
for (let i = 0; i < CANOPY_THEME_VARIABLES.length; i += 1) {
|
|
536
|
+
const name = CANOPY_THEME_VARIABLES[i];
|
|
537
|
+
const value = internal.themeVariables[name];
|
|
538
|
+
if (value === void 0) continue;
|
|
539
|
+
url.searchParams.set(THEME_VARIABLE_PARAM_PREFIX + name, value);
|
|
540
|
+
}
|
|
90
541
|
url.hash = "cap=" + encodeURIComponent(internal.capability || "");
|
|
91
542
|
return url.toString();
|
|
92
543
|
}
|
|
@@ -97,6 +548,15 @@ var LOADER_VERSION = "3";
|
|
|
97
548
|
} catch {
|
|
98
549
|
}
|
|
99
550
|
}
|
|
551
|
+
function emitThemeRejections(internal, rejections) {
|
|
552
|
+
for (let i = 0; i < rejections.length; i += 1) {
|
|
553
|
+
const rejection = rejections[i];
|
|
554
|
+
emit(internal, "error", {
|
|
555
|
+
code: rejection.code,
|
|
556
|
+
variable: rejection.key
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
}
|
|
100
560
|
function teardownFrame(internal) {
|
|
101
561
|
if (internal.handshakeTimer) {
|
|
102
562
|
clearTimeout(internal.handshakeTimer);
|
|
@@ -228,6 +688,7 @@ var LOADER_VERSION = "3";
|
|
|
228
688
|
return;
|
|
229
689
|
}
|
|
230
690
|
if (data.type === "resize" && typeof data.height === "number" && internal.frame) {
|
|
691
|
+
if (!(data.height >= MIN_FRAME_HEIGHT_PX)) return;
|
|
231
692
|
internal.frame.style.height = data.height + "px";
|
|
232
693
|
return;
|
|
233
694
|
}
|
|
@@ -269,6 +730,8 @@ var LOADER_VERSION = "3";
|
|
|
269
730
|
}, destroy: function() {
|
|
270
731
|
} };
|
|
271
732
|
}
|
|
733
|
+
const forcedTheme = normalizeForcedTheme(opts.theme);
|
|
734
|
+
const themeVariables = resolveThemeVariables(opts.variables, forcedTheme);
|
|
272
735
|
const node = typeof opts.target === "string" ? document.querySelector(opts.target) : opts.target;
|
|
273
736
|
if (!node) {
|
|
274
737
|
return { openNow: function() {
|
|
@@ -282,6 +745,8 @@ var LOADER_VERSION = "3";
|
|
|
282
745
|
capability: opts.capability,
|
|
283
746
|
merchant: opts.merchant,
|
|
284
747
|
origin: originResolution.origin,
|
|
748
|
+
theme: forcedTheme,
|
|
749
|
+
themeVariables: themeVariables.accepted,
|
|
285
750
|
surface: opts.surface || "popup",
|
|
286
751
|
handshakeTimeoutMs: opts.handshakeTimeoutMs || DEFAULT_HANDSHAKE_TIMEOUT_MS,
|
|
287
752
|
fallbackLabel: opts.fallbackLabel || DEFAULT_FALLBACK_LABEL,
|
|
@@ -302,6 +767,7 @@ var LOADER_VERSION = "3";
|
|
|
302
767
|
handleMessage(internal, event);
|
|
303
768
|
};
|
|
304
769
|
window.addEventListener("message", internal.messageListener);
|
|
770
|
+
emitThemeRejections(internal, themeVariables.rejections);
|
|
305
771
|
if (internal.surface === "iframe" || internal.surface === "auto") {
|
|
306
772
|
createFrame(internal);
|
|
307
773
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,3 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canopy checkout theming -- the ONE validator behind
|
|
3
|
+
* `Canopy.mount({ theme, variables })`.
|
|
4
|
+
*
|
|
5
|
+
* Imported by BOTH `packages/checkout-sdk/src/loader.ts` (tsup bundles this
|
|
6
|
+
* relative sibling into the IIFE) and `app/customer-pay/page.tsx` (the app
|
|
7
|
+
* already imports across this package boundary; `tsconfig.json` maps `@/*`
|
|
8
|
+
* to the repo root and includes `packages/**\/*.ts`). Deliberately NOT
|
|
9
|
+
* duplicated the way `MESSAGE_SOURCE` is -- that duplication exists only
|
|
10
|
+
* because a React component cannot reach into the tsup entry graph, which
|
|
11
|
+
* is not the case here. Two copies of a grammar are two grammars.
|
|
12
|
+
*
|
|
13
|
+
* The two passes are not equals. The SERVER pass in `app/customer-pay/
|
|
14
|
+
* page.tsx` is the security boundary: those values arrive as query
|
|
15
|
+
* parameters that anyone can hand-craft, with no loader involved. The
|
|
16
|
+
* client-side pass inside `mount()` is a developer-experience courtesy --
|
|
17
|
+
* it turns a typo into an `error` event on the merchant's own console
|
|
18
|
+
* instead of a value that silently vanishes server-side.
|
|
19
|
+
*
|
|
20
|
+
* Threat register (quick 260906-qql): T-QQL-01 tampering (a value escaping
|
|
21
|
+
* its declaration), T-QQL-02 elevation (a prototype-chain key), T-QQL-03
|
|
22
|
+
* denial of service (unbounded input).
|
|
23
|
+
*
|
|
24
|
+
* Pure and browser-free: no `window`, no `document`, no DOM types. It runs
|
|
25
|
+
* inside a React Server Component, inside a `node --test` process, and
|
|
26
|
+
* inside an es2018 IIFE in a merchant's page.
|
|
27
|
+
*/
|
|
28
|
+
/** What a merchant may pass as `theme`. */
|
|
29
|
+
type CanopyThemeOption = "light" | "dark" | "auto";
|
|
30
|
+
/** The eight public names, in the order their declarations are emitted. */
|
|
31
|
+
declare const CANOPY_THEME_VARIABLES: readonly ["accent", "background", "surface", "text", "muted", "border", "radius", "font"];
|
|
32
|
+
type CanopyThemeVariable = (typeof CANOPY_THEME_VARIABLES)[number];
|
|
33
|
+
/** What a merchant may pass as `variables`. */
|
|
34
|
+
type CanopyThemeVariables = Partial<Record<CanopyThemeVariable, string>>;
|
|
35
|
+
|
|
1
36
|
/**
|
|
2
37
|
* Canopy checkout SDK loader.
|
|
3
38
|
*
|
|
@@ -31,6 +66,7 @@
|
|
|
31
66
|
* | "auto"`, default `"popup"`), seven events (`ready`, `resize`, `paid`,
|
|
32
67
|
* `error`, `close`, `surface_unavailable`, `fallback_offered`).
|
|
33
68
|
*/
|
|
69
|
+
|
|
34
70
|
/**
|
|
35
71
|
* `close` is POPUP-ONLY. It reports that the payer closed the checkout
|
|
36
72
|
* window, which the loader detects by polling `popupWin.closed`. An inline
|
|
@@ -68,6 +104,28 @@ type MountOptions = {
|
|
|
68
104
|
* script tag when both are available.
|
|
69
105
|
*/
|
|
70
106
|
canopyOrigin?: string;
|
|
107
|
+
/**
|
|
108
|
+
* Forces the checkout's colour scheme for THIS embed only, overriding the
|
|
109
|
+
* visitor's own stored preference inside the frame and nowhere else.
|
|
110
|
+
* `"auto"` and omitting it are the same thing and are the default: the
|
|
111
|
+
* visitor's preference (and their OS setting) keeps deciding. Nothing is
|
|
112
|
+
* written to the visitor's storage either way.
|
|
113
|
+
*/
|
|
114
|
+
theme?: CanopyThemeOption;
|
|
115
|
+
/**
|
|
116
|
+
* Repaints the checkout through eight allowlisted names: `accent`,
|
|
117
|
+
* `background`, `surface`, `text`, `muted`, `border`, `radius` and
|
|
118
|
+
* `font`. Values are CSS -- a colour (hex, `rgb()`/`rgba()`/`hsl()`, or a
|
|
119
|
+
* bare keyword such as `transparent`) for the six colour names, a length
|
|
120
|
+
* for `radius`, a plain family list for `font`.
|
|
121
|
+
*
|
|
122
|
+
* Rejection is PER ENTRY and never fatal: an unknown name or a malformed
|
|
123
|
+
* value drops that one entry, emits an `error` event naming it, and lets
|
|
124
|
+
* every other entry through. A cosmetic option can never block a checkout.
|
|
125
|
+
* Validated again server-side, which is the authoritative pass -- this one
|
|
126
|
+
* exists so a typo reaches your console instead of vanishing silently.
|
|
127
|
+
*/
|
|
128
|
+
variables?: CanopyThemeVariables;
|
|
71
129
|
};
|
|
72
130
|
type CanopyHandle = {
|
|
73
131
|
openNow: (win: Window | null) => void;
|
|
@@ -97,4 +155,4 @@ declare function mount(opts: MountOptions): CanopyHandle;
|
|
|
97
155
|
* `undefined` server-side / before the loader has installed the global. */
|
|
98
156
|
declare function version(): string | undefined;
|
|
99
157
|
|
|
100
|
-
export { type CanopyEvent, type CanopyEventType, type CanopyHandle, type MountOptions, type Surface, mount, version };
|
|
158
|
+
export { type CanopyEvent, type CanopyEventType, type CanopyHandle, type CanopyThemeOption, type CanopyThemeVariable, type CanopyThemeVariables, type MountOptions, type Surface, mount, version };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canopy checkout theming -- the ONE validator behind
|
|
3
|
+
* `Canopy.mount({ theme, variables })`.
|
|
4
|
+
*
|
|
5
|
+
* Imported by BOTH `packages/checkout-sdk/src/loader.ts` (tsup bundles this
|
|
6
|
+
* relative sibling into the IIFE) and `app/customer-pay/page.tsx` (the app
|
|
7
|
+
* already imports across this package boundary; `tsconfig.json` maps `@/*`
|
|
8
|
+
* to the repo root and includes `packages/**\/*.ts`). Deliberately NOT
|
|
9
|
+
* duplicated the way `MESSAGE_SOURCE` is -- that duplication exists only
|
|
10
|
+
* because a React component cannot reach into the tsup entry graph, which
|
|
11
|
+
* is not the case here. Two copies of a grammar are two grammars.
|
|
12
|
+
*
|
|
13
|
+
* The two passes are not equals. The SERVER pass in `app/customer-pay/
|
|
14
|
+
* page.tsx` is the security boundary: those values arrive as query
|
|
15
|
+
* parameters that anyone can hand-craft, with no loader involved. The
|
|
16
|
+
* client-side pass inside `mount()` is a developer-experience courtesy --
|
|
17
|
+
* it turns a typo into an `error` event on the merchant's own console
|
|
18
|
+
* instead of a value that silently vanishes server-side.
|
|
19
|
+
*
|
|
20
|
+
* Threat register (quick 260906-qql): T-QQL-01 tampering (a value escaping
|
|
21
|
+
* its declaration), T-QQL-02 elevation (a prototype-chain key), T-QQL-03
|
|
22
|
+
* denial of service (unbounded input).
|
|
23
|
+
*
|
|
24
|
+
* Pure and browser-free: no `window`, no `document`, no DOM types. It runs
|
|
25
|
+
* inside a React Server Component, inside a `node --test` process, and
|
|
26
|
+
* inside an es2018 IIFE in a merchant's page.
|
|
27
|
+
*/
|
|
28
|
+
/** What a merchant may pass as `theme`. */
|
|
29
|
+
type CanopyThemeOption = "light" | "dark" | "auto";
|
|
30
|
+
/** The eight public names, in the order their declarations are emitted. */
|
|
31
|
+
declare const CANOPY_THEME_VARIABLES: readonly ["accent", "background", "surface", "text", "muted", "border", "radius", "font"];
|
|
32
|
+
type CanopyThemeVariable = (typeof CANOPY_THEME_VARIABLES)[number];
|
|
33
|
+
/** What a merchant may pass as `variables`. */
|
|
34
|
+
type CanopyThemeVariables = Partial<Record<CanopyThemeVariable, string>>;
|
|
35
|
+
|
|
1
36
|
/**
|
|
2
37
|
* Canopy checkout SDK loader.
|
|
3
38
|
*
|
|
@@ -31,6 +66,7 @@
|
|
|
31
66
|
* | "auto"`, default `"popup"`), seven events (`ready`, `resize`, `paid`,
|
|
32
67
|
* `error`, `close`, `surface_unavailable`, `fallback_offered`).
|
|
33
68
|
*/
|
|
69
|
+
|
|
34
70
|
/**
|
|
35
71
|
* `close` is POPUP-ONLY. It reports that the payer closed the checkout
|
|
36
72
|
* window, which the loader detects by polling `popupWin.closed`. An inline
|
|
@@ -68,6 +104,28 @@ type MountOptions = {
|
|
|
68
104
|
* script tag when both are available.
|
|
69
105
|
*/
|
|
70
106
|
canopyOrigin?: string;
|
|
107
|
+
/**
|
|
108
|
+
* Forces the checkout's colour scheme for THIS embed only, overriding the
|
|
109
|
+
* visitor's own stored preference inside the frame and nowhere else.
|
|
110
|
+
* `"auto"` and omitting it are the same thing and are the default: the
|
|
111
|
+
* visitor's preference (and their OS setting) keeps deciding. Nothing is
|
|
112
|
+
* written to the visitor's storage either way.
|
|
113
|
+
*/
|
|
114
|
+
theme?: CanopyThemeOption;
|
|
115
|
+
/**
|
|
116
|
+
* Repaints the checkout through eight allowlisted names: `accent`,
|
|
117
|
+
* `background`, `surface`, `text`, `muted`, `border`, `radius` and
|
|
118
|
+
* `font`. Values are CSS -- a colour (hex, `rgb()`/`rgba()`/`hsl()`, or a
|
|
119
|
+
* bare keyword such as `transparent`) for the six colour names, a length
|
|
120
|
+
* for `radius`, a plain family list for `font`.
|
|
121
|
+
*
|
|
122
|
+
* Rejection is PER ENTRY and never fatal: an unknown name or a malformed
|
|
123
|
+
* value drops that one entry, emits an `error` event naming it, and lets
|
|
124
|
+
* every other entry through. A cosmetic option can never block a checkout.
|
|
125
|
+
* Validated again server-side, which is the authoritative pass -- this one
|
|
126
|
+
* exists so a typo reaches your console instead of vanishing silently.
|
|
127
|
+
*/
|
|
128
|
+
variables?: CanopyThemeVariables;
|
|
71
129
|
};
|
|
72
130
|
type CanopyHandle = {
|
|
73
131
|
openNow: (win: Window | null) => void;
|
|
@@ -97,4 +155,4 @@ declare function mount(opts: MountOptions): CanopyHandle;
|
|
|
97
155
|
* `undefined` server-side / before the loader has installed the global. */
|
|
98
156
|
declare function version(): string | undefined;
|
|
99
157
|
|
|
100
|
-
export { type CanopyEvent, type CanopyEventType, type CanopyHandle, type MountOptions, type Surface, mount, version };
|
|
158
|
+
export { type CanopyEvent, type CanopyEventType, type CanopyHandle, type CanopyThemeOption, type CanopyThemeVariable, type CanopyThemeVariables, type MountOptions, type Surface, mount, version };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,446 @@
|
|
|
1
|
+
// src/theme.ts
|
|
2
|
+
var THEME_PARAM = "theme";
|
|
3
|
+
var THEME_VARIABLE_PARAM_PREFIX = "v.";
|
|
4
|
+
var MAX_THEME_VARIABLE_VALUE_LENGTH = 64;
|
|
5
|
+
var MAX_THEME_VARIABLE_ENTRIES = 12;
|
|
6
|
+
var CANOPY_THEME_VARIABLES = [
|
|
7
|
+
"accent",
|
|
8
|
+
"background",
|
|
9
|
+
"surface",
|
|
10
|
+
"text",
|
|
11
|
+
"muted",
|
|
12
|
+
"border",
|
|
13
|
+
"radius",
|
|
14
|
+
"font"
|
|
15
|
+
];
|
|
16
|
+
var VARIABLE_TARGETS = /* @__PURE__ */ new Map([
|
|
17
|
+
[
|
|
18
|
+
"accent",
|
|
19
|
+
{
|
|
20
|
+
kind: "colour",
|
|
21
|
+
targets: ["--leaf", "--primary", "--accent", "--ring"]
|
|
22
|
+
}
|
|
23
|
+
],
|
|
24
|
+
[
|
|
25
|
+
"background",
|
|
26
|
+
{
|
|
27
|
+
kind: "colour",
|
|
28
|
+
targets: ["--paper", "--background", "background"]
|
|
29
|
+
}
|
|
30
|
+
],
|
|
31
|
+
[
|
|
32
|
+
"surface",
|
|
33
|
+
{
|
|
34
|
+
kind: "colour",
|
|
35
|
+
targets: ["--surface", "--card", "--popover", "--secondary"]
|
|
36
|
+
}
|
|
37
|
+
],
|
|
38
|
+
[
|
|
39
|
+
"text",
|
|
40
|
+
{
|
|
41
|
+
kind: "colour",
|
|
42
|
+
targets: [
|
|
43
|
+
"--ink",
|
|
44
|
+
"--foreground",
|
|
45
|
+
"--card-foreground",
|
|
46
|
+
"--popover-foreground",
|
|
47
|
+
"--secondary-foreground"
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
],
|
|
51
|
+
[
|
|
52
|
+
"muted",
|
|
53
|
+
{
|
|
54
|
+
kind: "colour",
|
|
55
|
+
targets: ["--ink-muted", "--muted-foreground"]
|
|
56
|
+
}
|
|
57
|
+
],
|
|
58
|
+
[
|
|
59
|
+
"border",
|
|
60
|
+
{ kind: "colour", targets: ["--line", "--border", "--input"] }
|
|
61
|
+
],
|
|
62
|
+
["radius", { kind: "length", targets: ["--radius"] }],
|
|
63
|
+
["font", { kind: "font", targets: ["--font-sans"] }]
|
|
64
|
+
]);
|
|
65
|
+
var COLOUR_HEX = /^#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;
|
|
66
|
+
var COLOUR_FUNCTION = /^(rgb|rgba|hsl|hsla)\(([0-9a-z.,%/ +-]*)\)$/;
|
|
67
|
+
var NUMBER = /^[+-]?(?:[0-9]{1,4}(?:\.[0-9]{1,4})?|\.[0-9]{1,4})$/;
|
|
68
|
+
var PERCENT = /^[+-]?(?:[0-9]{1,3}(?:\.[0-9]{1,4})?|\.[0-9]{1,4})%$/;
|
|
69
|
+
var LENGTH = /^(?:0|(?:[0-9]{1,4}(?:\.[0-9]{1,4})?|\.[0-9]{1,4})(?:px|rem|em|%))$/;
|
|
70
|
+
var FONT_FAMILY_LIST = /^[A-Za-z0-9 ,_-]+$/;
|
|
71
|
+
var NAMED_COLOURS = /* @__PURE__ */ new Map([
|
|
72
|
+
["transparent", { r: 0, g: 0, b: 0, a: 0 }],
|
|
73
|
+
["black", { r: 0, g: 0, b: 0, a: 1 }],
|
|
74
|
+
["white", { r: 255, g: 255, b: 255, a: 1 }],
|
|
75
|
+
["silver", { r: 192, g: 192, b: 192, a: 1 }],
|
|
76
|
+
["gray", { r: 128, g: 128, b: 128, a: 1 }],
|
|
77
|
+
["grey", { r: 128, g: 128, b: 128, a: 1 }],
|
|
78
|
+
["maroon", { r: 128, g: 0, b: 0, a: 1 }],
|
|
79
|
+
["red", { r: 255, g: 0, b: 0, a: 1 }],
|
|
80
|
+
["purple", { r: 128, g: 0, b: 128, a: 1 }],
|
|
81
|
+
["fuchsia", { r: 255, g: 0, b: 255, a: 1 }],
|
|
82
|
+
["magenta", { r: 255, g: 0, b: 255, a: 1 }],
|
|
83
|
+
["green", { r: 0, g: 128, b: 0, a: 1 }],
|
|
84
|
+
["lime", { r: 0, g: 255, b: 0, a: 1 }],
|
|
85
|
+
["olive", { r: 128, g: 128, b: 0, a: 1 }],
|
|
86
|
+
["yellow", { r: 255, g: 255, b: 0, a: 1 }],
|
|
87
|
+
["navy", { r: 0, g: 0, b: 128, a: 1 }],
|
|
88
|
+
["blue", { r: 0, g: 0, b: 255, a: 1 }],
|
|
89
|
+
["teal", { r: 0, g: 128, b: 128, a: 1 }],
|
|
90
|
+
["aqua", { r: 0, g: 255, b: 255, a: 1 }],
|
|
91
|
+
["cyan", { r: 0, g: 255, b: 255, a: 1 }],
|
|
92
|
+
["orange", { r: 255, g: 165, b: 0, a: 1 }],
|
|
93
|
+
["pink", { r: 255, g: 192, b: 203, a: 1 }],
|
|
94
|
+
["brown", { r: 165, g: 42, b: 42, a: 1 }],
|
|
95
|
+
["beige", { r: 245, g: 245, b: 220, a: 1 }],
|
|
96
|
+
["ivory", { r: 255, g: 255, b: 240, a: 1 }],
|
|
97
|
+
["indigo", { r: 75, g: 0, b: 130, a: 1 }],
|
|
98
|
+
["violet", { r: 238, g: 130, b: 238, a: 1 }],
|
|
99
|
+
["gold", { r: 255, g: 215, b: 0, a: 1 }],
|
|
100
|
+
["crimson", { r: 220, g: 20, b: 60, a: 1 }],
|
|
101
|
+
["salmon", { r: 250, g: 128, b: 114, a: 1 }],
|
|
102
|
+
["khaki", { r: 240, g: 230, b: 140, a: 1 }],
|
|
103
|
+
["lavender", { r: 230, g: 230, b: 250, a: 1 }],
|
|
104
|
+
["turquoise", { r: 64, g: 224, b: 208, a: 1 }],
|
|
105
|
+
["tan", { r: 210, g: 180, b: 140, a: 1 }],
|
|
106
|
+
["plum", { r: 221, g: 160, b: 221, a: 1 }],
|
|
107
|
+
["orchid", { r: 218, g: 112, b: 214, a: 1 }],
|
|
108
|
+
["coral", { r: 255, g: 127, b: 80, a: 1 }],
|
|
109
|
+
["tomato", { r: 255, g: 99, b: 71, a: 1 }],
|
|
110
|
+
["chocolate", { r: 210, g: 105, b: 30, a: 1 }],
|
|
111
|
+
["snow", { r: 255, g: 250, b: 250, a: 1 }],
|
|
112
|
+
["linen", { r: 250, g: 240, b: 230, a: 1 }],
|
|
113
|
+
["azure", { r: 240, g: 255, b: 255, a: 1 }],
|
|
114
|
+
["wheat", { r: 245, g: 222, b: 179, a: 1 }],
|
|
115
|
+
["thistle", { r: 216, g: 191, b: 216, a: 1 }]
|
|
116
|
+
]);
|
|
117
|
+
var CONTENT_ERASING_COLOURS = /* @__PURE__ */ new Set([
|
|
118
|
+
"transparent",
|
|
119
|
+
"currentcolor",
|
|
120
|
+
"inherit",
|
|
121
|
+
"initial",
|
|
122
|
+
"unset",
|
|
123
|
+
"revert",
|
|
124
|
+
"revert-layer"
|
|
125
|
+
]);
|
|
126
|
+
var FOREGROUND_VARIABLES = /* @__PURE__ */ new Set([
|
|
127
|
+
"text",
|
|
128
|
+
"muted",
|
|
129
|
+
"accent"
|
|
130
|
+
]);
|
|
131
|
+
function clamp(value, low, high) {
|
|
132
|
+
if (value < low) return low;
|
|
133
|
+
if (value > high) return high;
|
|
134
|
+
return value;
|
|
135
|
+
}
|
|
136
|
+
function parseNumber(token) {
|
|
137
|
+
if (!NUMBER.test(token)) return null;
|
|
138
|
+
const value = Number(token);
|
|
139
|
+
return Number.isFinite(value) ? value : null;
|
|
140
|
+
}
|
|
141
|
+
function parsePercent(token) {
|
|
142
|
+
if (!PERCENT.test(token)) return null;
|
|
143
|
+
const value = Number(token.slice(0, token.length - 1));
|
|
144
|
+
return Number.isFinite(value) ? value / 100 : null;
|
|
145
|
+
}
|
|
146
|
+
function parseRgbComponent(token) {
|
|
147
|
+
const percent = parsePercent(token);
|
|
148
|
+
if (percent !== null) return clamp(percent, 0, 1) * 255;
|
|
149
|
+
const number = parseNumber(token);
|
|
150
|
+
if (number === null) return null;
|
|
151
|
+
return clamp(number, 0, 255);
|
|
152
|
+
}
|
|
153
|
+
function parseAlpha(token) {
|
|
154
|
+
const percent = parsePercent(token);
|
|
155
|
+
if (percent !== null) return clamp(percent, 0, 1);
|
|
156
|
+
const number = parseNumber(token);
|
|
157
|
+
if (number === null) return null;
|
|
158
|
+
return clamp(number, 0, 1);
|
|
159
|
+
}
|
|
160
|
+
function parseHue(token) {
|
|
161
|
+
let text = token;
|
|
162
|
+
let scale = 1;
|
|
163
|
+
if (text.endsWith("deg")) text = text.slice(0, text.length - 3);
|
|
164
|
+
else if (text.endsWith("grad")) {
|
|
165
|
+
text = text.slice(0, text.length - 4);
|
|
166
|
+
scale = 360 / 400;
|
|
167
|
+
} else if (text.endsWith("turn")) {
|
|
168
|
+
text = text.slice(0, text.length - 4);
|
|
169
|
+
scale = 360;
|
|
170
|
+
} else if (text.endsWith("rad")) {
|
|
171
|
+
text = text.slice(0, text.length - 3);
|
|
172
|
+
scale = 180 / Math.PI;
|
|
173
|
+
}
|
|
174
|
+
const number = parseNumber(text);
|
|
175
|
+
if (number === null) return null;
|
|
176
|
+
return (number * scale % 360 + 360) % 360;
|
|
177
|
+
}
|
|
178
|
+
function hueToChannel(p, q, tRaw) {
|
|
179
|
+
let t = tRaw;
|
|
180
|
+
if (t < 0) t += 1;
|
|
181
|
+
if (t > 1) t -= 1;
|
|
182
|
+
if (t < 1 / 6) return p + (q - p) * 6 * t;
|
|
183
|
+
if (t < 1 / 2) return q;
|
|
184
|
+
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
|
|
185
|
+
return p;
|
|
186
|
+
}
|
|
187
|
+
function hslToRgb(h, s, l, a) {
|
|
188
|
+
if (s === 0) {
|
|
189
|
+
const grey = l * 255;
|
|
190
|
+
return { r: grey, g: grey, b: grey, a };
|
|
191
|
+
}
|
|
192
|
+
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
|
193
|
+
const p = 2 * l - q;
|
|
194
|
+
const hk = h / 360;
|
|
195
|
+
return {
|
|
196
|
+
r: hueToChannel(p, q, hk + 1 / 3) * 255,
|
|
197
|
+
g: hueToChannel(p, q, hk) * 255,
|
|
198
|
+
b: hueToChannel(p, q, hk - 1 / 3) * 255,
|
|
199
|
+
a
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
function splitColourComponents(body) {
|
|
203
|
+
const trimmed = body.trim();
|
|
204
|
+
if (trimmed === "") return null;
|
|
205
|
+
if (trimmed.indexOf(",") >= 0) {
|
|
206
|
+
if (trimmed.indexOf("/") >= 0) return null;
|
|
207
|
+
const parts = trimmed.split(",").map(function(part) {
|
|
208
|
+
return part.trim();
|
|
209
|
+
});
|
|
210
|
+
if (parts.length !== 3 && parts.length !== 4) return null;
|
|
211
|
+
return parts;
|
|
212
|
+
}
|
|
213
|
+
const slashParts = trimmed.split("/");
|
|
214
|
+
if (slashParts.length > 2) return null;
|
|
215
|
+
const main = slashParts[0].trim().split(/ +/);
|
|
216
|
+
if (main.length !== 3) return null;
|
|
217
|
+
if (slashParts.length === 1) return main;
|
|
218
|
+
const alpha = slashParts[1].trim();
|
|
219
|
+
if (alpha === "" || alpha.indexOf(" ") >= 0) return null;
|
|
220
|
+
return main.concat([alpha]);
|
|
221
|
+
}
|
|
222
|
+
function parseColourFunction(value) {
|
|
223
|
+
const match = COLOUR_FUNCTION.exec(value);
|
|
224
|
+
if (match === null) return null;
|
|
225
|
+
const fn = match[1];
|
|
226
|
+
const parts = splitColourComponents(match[2]);
|
|
227
|
+
if (parts === null) return null;
|
|
228
|
+
let alpha = 1;
|
|
229
|
+
if (parts.length === 4) {
|
|
230
|
+
const parsed = parseAlpha(parts[3]);
|
|
231
|
+
if (parsed === null) return null;
|
|
232
|
+
alpha = parsed;
|
|
233
|
+
}
|
|
234
|
+
if (fn === "rgb" || fn === "rgba") {
|
|
235
|
+
const r = parseRgbComponent(parts[0]);
|
|
236
|
+
const g = parseRgbComponent(parts[1]);
|
|
237
|
+
const b = parseRgbComponent(parts[2]);
|
|
238
|
+
if (r === null || g === null || b === null) return null;
|
|
239
|
+
return { r, g, b, a: alpha };
|
|
240
|
+
}
|
|
241
|
+
const h = parseHue(parts[0]);
|
|
242
|
+
const s = parsePercent(parts[1]);
|
|
243
|
+
const l = parsePercent(parts[2]);
|
|
244
|
+
if (h === null || s === null || l === null) return null;
|
|
245
|
+
return hslToRgb(h, clamp(s, 0, 1), clamp(l, 0, 1), alpha);
|
|
246
|
+
}
|
|
247
|
+
function parseHexColour(value) {
|
|
248
|
+
if (!COLOUR_HEX.test(value)) return null;
|
|
249
|
+
const digits = value.slice(1);
|
|
250
|
+
const short = digits.length === 3 || digits.length === 4;
|
|
251
|
+
const size = short ? 1 : 2;
|
|
252
|
+
const channel = function(index) {
|
|
253
|
+
const part = digits.slice(index * size, index * size + size);
|
|
254
|
+
return parseInt(short ? part + part : part, 16);
|
|
255
|
+
};
|
|
256
|
+
const hasAlpha = digits.length === 4 || digits.length === 8;
|
|
257
|
+
return {
|
|
258
|
+
r: channel(0),
|
|
259
|
+
g: channel(1),
|
|
260
|
+
b: channel(2),
|
|
261
|
+
a: hasAlpha ? channel(3) / 255 : 1
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
function parseColour(value) {
|
|
265
|
+
const hex = parseHexColour(value);
|
|
266
|
+
if (hex !== null) return hex;
|
|
267
|
+
const fn = parseColourFunction(value);
|
|
268
|
+
if (fn !== null) return fn;
|
|
269
|
+
const named = NAMED_COLOURS.get(value.toLowerCase());
|
|
270
|
+
return named === void 0 ? null : named;
|
|
271
|
+
}
|
|
272
|
+
function channelLuminance(component) {
|
|
273
|
+
const s = component / 255;
|
|
274
|
+
return s <= 0.03928 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);
|
|
275
|
+
}
|
|
276
|
+
function relativeLuminance(colour) {
|
|
277
|
+
return 0.2126 * channelLuminance(colour.r) + 0.7152 * channelLuminance(colour.g) + 0.0722 * channelLuminance(colour.b);
|
|
278
|
+
}
|
|
279
|
+
function contrastRatio(a, b) {
|
|
280
|
+
const la = relativeLuminance(a);
|
|
281
|
+
const lb = relativeLuminance(b);
|
|
282
|
+
const light = la > lb ? la : lb;
|
|
283
|
+
const dark = la > lb ? lb : la;
|
|
284
|
+
return (light + 0.05) / (dark + 0.05);
|
|
285
|
+
}
|
|
286
|
+
function composite(fg, bg) {
|
|
287
|
+
if (fg.a >= 1) return fg;
|
|
288
|
+
return {
|
|
289
|
+
r: fg.r * fg.a + bg.r * (1 - fg.a),
|
|
290
|
+
g: fg.g * fg.a + bg.g * (1 - fg.a),
|
|
291
|
+
b: fg.b * fg.a + bg.b * (1 - fg.a),
|
|
292
|
+
a: 1
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
var MIN_THEME_CONTRAST_RATIO = 3;
|
|
296
|
+
var DEFAULT_BACKDROPS = {
|
|
297
|
+
light: [
|
|
298
|
+
{ r: 243, g: 250, b: 246, a: 1 },
|
|
299
|
+
// --paper
|
|
300
|
+
{ r: 255, g: 255, b: 255, a: 1 }
|
|
301
|
+
// --surface (--white)
|
|
302
|
+
],
|
|
303
|
+
dark: [
|
|
304
|
+
{ r: 10, g: 22, b: 40, a: 1 },
|
|
305
|
+
// --background (--navy)
|
|
306
|
+
{ r: 26, g: 40, b: 60, a: 1 }
|
|
307
|
+
// --surface (--navy-mid)
|
|
308
|
+
]
|
|
309
|
+
};
|
|
310
|
+
var ACCENT_FOREGROUND = { r: 255, g: 255, b: 255, a: 1 };
|
|
311
|
+
function backdropCandidates(accepted, forcedTheme) {
|
|
312
|
+
const schemes = forcedTheme === null ? ["light", "dark"] : [forcedTheme];
|
|
313
|
+
const bases = [];
|
|
314
|
+
for (let i = 0; i < schemes.length; i += 1) {
|
|
315
|
+
const scheme = DEFAULT_BACKDROPS[schemes[i]];
|
|
316
|
+
for (let j = 0; j < scheme.length; j += 1) bases.push(scheme[j]);
|
|
317
|
+
}
|
|
318
|
+
const supplied = [];
|
|
319
|
+
const names = ["surface", "background"];
|
|
320
|
+
for (let i = 0; i < names.length; i += 1) {
|
|
321
|
+
const raw = accepted[names[i]];
|
|
322
|
+
if (raw === void 0) continue;
|
|
323
|
+
const parsed = parseColour(raw);
|
|
324
|
+
if (parsed === null) continue;
|
|
325
|
+
supplied.push(parsed);
|
|
326
|
+
}
|
|
327
|
+
if (supplied.length === 0) return bases;
|
|
328
|
+
const out = [];
|
|
329
|
+
for (let i = 0; i < supplied.length; i += 1) {
|
|
330
|
+
const value = supplied[i];
|
|
331
|
+
if (value.a >= 1) {
|
|
332
|
+
out.push(value);
|
|
333
|
+
continue;
|
|
334
|
+
}
|
|
335
|
+
for (let j = 0; j < bases.length; j += 1) {
|
|
336
|
+
out.push(composite(value, bases[j]));
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
return out;
|
|
340
|
+
}
|
|
341
|
+
function enforceLegibilityFloor(accepted, rejections, forcedTheme) {
|
|
342
|
+
const backdrops = backdropCandidates(accepted, forcedTheme);
|
|
343
|
+
const text = accepted["text"];
|
|
344
|
+
if (text !== void 0) {
|
|
345
|
+
const parsed = parseColour(text);
|
|
346
|
+
let worst = Infinity;
|
|
347
|
+
if (parsed === null) worst = 0;
|
|
348
|
+
else {
|
|
349
|
+
for (let i = 0; i < backdrops.length; i += 1) {
|
|
350
|
+
const backdrop = backdrops[i];
|
|
351
|
+
const ratio = contrastRatio(composite(parsed, backdrop), backdrop);
|
|
352
|
+
if (ratio < worst) worst = ratio;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
if (worst < MIN_THEME_CONTRAST_RATIO) {
|
|
356
|
+
delete accepted["text"];
|
|
357
|
+
rejections.push({ key: "text", code: "variable_contrast_too_low" });
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
const accent = accepted["accent"];
|
|
361
|
+
if (accent !== void 0) {
|
|
362
|
+
const parsed = parseColour(accent);
|
|
363
|
+
let worst = Infinity;
|
|
364
|
+
if (parsed === null) worst = 0;
|
|
365
|
+
else if (parsed.a >= 1) {
|
|
366
|
+
worst = contrastRatio(parsed, ACCENT_FOREGROUND);
|
|
367
|
+
} else {
|
|
368
|
+
for (let i = 0; i < backdrops.length; i += 1) {
|
|
369
|
+
const ratio = contrastRatio(
|
|
370
|
+
composite(parsed, backdrops[i]),
|
|
371
|
+
ACCENT_FOREGROUND
|
|
372
|
+
);
|
|
373
|
+
if (ratio < worst) worst = ratio;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
if (worst < MIN_THEME_CONTRAST_RATIO) {
|
|
377
|
+
delete accepted["accent"];
|
|
378
|
+
rejections.push({ key: "accent", code: "variable_contrast_too_low" });
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
function matchesKind(kind, value) {
|
|
383
|
+
if (kind === "colour") return parseColour(value) !== null;
|
|
384
|
+
if (kind === "length") return LENGTH.test(value);
|
|
385
|
+
return FONT_FAMILY_LIST.test(value);
|
|
386
|
+
}
|
|
387
|
+
function classifyEntry(key, raw) {
|
|
388
|
+
const spec = VARIABLE_TARGETS.get(key);
|
|
389
|
+
if (spec === void 0) return { code: "unknown_variable", value: "" };
|
|
390
|
+
if (typeof raw !== "string")
|
|
391
|
+
return { code: "variable_not_a_string", value: "" };
|
|
392
|
+
if (raw.length > MAX_THEME_VARIABLE_VALUE_LENGTH)
|
|
393
|
+
return { code: "variable_value_too_long", value: "" };
|
|
394
|
+
if (spec.kind === "colour" && FOREGROUND_VARIABLES.has(key) && CONTENT_ERASING_COLOURS.has(raw.toLowerCase())) {
|
|
395
|
+
return { code: "variable_value_erases_content", value: "" };
|
|
396
|
+
}
|
|
397
|
+
if (!matchesKind(spec.kind, raw))
|
|
398
|
+
return { code: "variable_value_malformed", value: "" };
|
|
399
|
+
return { code: null, value: raw };
|
|
400
|
+
}
|
|
401
|
+
function resolveThemeVariables(raw, forcedTheme = null) {
|
|
402
|
+
const accepted = {};
|
|
403
|
+
const rejections = [];
|
|
404
|
+
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
|
|
405
|
+
return { accepted: {}, declarations: {}, rejections: [] };
|
|
406
|
+
}
|
|
407
|
+
const entries = Object.keys(raw);
|
|
408
|
+
for (let i = 0; i < entries.length; i += 1) {
|
|
409
|
+
const key = entries[i];
|
|
410
|
+
if (i >= MAX_THEME_VARIABLE_ENTRIES) {
|
|
411
|
+
rejections.push({ key, code: "too_many_variables" });
|
|
412
|
+
break;
|
|
413
|
+
}
|
|
414
|
+
const outcome = classifyEntry(key, raw[key]);
|
|
415
|
+
if (outcome.code !== null) {
|
|
416
|
+
rejections.push({ key, code: outcome.code });
|
|
417
|
+
continue;
|
|
418
|
+
}
|
|
419
|
+
accepted[key] = outcome.value;
|
|
420
|
+
}
|
|
421
|
+
enforceLegibilityFloor(accepted, rejections, forcedTheme);
|
|
422
|
+
const declarations = {};
|
|
423
|
+
for (const name of CANOPY_THEME_VARIABLES) {
|
|
424
|
+
const value = accepted[name];
|
|
425
|
+
if (value === void 0) continue;
|
|
426
|
+
const targets = VARIABLE_TARGETS.get(name).targets;
|
|
427
|
+
for (let i = 0; i < targets.length; i += 1) {
|
|
428
|
+
declarations[targets[i]] = value;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
return {
|
|
432
|
+
accepted,
|
|
433
|
+
declarations,
|
|
434
|
+
rejections
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
function normalizeForcedTheme(raw) {
|
|
438
|
+
if (raw === "light" || raw === "dark") return raw;
|
|
439
|
+
return null;
|
|
440
|
+
}
|
|
441
|
+
|
|
1
442
|
// src/loader.ts
|
|
2
|
-
var LOADER_VERSION = "
|
|
443
|
+
var LOADER_VERSION = "5";
|
|
3
444
|
(function() {
|
|
4
445
|
"use strict";
|
|
5
446
|
if (typeof window === "undefined") return;
|
|
@@ -8,6 +449,7 @@ var LOADER_VERSION = "3";
|
|
|
8
449
|
const DEFAULT_FALLBACK_LABEL = "Pay with Canopy";
|
|
9
450
|
const POPUP_POLL_INTERVAL_MS = 500;
|
|
10
451
|
const INITIAL_FRAME_HEIGHT_PX = 420;
|
|
452
|
+
const MIN_FRAME_HEIGHT_PX = 46;
|
|
11
453
|
const MESSAGE_SOURCE = "canopy";
|
|
12
454
|
const PUBLISHABLE_KEY_PREFIX = "cnpy_pk_live_";
|
|
13
455
|
function resolveOrigin() {
|
|
@@ -60,6 +502,15 @@ var LOADER_VERSION = "3";
|
|
|
60
502
|
function buildCheckoutUrl(internal) {
|
|
61
503
|
const url = new URL("/customer-pay", internal.origin);
|
|
62
504
|
url.searchParams.set("merchant", internal.merchant);
|
|
505
|
+
if (internal.theme !== null) {
|
|
506
|
+
url.searchParams.set(THEME_PARAM, internal.theme);
|
|
507
|
+
}
|
|
508
|
+
for (let i = 0; i < CANOPY_THEME_VARIABLES.length; i += 1) {
|
|
509
|
+
const name = CANOPY_THEME_VARIABLES[i];
|
|
510
|
+
const value = internal.themeVariables[name];
|
|
511
|
+
if (value === void 0) continue;
|
|
512
|
+
url.searchParams.set(THEME_VARIABLE_PARAM_PREFIX + name, value);
|
|
513
|
+
}
|
|
63
514
|
url.hash = "cap=" + encodeURIComponent(internal.capability || "");
|
|
64
515
|
return url.toString();
|
|
65
516
|
}
|
|
@@ -70,6 +521,15 @@ var LOADER_VERSION = "3";
|
|
|
70
521
|
} catch {
|
|
71
522
|
}
|
|
72
523
|
}
|
|
524
|
+
function emitThemeRejections(internal, rejections) {
|
|
525
|
+
for (let i = 0; i < rejections.length; i += 1) {
|
|
526
|
+
const rejection = rejections[i];
|
|
527
|
+
emit(internal, "error", {
|
|
528
|
+
code: rejection.code,
|
|
529
|
+
variable: rejection.key
|
|
530
|
+
});
|
|
531
|
+
}
|
|
532
|
+
}
|
|
73
533
|
function teardownFrame(internal) {
|
|
74
534
|
if (internal.handshakeTimer) {
|
|
75
535
|
clearTimeout(internal.handshakeTimer);
|
|
@@ -201,6 +661,7 @@ var LOADER_VERSION = "3";
|
|
|
201
661
|
return;
|
|
202
662
|
}
|
|
203
663
|
if (data.type === "resize" && typeof data.height === "number" && internal.frame) {
|
|
664
|
+
if (!(data.height >= MIN_FRAME_HEIGHT_PX)) return;
|
|
204
665
|
internal.frame.style.height = data.height + "px";
|
|
205
666
|
return;
|
|
206
667
|
}
|
|
@@ -242,6 +703,8 @@ var LOADER_VERSION = "3";
|
|
|
242
703
|
}, destroy: function() {
|
|
243
704
|
} };
|
|
244
705
|
}
|
|
706
|
+
const forcedTheme = normalizeForcedTheme(opts.theme);
|
|
707
|
+
const themeVariables = resolveThemeVariables(opts.variables, forcedTheme);
|
|
245
708
|
const node = typeof opts.target === "string" ? document.querySelector(opts.target) : opts.target;
|
|
246
709
|
if (!node) {
|
|
247
710
|
return { openNow: function() {
|
|
@@ -255,6 +718,8 @@ var LOADER_VERSION = "3";
|
|
|
255
718
|
capability: opts.capability,
|
|
256
719
|
merchant: opts.merchant,
|
|
257
720
|
origin: originResolution.origin,
|
|
721
|
+
theme: forcedTheme,
|
|
722
|
+
themeVariables: themeVariables.accepted,
|
|
258
723
|
surface: opts.surface || "popup",
|
|
259
724
|
handshakeTimeoutMs: opts.handshakeTimeoutMs || DEFAULT_HANDSHAKE_TIMEOUT_MS,
|
|
260
725
|
fallbackLabel: opts.fallbackLabel || DEFAULT_FALLBACK_LABEL,
|
|
@@ -275,6 +740,7 @@ var LOADER_VERSION = "3";
|
|
|
275
740
|
handleMessage(internal, event);
|
|
276
741
|
};
|
|
277
742
|
window.addEventListener("message", internal.messageListener);
|
|
743
|
+
emitThemeRejections(internal, themeVariables.rejections);
|
|
278
744
|
if (internal.surface === "iframe" || internal.surface === "auto") {
|
|
279
745
|
createFrame(internal);
|
|
280
746
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@canopypay/checkout-sdk",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.4.1",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
7
7
|
"module": "./dist/index.js",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"prepublishOnly": "npm --prefix ../.. run sdk:build && npm run build:npm"
|
|
31
31
|
},
|
|
32
32
|
"canopy": {
|
|
33
|
-
"loaderVersion": "
|
|
33
|
+
"loaderVersion": "5",
|
|
34
34
|
"apiVersion": "2026-09-01"
|
|
35
35
|
},
|
|
36
36
|
"publishConfig": {
|