UNPKG

@swishapp/browser

Version:

JS library to integrate Swish into a browser environment.

5 lines (4 loc) 9.98 kB
var C=Object.defineProperty;var i=(s,e)=>C(s,"name",{value:e,configurable:!0});var L=".swish-shop-bridge{position:absolute!important;top:0!important;left:0!important;padding:0!important;border:0!important;margin:0!important;pointer-events:none!important}.swish-shop-bridge input{appearance:none!important;border:none!important;width:1px!important;height:1px!important;padding:0!important;margin:0!important;background:rgba(0,0,0,0)!important}",A=`<form class=swish-shop-bridge data-login-with-shop-sign-in=true id=customer_login><input name=customer[email] id=customer_login_email> <input name=return_url type=hidden value=${window.location.pathname}></form>`,f=class extends HTMLElement{constructor(){super();this.swish=window.swish;this.emailInput=this.querySelector('form[data-login-with-shop-sign-in] input[type="email"],form[data-login-with-shop-sign-in] input[name="customer[email]"'),this.emailInput||(this.innerHTML=` <style>${L}</style> ${A} `,this.emailInput=this.querySelector("#customer_login_email")),this.shopModalObserver=new MutationObserver(t=>{t.forEach(n=>{n.attributeName==="style"&&document.documentElement.style.overflow==="hidden"&&this.dispatchEvent(new CustomEvent("shop-modal-open"))})}),this.shopModalObserver.observe(document.documentElement,{attributes:!0,attributeFilter:["style"]})}static{i(this,"ShopBridge")}disconnectedCallback(){this.shopModalObserver?.disconnect()}async load(){try{(window.Shopify?.featureAssets?.["shop-js"]?.["init-customer-accounts"]?.[0]??"").includes("init-customer-accounts")&&(await Promise.all(window.Shopify?.featureAssets?.["shop-js"]?.["init-customer-accounts"]?.map(n=>import(`/cdn/shopifycloud/shop-js/${n}`))??[]),window.Shopify?.SignInWithShop?.initCustomerAccounts?.(!0,{fedCMEnabled:!0,windoidEnabled:!1}))}catch(t){console.warn("Failed to initialize Shop JS",t)}}update(t){if(t.email&&(this.emailInput.value=t.email,this.emailInput.dispatchEvent(new Event("input"))),t.returnTo){let n=this.querySelector("input[name='return_url']");n&&(n.value=t.returnTo)}}};customElements.define("swish-shop-bridge",f);var h,l,R=i(s=>{l=s},"setConfig"),T=i(async s=>{let e=await w("sign-in");e.setAttribute("open","true"),e.setAttribute("return-to",s?.returnTo??window.location.pathname)},"showSignIn"),S=i(async s=>{await w("notifications",{onHydrated:i(e=>{e.current.pushNotification(s)},"onHydrated")})},"showNotification"),b=i(async s=>{let e=await w("variant-select",{listeners:{submit:i(async t=>{"detail"in t&&t.detail?(await s.onSubmit?.(t.detail),e.setAttribute("open","false")):console.warn("Variant select form submitted without detail",t)},"submit")}});if(s.productId)e.setAttribute("product-id",s.productId);else if(s.productHandle)e.setAttribute("product-handle",s.productHandle);else throw new Error("Either productId or productHandle must be provided");s.variantId&&e.setAttribute("variant-id",s.variantId),e.setAttribute("display-type",s.displayType??"rows"),e.setAttribute("open","true")},"showVariantSelect"),E=i(async({onShopModalOpen:s})=>{let e=document.querySelector("swish-shop-bridge");if(e||(document.body.insertAdjacentHTML("beforeend","<swish-shop-bridge></swish-shop-bridge>"),e=document.querySelector("swish-shop-bridge")),!e)throw new Error("Failed to initialize Shop Bridge");return e.addEventListener("shop-modal-open",()=>s(),{once:!0}),await e.load(),e},"initShopBridge"),y=i(async()=>h||(l?.manifest&&(h=await l.manifest()),h??{elements:{},version:""}),"loadManifest"),M=i(async s=>{let t=(await y()).elements[s];if(!t)throw new Error(`Element ${s} not found in manifest`);return import(`${l?.host??""}/assets/ui/${t}`).then(r=>({script:r.default.script,template:r.default.template}))},"importElementSepc"),g=new Map,w=i(async(s,e)=>{let{template:t,script:n}=await M(s),r=`${l?.host??""}/assets/ui/${n}`,a=e?.instance,d=e?.listeners,o=v(s,a)??await O({name:s,template:t,refElement:document.body,position:"beforeend",instance:a});o.shadowRoot&&!o.hasAttribute("hydrated")?import(r).then(({hydrate:p})=>{p(o),o.setAttribute("hydrated",""),e?.onHydrated?.(o.getComponentRef())}):o.hasAttribute("hydrated")&&e?.onHydrated?.(o.getComponentRef());for(let{event:p,listener:u}of g.values())o.removeEventListener(p,u);for(let[p,u]of Object.entries(d??{}))g.set(`${s}-${a}-${p}`,{event:p,listener:u}),o.addEventListener(p,u);return o},"requireUiComponent"),O=i(async({name:s,instance:e,template:t,position:n,refElement:r})=>{r.insertAdjacentHTML(n,t.replace(' shadowrootmode="open"',""));let a=v(s,e);if(!a)throw new Error(`Element ${s} not found in DOM`);return a},"insertComponent"),v=i((s,e)=>{let t=`swish-ui[ref="${s}${e?`-${e}`:""}"]`;return document.querySelector(t)},"queryComponent"),m=class extends HTMLElement{constructor(){super();this.getComponentRef=i(()=>this.componentRef,"getComponentRef");this.setComponentRef=i(t=>{this.componentRef=t},"setComponentRef");this.shadowRoot||this.attachShadow({mode:"open"});let t=this.querySelector("template");t&&this.shadowRoot&&(this.shadowRoot.appendChild(t.content),t.remove())}static{i(this,"SwishUiElement")}};typeof requestIdleCallback=="function"?requestIdleCallback(()=>{y()}):setTimeout(()=>{y()},1e3);var c=class{constructor(e,t=0){this.worker=e;this.rpcTimeout=t;this.worker=e,this.rpcTimeout=t,this.worker.onmessage=n=>{this.#o(n.data)}}static{i(this,"WorkerRpc")}#t=new Map;#i=new Map;#n=0;call(e,...t){let n=this.#n++;return this.worker.postMessage({type:"RPC",transactionId:n,id:e,payload:t}),new Promise((r,a)=>{let d={id:n,resolve:r,reject:a};this.rpcTimeout>0&&(d.timeoutHandle=setTimeout(()=>this.#p(d),this.rpcTimeout)),this.#i.set(n,d)})}addMethod(e,t){if(this.#t.has(e))throw new Error(`rpc handler for ${e} already registered`);this.#t.set(e,t)}removeMethod(e){this.#t.delete(e)}#o(e){let t=e;switch(t.type){case"RPC":return this.#r(t);case"INTERNAL":return this.#a(t);default:this.#e(`invalid message type ${t.type}`)}}#e(e){console.error(e),this.worker.postMessage({type:"INTERNAL",id:"ERROR",payload:e})}async#r(e){let t=this.#t.get(e.id);if(!t)return this.#e(`invalid rpc ${e.id}`);try{let n=await t(...e.payload);this.worker.postMessage({type:"INTERNAL",id:"RESOLVE_TRANSACTION",transactionId:e.transactionId,payload:n})}catch(n){this.worker.postMessage({type:"INTERNAL",id:"REJECT_TRANSACTION",transactionId:e.transactionId,payload:n})}}#a(e){let t=typeof e.transactionId=="number"?this.#i.get(e.transactionId):void 0;switch(e.id){case"RESOLVE_TRANSACTION":if(!t)return this.#e(`no pending transaction with id ${e.transactionId}`);t.resolve(e.payload),this.#s(t);break;case"REJECT_TRANSACTION":if(!t)return this.#e(`no pending transaction with id ${e.transactionId}`);t.reject(e.payload),this.#s(t);break;case"ERROR":console.error(`remote error: ${e.payload}`);break;default:this.#e(`unhandled internal message ${e.id}`);break}}#p(e){e.reject("transaction timed out"),this.#e(`transaction ${e.id} timed out`),this.#i.delete(e.id)}#s(e){typeof e.timeoutHandle<"u"&&clearTimeout(e.timeoutHandle),this.#i.delete(e.id)}};var q=i(async s=>{if(typeof window>"u"||!window.Worker)throw new Error("Swish is not supported in this environment");if(window.swish)return window.swish;try{let n=localStorage.getItem("wk_session_id");n&&localStorage.setItem("swish-profile",`gid://swish/Session/${n}`)}catch(n){console.warn("Failed to migrate legacy session id to Swish profile",{cause:n})}let e=s.proxy?.baseUrl??"/apps/wishlist",t=new I({loadProfile:i(()=>localStorage.getItem("swish-profile"),"loadProfile"),storeProfile:i(n=>localStorage.setItem("swish-profile",n),"storeProfile"),deleteProfile:i(()=>localStorage.removeItem("swish-profile"),"deleteProfile"),proxy:{baseUrl:e},ui:s.ui,storefront:s.storefront});return await t.init(),window.swish=t,document.dispatchEvent(new Event("swish-ready")),t},"swishApp"),I=class{constructor(e){this.api={items:{list:i(e=>this.rpc.call("api.items.list",e),"list"),create:i(e=>this.rpc.call("api.items.create",e),"create"),delete:i(e=>this.rpc.call("api.items.delete",e),"delete"),findById:i(e=>this.rpc.call("api.items.findById",e),"findById"),updateById:i((e,t)=>this.rpc.call("api.items.updateById",e,t),"updateById"),deleteById:i(e=>this.rpc.call("api.items.deleteById",e),"deleteById")},lists:{list:i(()=>this.rpc.call("api.lists.list"),"list"),findById:i((e,t)=>this.rpc.call("api.lists.findById",e,t),"findById"),create:i(e=>this.rpc.call("api.lists.create",e),"create"),updateById:i((e,t)=>this.rpc.call("api.lists.updateById",e,t),"updateById"),deleteById:i(e=>this.rpc.call("api.lists.deleteById",e),"deleteById"),orderItems:i((e,t)=>this.rpc.call("api.lists.orderItems",e,t),"orderItems")},profiles:{customerAccountsVersion:i(()=>this.rpc.call("api.profiles.customerAccountsVersion"),"customerAccountsVersion"),identify:i(e=>this.rpc.call("api.profiles.identify",e),"identify")}};this.storefront={loadProductOptions:i(e=>this.rpc.call("storefront.loadProductOptions",e),"loadProductOptions"),loadSelectedVariant:i(e=>this.rpc.call("storefront.loadSelectedVariant",e),"loadSelectedVariant")};this.ui={showSignIn:T,showVariantSelect:b,initShopBridge:E,showNotification:S};this.options=e,this.worker=new Worker(`${this.options.proxy.baseUrl}/assets/browser/worker.js`,{type:"module"}),this.rpc=new c(this.worker,1e4),this.rpc.addMethod("storeProfile",this.storeProfile.bind(this)),this.rpc.addMethod("deleteProfile",this.deleteProfile.bind(this))}static{i(this,"SwishApp")}async init(){return this.initPromise?this.initPromise:(this.initPromise=this._init(),this.initPromise)}async _init(){this.options.ui&&R(this.options.ui);let e=await this.options.loadProfile?.();e&&this.rpc.call("api.setProfile",e),this.rpc.call("api.setConfig",{baseUrl:`${this.options.proxy.baseUrl}/api`,...this.options.swishApi??{}}),this.rpc.call("storefront.setConfig",this.options.storefront),customElements.define("swish-ui",m)}async storeProfile(e){await this.options.storeProfile?.(e)}async deleteProfile(){await this.options.deleteProfile?.()}};export{I as SwishApp,q as swishApp};