@momentco-ai/moment-sdk 0.1.2 → 0.2.0-dev.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -9
- package/dist/moment-sdk.js +1 -1
- package/dist/moment-sdk.mjs +114 -68
- package/dist/types/sdk/button.d.ts +2 -1
- package/dist/types/sdk/types.d.ts +33 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -29,7 +29,7 @@ npm install @momentco-ai/moment-sdk
|
|
|
29
29
|
<button
|
|
30
30
|
class="moment-sync-trigger"
|
|
31
31
|
data-moment-team-slug="your-team-slug"
|
|
32
|
-
data-
|
|
32
|
+
data-moment-slug="event-001"
|
|
33
33
|
data-moment-trigger-type="moment"
|
|
34
34
|
>
|
|
35
35
|
Add to Calendar
|
|
@@ -71,9 +71,9 @@ Place these on any element matching the trigger selector (default: `.moment-sync
|
|
|
71
71
|
| Attribute | Required | Description |
|
|
72
72
|
| -------------------------- | -------- | ------------------------------------------------------------ |
|
|
73
73
|
| `data-moment-team-slug` | ✅ | Team/brand slug |
|
|
74
|
-
| `data-
|
|
75
|
-
| `data-moment-list-slug` | No | List slug (resolved to
|
|
76
|
-
| `data-moment-trigger-type` | No | `moment` (default), `list`, or `
|
|
74
|
+
| `data-moment-slug` | No | Brand-level moment slug (resolved to real ID by Moment) |
|
|
75
|
+
| `data-moment-list-slug` | No | List slug (resolved to a list-level subscription by Moment) |
|
|
76
|
+
| `data-moment-trigger-type` | No | `moment` (default), `list`, or `team` |
|
|
77
77
|
| `data-moment-ids` | No | Comma-separated moment IDs (fallback if slugs don't resolve) |
|
|
78
78
|
| `data-moment-game-id` | No | Alias for `data-moment-ids` |
|
|
79
79
|
| `data-moment-calendar` | No | Pre-select provider: `google` or `outlook` |
|
|
@@ -93,7 +93,7 @@ You can also open the modal programmatically instead of relying on data attribut
|
|
|
93
93
|
// Open modal
|
|
94
94
|
sdk.open({
|
|
95
95
|
teamSlug: 'your-team-slug',
|
|
96
|
-
|
|
96
|
+
momentSlug: 'event-123',
|
|
97
97
|
triggerType: 'moment',
|
|
98
98
|
ids: ['moment-id-1'],
|
|
99
99
|
calendar: 'google', // optional: skip provider selection
|
|
@@ -120,7 +120,7 @@ Programmatically create a styled trigger button:
|
|
|
120
120
|
<script>
|
|
121
121
|
const btn = createMomentButton({
|
|
122
122
|
teamSlug: 'your-team-slug',
|
|
123
|
-
|
|
123
|
+
momentSlug: 'event-001',
|
|
124
124
|
triggerType: 'moment',
|
|
125
125
|
label: 'Add to Calendar',
|
|
126
126
|
});
|
|
@@ -161,7 +161,7 @@ You can customize trigger button appearance in a few ways:
|
|
|
161
161
|
<script>
|
|
162
162
|
const primaryBtn = createMomentButton({
|
|
163
163
|
teamSlug: 'your-team-slug',
|
|
164
|
-
|
|
164
|
+
momentSlug: 'event-001',
|
|
165
165
|
triggerType: 'moment',
|
|
166
166
|
label: 'Get Tickets + Calendar',
|
|
167
167
|
className: 'my-calendar-btn',
|
|
@@ -177,7 +177,7 @@ You can also create plain HTML triggers and fully own styles/text:
|
|
|
177
177
|
<button
|
|
178
178
|
class="my-calendar-btn moment-sync-trigger"
|
|
179
179
|
data-moment-team-slug="your-team-slug"
|
|
180
|
-
data-
|
|
180
|
+
data-moment-slug="event-001"
|
|
181
181
|
data-moment-trigger-type="moment"
|
|
182
182
|
>
|
|
183
183
|
Add This Match to My Calendar
|
|
@@ -221,7 +221,7 @@ All callbacks (`onSuccess`, `onError`, `onClose`) receive a result payload:
|
|
|
221
221
|
"type": "moment.embed.result",
|
|
222
222
|
"result": "success | error | cancelled",
|
|
223
223
|
"provider": "google | outlook",
|
|
224
|
-
"triggerType": "moment | list |
|
|
224
|
+
"triggerType": "moment | list | team",
|
|
225
225
|
"momentIds": ["..."],
|
|
226
226
|
"message": "optional details"
|
|
227
227
|
}
|
package/dist/moment-sdk.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(u){"use strict";class g{popup=null;pollTimer=null;messageHandler=null;resultReceived=!1;opts;constructor(e){this.opts=e}open(e){this.cleanup(),this.resultReceived=!1;const t=this.buildPopupUrl(e),s=Math.round(window.screenX+(window.outerWidth-500)/2),r=Math.round(window.screenY+(window.outerHeight-700)/2);if(this.popup=window.open(t,"moment-oauth-popup",`width=500,height=700,left=${s},top=${r},menubar=no,toolbar=no,location=yes,status=no`),!this.popup||this.popup.closed){this.sendStatusToIframe("popup-blocked"),this.opts.onPopupBlocked();return}this.sendStatusToIframe("popup-opened"),this.startPolling(),this.messageHandler=i=>{if(i.origin!==this.opts.liveOrigin||i.source!==this.popup)return;const o=i.data;!o||typeof o!="object"||o.source!=="moment-live-embed"||o.type!=="moment.embed.result"||(this.resultReceived=!0,this.sendStatusToIframe("completed"),this.opts.iframeWindow&&this.opts.iframeWindow.postMessage(o,this.opts.liveOrigin),this.opts.onResult(o),this.cleanup())},window.addEventListener("message",this.messageHandler)}cleanup(){if(this.pollTimer&&(clearInterval(this.pollTimer),this.pollTimer=null),this.messageHandler&&(window.removeEventListener("message",this.messageHandler),this.messageHandler=null),this.popup&&!this.popup.closed)try{this.popup.close()}catch{}this.popup=null}buildPopupUrl(e){const t=window.location.origin,s=new URLSearchParams({provider:e.provider,teamSlug:e.teamSlug,ids:e.ids.join(","),triggerType:e.triggerType,returnOrigin:t});return`${this.opts.liveBaseUrl}/en/embed/oauth-popup?${s.toString()}`}startPolling(){this.pollTimer=setInterval(()=>{(!this.popup||this.popup.closed)&&(this.pollTimer&&(clearInterval(this.pollTimer),this.pollTimer=null),this.resultReceived||(this.sendStatusToIframe("popup-closed"),this.opts.onPopupClosed()),this.cleanup())},500)}sendStatusToIframe(e){if(!this.opts.iframeWindow)return;const t={source:"moment-sdk",type:"moment.embed.oauth.status",status:e};this.opts.iframeWindow.postMessage(t,this.opts.liveOrigin)}}const f=".moment-sync-trigger",v="https://live.momentco.ai";class m{opts;liveBaseUrl;liveOrigin;overlay=null;iframe=null;popupBridge=null;messageHandler=null;boundClickHandlers=new Map;activePayload=null;previousFocusedElement=null;previousBodyOverflow="";didManageBodyOverflow=!1;closeTimer=null;constructor(e){this.opts={triggerSelector:f,...e},this.liveBaseUrl=v;try{this.liveOrigin=new URL(this.liveBaseUrl).origin}catch{throw new Error(`[MomentSdk] Invalid VITE_LIVE_BASE_URL: "${this.liveBaseUrl}"`)}this.bindTriggers(),this.emitAnalytics("embed.init")}open(e){this.emitAnalytics("embed.open",{teamSlug:e.teamSlug,triggerType:e.triggerType}),this.createModal(e)}close(){this.handleCancel()}rebind(){this.unbindTriggers(),this.bindTriggers()}destroy(){this.cleanup(),this.unbindTriggers()}bindTriggers(){document.querySelectorAll(this.opts.triggerSelector).forEach(t=>{const s=i=>{i.preventDefault(),this.handleTriggerClick(t)},r=this.boundClickHandlers.get(t);r&&t.removeEventListener("click",r),t.addEventListener("click",s),this.boundClickHandlers.set(t,s)})}unbindTriggers(){this.boundClickHandlers.forEach((e,t)=>{t.removeEventListener("click",e)}),this.boundClickHandlers.clear()}handleTriggerClick(e){const t=e.getAttribute("data-moment-team-slug")??"",s=e.getAttribute("data-external-event-id")??void 0,r=e.getAttribute("data-moment-list-slug")??void 0,i=e.getAttribute("data-moment-trigger-type");let o="moment";i!=null&&i!==""&&(i==="moment"||i==="list"||i==="schedule"?o=i:console.warn("[MomentSdk] Invalid data-moment-trigger-type, falling back to 'moment':",i));const l=e.getAttribute("data-moment-ids")??e.getAttribute("data-moment-game-id")??"",d=l?l.split(",").filter(Boolean):[],a=e.getAttribute("data-moment-calendar");let c;if(a!=null&&a!==""&&(a==="google"||a==="outlook"?c=a:console.warn("[MomentSdk] Invalid data-moment-calendar, ignoring value:",a)),!t){console.warn("[MomentSdk] Missing data-moment-team-slug on trigger element");return}this.emitAnalytics("embed.trigger.click",{teamSlug:t,triggerType:o,momentIds:d}),this.open({teamSlug:t,externalEventId:s,listSlug:r,triggerType:o,ids:d,calendar:c??void 0})}createModal(e){this.cleanup(),this.previousFocusedElement=document.activeElement||null,this.activePayload=e;const t=this.buildIframeUrl(e);this.overlay=document.createElement("div"),this.overlay.setAttribute("role","presentation"),Object.assign(this.overlay.style,{position:"fixed",inset:"0",zIndex:"999999",display:"flex",alignItems:"center",justifyContent:"center",backgroundColor:"rgba(0, 0, 0, 0.5)",backdropFilter:"blur(2px)",padding:"16px"}),this.overlay.addEventListener("click",l=>{l.target===this.overlay&&this.handleCancel()});const s=l=>{l.key==="Escape"&&this.handleCancel()};document.addEventListener("keydown",s);const r=document.createElement("div");r.setAttribute("role","dialog"),r.setAttribute("aria-modal","true"),r.setAttribute("aria-label","Calendar sync modal"),r.tabIndex=-1,Object.assign(r.style,{position:"relative",width:"100%",maxWidth:"420px",maxHeight:"90vh",borderRadius:"16px",overflow:"hidden",backgroundColor:"#ffffff",boxShadow:"0 25px 50px -12px rgba(0, 0, 0, 0.25)"});const i=document.createElement("button");i.type="button",i.textContent="ⓧ",i.setAttribute("aria-label","Close"),Object.assign(i.style,{position:"absolute",top:"8px",right:"8px",zIndex:"10",border:"none",backgroundColor:"transparent",color:"#999",fontSize:"20px",lineHeight:"1",cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center"}),i.addEventListener("click",()=>this.handleCancel()),this.iframe=document.createElement("iframe"),this.iframe.src=t,this.iframe.setAttribute("allow",""),this.iframe.setAttribute("sandbox","allow-scripts allow-same-origin allow-popups allow-forms"),Object.assign(this.iframe.style,{width:"100%",height:"480px",border:"none",display:"block"}),r.appendChild(i),r.appendChild(this.iframe),this.overlay.appendChild(r),document.body.appendChild(this.overlay);const o=l=>{if(l.key!=="Tab")return;const d=r.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');if(d.length===0){l.preventDefault(),r.focus();return}const a=d[0],c=d[d.length-1],h=document.activeElement;l.shiftKey&&h===a?(l.preventDefault(),c.focus()):!l.shiftKey&&h===c&&(l.preventDefault(),a.focus())};r.addEventListener("keydown",o),i.focus(),this.previousBodyOverflow=document.body.style.overflow,document.body.style.overflow="hidden",this.didManageBodyOverflow=!0,this.setupMessageListener(),this.overlay._escHandler=s,this.overlay._focusTrapHandler=o}buildIframeUrl(e){const t=new URLSearchParams;return t.set("teamSlug",e.teamSlug),e.externalEventId&&t.set("momentSlug",e.externalEventId),e.listSlug&&t.set("listSlug",e.listSlug),t.set("triggerType",e.triggerType),e.ids?.length&&t.set("ids",e.ids.join(",")),e.calendar&&t.set("calendar",e.calendar),t.set("returnOrigin",window.location.origin),t.set("embed","1"),`${this.liveBaseUrl}/en/embed/sync?${t.toString()}`}setupMessageListener(){this.messageHandler=e=>{if(e.origin!==this.liveOrigin||e.source!==this.iframe?.contentWindow)return;const t=e.data;if(!(!t||typeof t!="object")){if(t.source==="moment-live-embed"&&t.type==="moment.embed.oauth.start"){const s=t;this.emitAnalytics("oauth.start",{provider:s.provider,teamSlug:s.teamSlug}),this.handleOAuthStart(s);return}if(t.source==="moment-live-embed"&&t.type==="moment.embed.result"){const s=t;this.handleResult(s)}}},window.addEventListener("message",this.messageHandler)}handleOAuthStart(e){this.popupBridge&&(this.popupBridge.cleanup(),this.popupBridge=null),this.popupBridge=new g({liveBaseUrl:this.liveBaseUrl,liveOrigin:this.liveOrigin,iframeWindow:this.iframe?.contentWindow??null,onResult:t=>{this.handleResult(t)},onPopupBlocked:()=>{this.emitAnalytics("oauth.popup.blocked",{provider:e.provider})},onPopupClosed:()=>{this.emitAnalytics("oauth.popup.closed",{provider:e.provider})}}),this.popupBridge.open(e)}handleResult(e){if(e.result==="success")this.emitAnalytics("subscribe.success",{provider:e.provider,triggerType:e.triggerType,momentIds:e.momentIds}),this.opts.onSuccess?.(e);else if(e.result==="error")this.emitAnalytics("subscribe.error",{provider:e.provider,triggerType:e.triggerType,momentIds:e.momentIds}),this.opts.onError?.(e);else if(e.result==="cancelled")return;this.opts.onClose?.(e),this.emitAnalytics("embed.close"),this.closeTimer=setTimeout(()=>this.cleanup(),1500)}handleCancel(){this.emitAnalytics("embed.close");const t={source:"moment-live-embed",type:"moment.embed.result",result:"cancelled",triggerType:this.activePayload?.triggerType??"moment",momentIds:this.activePayload?.ids??[]};this.opts.onClose?.(t),this.cleanup()}cleanup(){if(this.closeTimer&&(clearTimeout(this.closeTimer),this.closeTimer=null),this.popupBridge&&(this.popupBridge.cleanup(),this.popupBridge=null),this.messageHandler&&(window.removeEventListener("message",this.messageHandler),this.messageHandler=null),this.overlay){const{_escHandler:e,_focusTrapHandler:t}=this.overlay;e&&document.removeEventListener("keydown",e);const s=this.overlay.firstElementChild;s&&t&&s.removeEventListener("keydown",t),this.overlay.remove(),this.overlay=null}this.iframe=null,this.activePayload=null,this.didManageBodyOverflow&&(document.body.style.overflow=this.previousBodyOverflow,this.didManageBodyOverflow=!1),this.previousFocusedElement&&typeof this.previousFocusedElement.focus=="function"&&this.previousFocusedElement.focus(),this.previousFocusedElement=null}emitAnalytics(e,t){this.opts.onAnalytics?.({event:e,timestamp:Date.now(),...t})}}function p(n){const e=document.createElement("button");return e.type="button",e.classList.add("moment-sync-trigger"),n.className&&n.className.split(" ").forEach(t=>{t&&e.classList.add(t)}),Object.assign(e.style,{backgroundColor:"#1c1917",color:"#ffffff",border:"1px solid #292524",borderRadius:"4px",padding:"8px 16px",fontSize:"14px",fontWeight:"500",cursor:"pointer",lineHeight:"1.4"}),e.setAttribute("data-moment-team-slug",n.teamSlug),n.externalEventId&&e.setAttribute("data-external-event-id",n.externalEventId),n.listSlug&&e.setAttribute("data-moment-list-slug",n.listSlug),n.triggerType&&e.setAttribute("data-moment-trigger-type",n.triggerType),n.ids?.length&&e.setAttribute("data-moment-ids",n.ids.join(",")),n.calendar&&e.setAttribute("data-moment-calendar",n.calendar),e.textContent=n.label??"Add to Calendar",e}if(typeof window<"u"){const n=window;n.MomentSdk=m,n.createMomentButton=p}u.MomentSdk=m,u.createMomentButton=p,Object.defineProperty(u,Symbol.toStringTag,{value:"Module"})})(this.MomentSdk=this.MomentSdk||{});
|
|
1
|
+
(function(h){"use strict";class y{popup=null;pollTimer=null;messageHandler=null;resultReceived=!1;opts;constructor(e){this.opts=e}open(e){this.cleanup(),this.resultReceived=!1;const t=this.buildPopupUrl(e),n=Math.round(window.screenX+(window.outerWidth-500)/2),r=Math.round(window.screenY+(window.outerHeight-700)/2);if(this.popup=window.open(t,"moment-oauth-popup",`width=500,height=700,left=${n},top=${r},menubar=no,toolbar=no,location=yes,status=no`),!this.popup||this.popup.closed){this.sendStatusToIframe("popup-blocked"),this.opts.onPopupBlocked();return}this.sendStatusToIframe("popup-opened"),this.startPolling(),this.messageHandler=i=>{if(i.origin!==this.opts.liveOrigin||i.source!==this.popup)return;const s=i.data;!s||typeof s!="object"||s.source!=="moment-live-embed"||s.type!=="moment.embed.result"||(this.resultReceived=!0,this.sendStatusToIframe("completed"),this.opts.iframeWindow&&this.opts.iframeWindow.postMessage(s,this.opts.liveOrigin),this.opts.onResult(s),this.cleanup())},window.addEventListener("message",this.messageHandler)}cleanup(){if(this.pollTimer&&(clearInterval(this.pollTimer),this.pollTimer=null),this.messageHandler&&(window.removeEventListener("message",this.messageHandler),this.messageHandler=null),this.popup&&!this.popup.closed)try{this.popup.close()}catch{}this.popup=null}buildPopupUrl(e){const t=window.location.origin,n=new URLSearchParams({provider:e.provider,teamSlug:e.teamSlug,ids:e.ids.join(","),triggerType:e.triggerType,returnOrigin:t});return e.subscriptionType&&n.set("subscriptionType",e.subscriptionType),`${this.opts.liveBaseUrl}/en/embed/oauth-popup?${n.toString()}`}startPolling(){this.pollTimer=setInterval(()=>{(!this.popup||this.popup.closed)&&(this.pollTimer&&(clearInterval(this.pollTimer),this.pollTimer=null),this.resultReceived||(this.sendStatusToIframe("popup-closed"),this.opts.onPopupClosed()),this.cleanup())},500)}sendStatusToIframe(e){if(!this.opts.iframeWindow)return;const t={source:"moment-sdk",type:"moment.embed.oauth.status",status:e};this.opts.iframeWindow.postMessage(t,this.opts.liveOrigin)}}const w=".moment-sync-trigger",T="https://live.dev.momentco.ai";class g{opts;liveBaseUrl;liveOrigin;overlay=null;iframe=null;popupBridge=null;messageHandler=null;boundClickHandlers=new Map;activePayload=null;previousFocusedElement=null;previousBodyOverflow="";didManageBodyOverflow=!1;closeTimer=null;constructor(e){this.opts={triggerSelector:w,...e},this.liveBaseUrl=T;try{this.liveOrigin=new URL(this.liveBaseUrl).origin}catch{throw new Error(`[MomentSdk] Invalid VITE_LIVE_BASE_URL: "${this.liveBaseUrl}"`)}this.bindTriggers(),this.emitAnalytics("embed.init")}open(e){this.emitAnalytics("embed.open",{teamSlug:e.teamSlug,triggerType:e.triggerType}),this.createModal(e)}close(){this.handleCancel()}rebind(){this.unbindTriggers(),this.bindTriggers()}destroy(){this.cleanup(),this.unbindTriggers()}bindTriggers(){document.querySelectorAll(this.opts.triggerSelector).forEach(t=>{const n=i=>{i.preventDefault(),this.handleTriggerClick(t)},r=this.boundClickHandlers.get(t);r&&t.removeEventListener("click",r),t.addEventListener("click",n),this.boundClickHandlers.set(t,n)})}unbindTriggers(){this.boundClickHandlers.forEach((e,t)=>{t.removeEventListener("click",e)}),this.boundClickHandlers.clear()}handleTriggerClick(e){const t=e.getAttribute("data-moment-team-slug")??"",n=e.getAttribute("data-moment-slug")??void 0,r=e.getAttribute("data-moment-list-slug")??void 0,i=e.getAttribute("data-moment-trigger-type");let s="moment";i!=null&&i!==""&&(i==="moment"||i==="list"||i==="team"?s=i:console.warn("[MomentSdk] Invalid data-moment-trigger-type, falling back to 'moment':",i));const d=e.getAttribute("data-moment-ids")??e.getAttribute("data-moment-game-id")??"",u=d?d.split(",").filter(Boolean):[],a=e.getAttribute("data-moment-calendar");let m;if(a!=null&&a!==""&&(a==="google"||a==="outlook"?m=a:console.warn("[MomentSdk] Invalid data-moment-calendar, ignoring value:",a)),!t){console.warn("[MomentSdk] Missing data-moment-team-slug on trigger element");return}const l=s==="team"?void 0:n,c=s==="team"?void 0:r,p=s==="team"?[]:u;this.emitAnalytics("embed.trigger.click",{teamSlug:t,triggerType:s,momentIds:p}),this.open({teamSlug:t,momentSlug:l,listSlug:c,triggerType:s,ids:p,calendar:m??void 0})}createModal(e){this.cleanup(),this.previousFocusedElement=document.activeElement||null,this.activePayload=e;const t=this.buildIframeUrl(e);this.overlay=document.createElement("div"),this.overlay.setAttribute("role","presentation"),Object.assign(this.overlay.style,{position:"fixed",inset:"0",zIndex:"999999",display:"flex",alignItems:"center",justifyContent:"center",backgroundColor:"rgba(0, 0, 0, 0.5)",backdropFilter:"blur(2px)",padding:"16px"}),this.overlay.addEventListener("click",l=>{l.target===this.overlay&&this.handleCancel()});const n=l=>{l.key==="Escape"&&this.handleCancel()};document.addEventListener("keydown",n);const r=document.createElement("div");Object.assign(r.style,{position:"relative",width:"100%",maxWidth:"380px",borderRadius:"16px",overflow:"hidden",backgroundColor:"#000000",boxShadow:"0 25px 50px -12px rgba(0, 0, 0, 0.25)",display:"flex",flexDirection:"column"});const i=document.createElement("div");i.setAttribute("role","dialog"),i.setAttribute("aria-modal","true"),i.setAttribute("aria-label","Calendar sync modal"),i.tabIndex=-1,Object.assign(i.style,{position:"relative",width:"100%",maxHeight:"80vh",borderRadius:"12px",overflow:"auto",backgroundColor:"#ffffff"});const s=document.createElement("button");s.type="button",s.innerHTML='<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M1 1l12 12M13 1L1 13" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/></svg>',s.setAttribute("aria-label","Close"),Object.assign(s.style,{position:"absolute",top:"10px",right:"10px",zIndex:"10",border:"none",backgroundColor:"transparent",color:"#999",cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center",width:"24px",height:"24px",padding:"0"}),s.addEventListener("mouseenter",()=>{s.style.color="#666"}),s.addEventListener("mouseleave",()=>{s.style.color="#999"}),s.addEventListener("click",()=>this.handleCancel()),this.iframe=document.createElement("iframe"),this.iframe.src=t,this.iframe.setAttribute("allow",""),this.iframe.setAttribute("sandbox","allow-scripts allow-same-origin allow-popups allow-forms"),this.iframe.setAttribute("scrolling","no"),Object.assign(this.iframe.style,{width:"100%",border:"none",display:"block",height:"420px",overflow:"hidden",transition:"height 0.15s ease"}),i.appendChild(s),i.appendChild(this.iframe);const d=document.createElement("div");Object.assign(d.style,{display:"flex",alignItems:"center",justifyContent:"center",gap:"6px",padding:"12px 0"});const u=document.createElement("span");u.textContent="Powered by",Object.assign(u.style,{fontFamily:"Inter, system-ui, -apple-system, sans-serif",fontSize:"12px",lineHeight:"16px",color:"#ffffff"});const a=document.createElement("img");a.alt="Moment",a.src=`${this.liveBaseUrl}/brand/moment-text-white.png`,Object.assign(a.style,{height:"auto",width:"67px"}),d.appendChild(u),d.appendChild(a),r.appendChild(i),r.appendChild(d),this.overlay.appendChild(r),document.body.appendChild(this.overlay);const m=l=>{if(l.key!=="Tab")return;const c=i.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');if(c.length===0){l.preventDefault(),i.focus();return}const p=c[0],v=c[c.length-1],b=document.activeElement;l.shiftKey&&b===p?(l.preventDefault(),v.focus()):!l.shiftKey&&b===v&&(l.preventDefault(),p.focus())};i.addEventListener("keydown",m),s.focus(),this.previousBodyOverflow=document.body.style.overflow,document.body.style.overflow="hidden",this.didManageBodyOverflow=!0,this.setupMessageListener(),this.overlay._escHandler=n,this.overlay._focusTrapHandler=m}buildIframeUrl(e){const t=new URLSearchParams;return t.set("teamSlug",e.teamSlug),e.momentSlug&&t.set("momentSlug",e.momentSlug),e.listSlug&&t.set("listSlug",e.listSlug),t.set("triggerType",e.triggerType),e.ids?.length&&t.set("ids",e.ids.join(",")),e.calendar&&t.set("calendar",e.calendar),t.set("returnOrigin",window.location.origin),t.set("embed","1"),`${this.liveBaseUrl}/en/embed/sync?${t.toString()}`}setupMessageListener(){this.messageHandler=e=>{if(e.origin!==this.liveOrigin||e.source!==this.iframe?.contentWindow)return;const t=e.data;if(!(!t||typeof t!="object")){if(t.source==="moment-live-embed"&&t.type==="moment.embed.oauth.start"){const n=t;this.emitAnalytics("oauth.start",{provider:n.provider,teamSlug:n.teamSlug}),this.handleOAuthStart(n);return}if(t.source==="moment-live-embed"&&t.type==="moment.embed.resize"){const n=typeof t.height=="number"?t.height:0;if(n>0&&this.iframe){const r=Math.round(window.innerHeight*.8);this.iframe.style.height=`${Math.min(n,r)}px`}return}if(t.source==="moment-live-embed"&&t.type==="moment.embed.result"){const n=t;this.handleResult(n)}}},window.addEventListener("message",this.messageHandler)}handleOAuthStart(e){this.popupBridge&&(this.popupBridge.cleanup(),this.popupBridge=null),this.popupBridge=new y({liveBaseUrl:this.liveBaseUrl,liveOrigin:this.liveOrigin,iframeWindow:this.iframe?.contentWindow??null,onResult:t=>{this.handleResult(t)},onPopupBlocked:()=>{this.emitAnalytics("oauth.popup.blocked",{provider:e.provider})},onPopupClosed:()=>{this.emitAnalytics("oauth.popup.closed",{provider:e.provider})}}),this.popupBridge.open(e)}handleResult(e){if(e.result==="success")this.emitAnalytics("subscribe.success",{provider:e.provider,triggerType:e.triggerType,momentIds:e.momentIds}),this.opts.onSuccess?.(e);else if(e.result==="error")this.emitAnalytics("subscribe.error",{provider:e.provider,triggerType:e.triggerType,momentIds:e.momentIds}),this.opts.onError?.(e);else if(e.result==="cancelled")return;this.opts.onClose?.(e),this.emitAnalytics("embed.close"),this.closeTimer=setTimeout(()=>this.cleanup(),1500)}handleCancel(){this.emitAnalytics("embed.close");const t={source:"moment-live-embed",type:"moment.embed.result",result:"cancelled",triggerType:this.activePayload?.triggerType??"moment",momentIds:this.activePayload?.ids??[]};this.opts.onClose?.(t),this.cleanup()}cleanup(){if(this.closeTimer&&(clearTimeout(this.closeTimer),this.closeTimer=null),this.popupBridge&&(this.popupBridge.cleanup(),this.popupBridge=null),this.messageHandler&&(window.removeEventListener("message",this.messageHandler),this.messageHandler=null),this.overlay){const{_escHandler:e,_focusTrapHandler:t}=this.overlay;e&&document.removeEventListener("keydown",e);const n=this.overlay.firstElementChild;n&&t&&n.removeEventListener("keydown",t),this.overlay.remove(),this.overlay=null}this.iframe=null,this.activePayload=null,this.didManageBodyOverflow&&(document.body.style.overflow=this.previousBodyOverflow,this.didManageBodyOverflow=!1),this.previousFocusedElement&&typeof this.previousFocusedElement.focus=="function"&&this.previousFocusedElement.focus(),this.previousFocusedElement=null}emitAnalytics(e,t){this.opts.onAnalytics?.({event:e,timestamp:Date.now(),...t})}}function f(o){const e=document.createElement("button");return e.type="button",e.classList.add("moment-sync-trigger"),o.className&&o.className.split(" ").forEach(t=>{t&&e.classList.add(t)}),Object.assign(e.style,{backgroundColor:"#1c1917",color:"#ffffff",border:"1px solid #292524",borderRadius:"4px",padding:"8px 16px",fontSize:"14px",fontWeight:"500",cursor:"pointer",lineHeight:"1.4"}),e.setAttribute("data-moment-team-slug",o.teamSlug),o.momentSlug&&e.setAttribute("data-moment-slug",o.momentSlug),o.listSlug&&e.setAttribute("data-moment-list-slug",o.listSlug),o.triggerType&&e.setAttribute("data-moment-trigger-type",o.triggerType),o.ids?.length&&e.setAttribute("data-moment-ids",o.ids.join(",")),o.calendar&&e.setAttribute("data-moment-calendar",o.calendar),e.textContent=o.label??"Add to Calendar",e}if(typeof window<"u"){const o=window;o.MomentSdk=g,o.createMomentButton=f}h.MomentSdk=g,h.createMomentButton=f,Object.defineProperty(h,Symbol.toStringTag,{value:"Module"})})(this.MomentSdk=this.MomentSdk||{});
|
package/dist/moment-sdk.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
class
|
|
1
|
+
class f {
|
|
2
2
|
popup = null;
|
|
3
3
|
pollTimer = null;
|
|
4
4
|
messageHandler = null;
|
|
@@ -12,19 +12,19 @@ class m {
|
|
|
12
12
|
*/
|
|
13
13
|
open(e) {
|
|
14
14
|
this.cleanup(), this.resultReceived = !1;
|
|
15
|
-
const t = this.buildPopupUrl(e),
|
|
15
|
+
const t = this.buildPopupUrl(e), n = Math.round(window.screenX + (window.outerWidth - 500) / 2), r = Math.round(window.screenY + (window.outerHeight - 700) / 2);
|
|
16
16
|
if (this.popup = window.open(
|
|
17
17
|
t,
|
|
18
18
|
"moment-oauth-popup",
|
|
19
|
-
`width=500,height=700,left=${
|
|
19
|
+
`width=500,height=700,left=${n},top=${r},menubar=no,toolbar=no,location=yes,status=no`
|
|
20
20
|
), !this.popup || this.popup.closed) {
|
|
21
21
|
this.sendStatusToIframe("popup-blocked"), this.opts.onPopupBlocked();
|
|
22
22
|
return;
|
|
23
23
|
}
|
|
24
24
|
this.sendStatusToIframe("popup-opened"), this.startPolling(), this.messageHandler = (i) => {
|
|
25
25
|
if (i.origin !== this.opts.liveOrigin || i.source !== this.popup) return;
|
|
26
|
-
const
|
|
27
|
-
!
|
|
26
|
+
const s = i.data;
|
|
27
|
+
!s || typeof s != "object" || s.source !== "moment-live-embed" || s.type !== "moment.embed.result" || (this.resultReceived = !0, this.sendStatusToIframe("completed"), this.opts.iframeWindow && this.opts.iframeWindow.postMessage(s, this.opts.liveOrigin), this.opts.onResult(s), this.cleanup());
|
|
28
28
|
}, window.addEventListener("message", this.messageHandler);
|
|
29
29
|
}
|
|
30
30
|
/**
|
|
@@ -39,14 +39,14 @@ class m {
|
|
|
39
39
|
this.popup = null;
|
|
40
40
|
}
|
|
41
41
|
buildPopupUrl(e) {
|
|
42
|
-
const t = window.location.origin,
|
|
42
|
+
const t = window.location.origin, n = new URLSearchParams({
|
|
43
43
|
provider: e.provider,
|
|
44
44
|
teamSlug: e.teamSlug,
|
|
45
45
|
ids: e.ids.join(","),
|
|
46
46
|
triggerType: e.triggerType,
|
|
47
47
|
returnOrigin: t
|
|
48
48
|
});
|
|
49
|
-
return `${this.opts.liveBaseUrl}/en/embed/oauth-popup?${
|
|
49
|
+
return e.subscriptionType && n.set("subscriptionType", e.subscriptionType), `${this.opts.liveBaseUrl}/en/embed/oauth-popup?${n.toString()}`;
|
|
50
50
|
}
|
|
51
51
|
startPolling() {
|
|
52
52
|
this.pollTimer = setInterval(() => {
|
|
@@ -63,8 +63,8 @@ class m {
|
|
|
63
63
|
this.opts.iframeWindow.postMessage(t, this.opts.liveOrigin);
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
|
-
const
|
|
67
|
-
class
|
|
66
|
+
const v = ".moment-sync-trigger", b = "https://live.dev.momentco.ai";
|
|
67
|
+
class y {
|
|
68
68
|
opts;
|
|
69
69
|
liveBaseUrl;
|
|
70
70
|
liveOrigin;
|
|
@@ -80,9 +80,9 @@ class g {
|
|
|
80
80
|
closeTimer = null;
|
|
81
81
|
constructor(e) {
|
|
82
82
|
this.opts = {
|
|
83
|
-
triggerSelector:
|
|
83
|
+
triggerSelector: v,
|
|
84
84
|
...e
|
|
85
|
-
}, this.liveBaseUrl =
|
|
85
|
+
}, this.liveBaseUrl = b;
|
|
86
86
|
try {
|
|
87
87
|
this.liveOrigin = new URL(this.liveBaseUrl).origin;
|
|
88
88
|
} catch {
|
|
@@ -120,10 +120,10 @@ class g {
|
|
|
120
120
|
// ── Private: trigger binding ──────────────────────────────────────
|
|
121
121
|
bindTriggers() {
|
|
122
122
|
document.querySelectorAll(this.opts.triggerSelector).forEach((t) => {
|
|
123
|
-
const
|
|
123
|
+
const n = (i) => {
|
|
124
124
|
i.preventDefault(), this.handleTriggerClick(t);
|
|
125
125
|
}, r = this.boundClickHandlers.get(t);
|
|
126
|
-
r && t.removeEventListener("click", r), t.addEventListener("click",
|
|
126
|
+
r && t.removeEventListener("click", r), t.addEventListener("click", n), this.boundClickHandlers.set(t, n);
|
|
127
127
|
});
|
|
128
128
|
}
|
|
129
129
|
unbindTriggers() {
|
|
@@ -132,29 +132,30 @@ class g {
|
|
|
132
132
|
}), this.boundClickHandlers.clear();
|
|
133
133
|
}
|
|
134
134
|
handleTriggerClick(e) {
|
|
135
|
-
const t = e.getAttribute("data-moment-team-slug") ?? "",
|
|
136
|
-
let
|
|
137
|
-
i != null && i !== "" && (i === "moment" || i === "list" || i === "
|
|
135
|
+
const t = e.getAttribute("data-moment-team-slug") ?? "", n = e.getAttribute("data-moment-slug") ?? void 0, r = e.getAttribute("data-moment-list-slug") ?? void 0, i = e.getAttribute("data-moment-trigger-type");
|
|
136
|
+
let s = "moment";
|
|
137
|
+
i != null && i !== "" && (i === "moment" || i === "list" || i === "team" ? s = i : console.warn(
|
|
138
138
|
"[MomentSdk] Invalid data-moment-trigger-type, falling back to 'moment':",
|
|
139
139
|
i
|
|
140
140
|
));
|
|
141
|
-
const
|
|
142
|
-
let
|
|
143
|
-
if (a != null && a !== "" && (a === "google" || a === "outlook" ?
|
|
141
|
+
const d = e.getAttribute("data-moment-ids") ?? e.getAttribute("data-moment-game-id") ?? "", u = d ? d.split(",").filter(Boolean) : [], a = e.getAttribute("data-moment-calendar");
|
|
142
|
+
let m;
|
|
143
|
+
if (a != null && a !== "" && (a === "google" || a === "outlook" ? m = a : console.warn("[MomentSdk] Invalid data-moment-calendar, ignoring value:", a)), !t) {
|
|
144
144
|
console.warn("[MomentSdk] Missing data-moment-team-slug on trigger element");
|
|
145
145
|
return;
|
|
146
146
|
}
|
|
147
|
+
const l = s === "team" ? void 0 : n, c = s === "team" ? void 0 : r, p = s === "team" ? [] : u;
|
|
147
148
|
this.emitAnalytics("embed.trigger.click", {
|
|
148
149
|
teamSlug: t,
|
|
149
|
-
triggerType:
|
|
150
|
-
momentIds:
|
|
150
|
+
triggerType: s,
|
|
151
|
+
momentIds: p
|
|
151
152
|
}), this.open({
|
|
152
153
|
teamSlug: t,
|
|
153
|
-
|
|
154
|
-
listSlug:
|
|
155
|
-
triggerType:
|
|
156
|
-
ids:
|
|
157
|
-
calendar:
|
|
154
|
+
momentSlug: l,
|
|
155
|
+
listSlug: c,
|
|
156
|
+
triggerType: s,
|
|
157
|
+
ids: p,
|
|
158
|
+
calendar: m ?? void 0
|
|
158
159
|
});
|
|
159
160
|
}
|
|
160
161
|
// ── Private: modal creation ───────────────────────────────────────
|
|
@@ -174,59 +175,96 @@ class g {
|
|
|
174
175
|
}), this.overlay.addEventListener("click", (l) => {
|
|
175
176
|
l.target === this.overlay && this.handleCancel();
|
|
176
177
|
});
|
|
177
|
-
const
|
|
178
|
+
const n = (l) => {
|
|
178
179
|
l.key === "Escape" && this.handleCancel();
|
|
179
180
|
};
|
|
180
|
-
document.addEventListener("keydown",
|
|
181
|
+
document.addEventListener("keydown", n);
|
|
181
182
|
const r = document.createElement("div");
|
|
182
|
-
|
|
183
|
+
Object.assign(r.style, {
|
|
183
184
|
position: "relative",
|
|
184
185
|
width: "100%",
|
|
185
|
-
maxWidth: "
|
|
186
|
-
maxHeight: "90vh",
|
|
186
|
+
maxWidth: "380px",
|
|
187
187
|
borderRadius: "16px",
|
|
188
188
|
overflow: "hidden",
|
|
189
|
-
backgroundColor: "#
|
|
190
|
-
boxShadow: "0 25px 50px -12px rgba(0, 0, 0, 0.25)"
|
|
189
|
+
backgroundColor: "#000000",
|
|
190
|
+
boxShadow: "0 25px 50px -12px rgba(0, 0, 0, 0.25)",
|
|
191
|
+
display: "flex",
|
|
192
|
+
flexDirection: "column"
|
|
193
|
+
});
|
|
194
|
+
const i = document.createElement("div");
|
|
195
|
+
i.setAttribute("role", "dialog"), i.setAttribute("aria-modal", "true"), i.setAttribute("aria-label", "Calendar sync modal"), i.tabIndex = -1, Object.assign(i.style, {
|
|
196
|
+
position: "relative",
|
|
197
|
+
width: "100%",
|
|
198
|
+
maxHeight: "80vh",
|
|
199
|
+
borderRadius: "12px",
|
|
200
|
+
overflow: "auto",
|
|
201
|
+
backgroundColor: "#ffffff"
|
|
191
202
|
});
|
|
192
|
-
const
|
|
193
|
-
|
|
203
|
+
const s = document.createElement("button");
|
|
204
|
+
s.type = "button", s.innerHTML = '<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M1 1l12 12M13 1L1 13" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/></svg>', s.setAttribute("aria-label", "Close"), Object.assign(s.style, {
|
|
194
205
|
position: "absolute",
|
|
195
|
-
top: "
|
|
196
|
-
right: "
|
|
206
|
+
top: "10px",
|
|
207
|
+
right: "10px",
|
|
197
208
|
zIndex: "10",
|
|
198
209
|
border: "none",
|
|
199
210
|
backgroundColor: "transparent",
|
|
200
211
|
color: "#999",
|
|
201
|
-
fontSize: "20px",
|
|
202
|
-
lineHeight: "1",
|
|
203
212
|
cursor: "pointer",
|
|
204
213
|
display: "flex",
|
|
205
214
|
alignItems: "center",
|
|
206
|
-
justifyContent: "center"
|
|
207
|
-
|
|
215
|
+
justifyContent: "center",
|
|
216
|
+
width: "24px",
|
|
217
|
+
height: "24px",
|
|
218
|
+
padding: "0"
|
|
219
|
+
}), s.addEventListener("mouseenter", () => {
|
|
220
|
+
s.style.color = "#666";
|
|
221
|
+
}), s.addEventListener("mouseleave", () => {
|
|
222
|
+
s.style.color = "#999";
|
|
223
|
+
}), s.addEventListener("click", () => this.handleCancel()), this.iframe = document.createElement("iframe"), this.iframe.src = t, this.iframe.setAttribute("allow", ""), this.iframe.setAttribute("sandbox", "allow-scripts allow-same-origin allow-popups allow-forms"), this.iframe.setAttribute("scrolling", "no"), Object.assign(this.iframe.style, {
|
|
208
224
|
width: "100%",
|
|
209
|
-
height: "480px",
|
|
210
225
|
border: "none",
|
|
211
|
-
display: "block"
|
|
212
|
-
|
|
213
|
-
|
|
226
|
+
display: "block",
|
|
227
|
+
height: "420px",
|
|
228
|
+
overflow: "hidden",
|
|
229
|
+
transition: "height 0.15s ease"
|
|
230
|
+
}), i.appendChild(s), i.appendChild(this.iframe);
|
|
231
|
+
const d = document.createElement("div");
|
|
232
|
+
Object.assign(d.style, {
|
|
233
|
+
display: "flex",
|
|
234
|
+
alignItems: "center",
|
|
235
|
+
justifyContent: "center",
|
|
236
|
+
gap: "6px",
|
|
237
|
+
padding: "12px 0"
|
|
238
|
+
});
|
|
239
|
+
const u = document.createElement("span");
|
|
240
|
+
u.textContent = "Powered by", Object.assign(u.style, {
|
|
241
|
+
fontFamily: "Inter, system-ui, -apple-system, sans-serif",
|
|
242
|
+
fontSize: "12px",
|
|
243
|
+
lineHeight: "16px",
|
|
244
|
+
color: "#ffffff"
|
|
245
|
+
});
|
|
246
|
+
const a = document.createElement("img");
|
|
247
|
+
a.alt = "Moment", a.src = `${this.liveBaseUrl}/brand/moment-text-white.png`, Object.assign(a.style, {
|
|
248
|
+
height: "auto",
|
|
249
|
+
width: "67px"
|
|
250
|
+
}), d.appendChild(u), d.appendChild(a), r.appendChild(i), r.appendChild(d), this.overlay.appendChild(r), document.body.appendChild(this.overlay);
|
|
251
|
+
const m = (l) => {
|
|
214
252
|
if (l.key !== "Tab") return;
|
|
215
|
-
const
|
|
253
|
+
const c = i.querySelectorAll(
|
|
216
254
|
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
|
|
217
255
|
);
|
|
218
|
-
if (
|
|
219
|
-
l.preventDefault(),
|
|
256
|
+
if (c.length === 0) {
|
|
257
|
+
l.preventDefault(), i.focus();
|
|
220
258
|
return;
|
|
221
259
|
}
|
|
222
|
-
const
|
|
223
|
-
l.shiftKey &&
|
|
260
|
+
const p = c[0], h = c[c.length - 1], g = document.activeElement;
|
|
261
|
+
l.shiftKey && g === p ? (l.preventDefault(), h.focus()) : !l.shiftKey && g === h && (l.preventDefault(), p.focus());
|
|
224
262
|
};
|
|
225
|
-
|
|
263
|
+
i.addEventListener("keydown", m), s.focus(), this.previousBodyOverflow = document.body.style.overflow, document.body.style.overflow = "hidden", this.didManageBodyOverflow = !0, this.setupMessageListener(), this.overlay._escHandler = n, this.overlay._focusTrapHandler = m;
|
|
226
264
|
}
|
|
227
265
|
buildIframeUrl(e) {
|
|
228
266
|
const t = new URLSearchParams();
|
|
229
|
-
return t.set("teamSlug", e.teamSlug), e.
|
|
267
|
+
return t.set("teamSlug", e.teamSlug), e.momentSlug && t.set("momentSlug", e.momentSlug), e.listSlug && t.set("listSlug", e.listSlug), t.set("triggerType", e.triggerType), e.ids?.length && t.set("ids", e.ids.join(",")), e.calendar && t.set("calendar", e.calendar), t.set("returnOrigin", window.location.origin), t.set("embed", "1"), `${this.liveBaseUrl}/en/embed/sync?${t.toString()}`;
|
|
230
268
|
}
|
|
231
269
|
// ── Private: message handling ─────────────────────────────────────
|
|
232
270
|
setupMessageListener() {
|
|
@@ -235,22 +273,30 @@ class g {
|
|
|
235
273
|
const t = e.data;
|
|
236
274
|
if (!(!t || typeof t != "object")) {
|
|
237
275
|
if (t.source === "moment-live-embed" && t.type === "moment.embed.oauth.start") {
|
|
238
|
-
const
|
|
276
|
+
const n = t;
|
|
239
277
|
this.emitAnalytics("oauth.start", {
|
|
240
|
-
provider:
|
|
241
|
-
teamSlug:
|
|
242
|
-
}), this.handleOAuthStart(
|
|
278
|
+
provider: n.provider,
|
|
279
|
+
teamSlug: n.teamSlug
|
|
280
|
+
}), this.handleOAuthStart(n);
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
if (t.source === "moment-live-embed" && t.type === "moment.embed.resize") {
|
|
284
|
+
const n = typeof t.height == "number" ? t.height : 0;
|
|
285
|
+
if (n > 0 && this.iframe) {
|
|
286
|
+
const r = Math.round(window.innerHeight * 0.8);
|
|
287
|
+
this.iframe.style.height = `${Math.min(n, r)}px`;
|
|
288
|
+
}
|
|
243
289
|
return;
|
|
244
290
|
}
|
|
245
291
|
if (t.source === "moment-live-embed" && t.type === "moment.embed.result") {
|
|
246
|
-
const
|
|
247
|
-
this.handleResult(
|
|
292
|
+
const n = t;
|
|
293
|
+
this.handleResult(n);
|
|
248
294
|
}
|
|
249
295
|
}
|
|
250
296
|
}, window.addEventListener("message", this.messageHandler);
|
|
251
297
|
}
|
|
252
298
|
handleOAuthStart(e) {
|
|
253
|
-
this.popupBridge && (this.popupBridge.cleanup(), this.popupBridge = null), this.popupBridge = new
|
|
299
|
+
this.popupBridge && (this.popupBridge.cleanup(), this.popupBridge = null), this.popupBridge = new f({
|
|
254
300
|
liveBaseUrl: this.liveBaseUrl,
|
|
255
301
|
liveOrigin: this.liveOrigin,
|
|
256
302
|
iframeWindow: this.iframe?.contentWindow ?? null,
|
|
@@ -302,8 +348,8 @@ class g {
|
|
|
302
348
|
if (this.closeTimer && (clearTimeout(this.closeTimer), this.closeTimer = null), this.popupBridge && (this.popupBridge.cleanup(), this.popupBridge = null), this.messageHandler && (window.removeEventListener("message", this.messageHandler), this.messageHandler = null), this.overlay) {
|
|
303
349
|
const { _escHandler: e, _focusTrapHandler: t } = this.overlay;
|
|
304
350
|
e && document.removeEventListener("keydown", e);
|
|
305
|
-
const
|
|
306
|
-
|
|
351
|
+
const n = this.overlay.firstElementChild;
|
|
352
|
+
n && t && n.removeEventListener("keydown", t), this.overlay.remove(), this.overlay = null;
|
|
307
353
|
}
|
|
308
354
|
this.iframe = null, this.activePayload = null, this.didManageBodyOverflow && (document.body.style.overflow = this.previousBodyOverflow, this.didManageBodyOverflow = !1), this.previousFocusedElement && typeof this.previousFocusedElement.focus == "function" && this.previousFocusedElement.focus(), this.previousFocusedElement = null;
|
|
309
355
|
}
|
|
@@ -316,9 +362,9 @@ class g {
|
|
|
316
362
|
});
|
|
317
363
|
}
|
|
318
364
|
}
|
|
319
|
-
function
|
|
365
|
+
function w(o) {
|
|
320
366
|
const e = document.createElement("button");
|
|
321
|
-
return e.type = "button", e.classList.add("moment-sync-trigger"),
|
|
367
|
+
return e.type = "button", e.classList.add("moment-sync-trigger"), o.className && o.className.split(" ").forEach((t) => {
|
|
322
368
|
t && e.classList.add(t);
|
|
323
369
|
}), Object.assign(e.style, {
|
|
324
370
|
backgroundColor: "#1c1917",
|
|
@@ -330,13 +376,13 @@ function f(n) {
|
|
|
330
376
|
fontWeight: "500",
|
|
331
377
|
cursor: "pointer",
|
|
332
378
|
lineHeight: "1.4"
|
|
333
|
-
}), e.setAttribute("data-moment-team-slug",
|
|
379
|
+
}), e.setAttribute("data-moment-team-slug", o.teamSlug), o.momentSlug && e.setAttribute("data-moment-slug", o.momentSlug), o.listSlug && e.setAttribute("data-moment-list-slug", o.listSlug), o.triggerType && e.setAttribute("data-moment-trigger-type", o.triggerType), o.ids?.length && e.setAttribute("data-moment-ids", o.ids.join(",")), o.calendar && e.setAttribute("data-moment-calendar", o.calendar), e.textContent = o.label ?? "Add to Calendar", e;
|
|
334
380
|
}
|
|
335
381
|
if (typeof window < "u") {
|
|
336
|
-
const
|
|
337
|
-
|
|
382
|
+
const o = window;
|
|
383
|
+
o.MomentSdk = y, o.createMomentButton = w;
|
|
338
384
|
}
|
|
339
385
|
export {
|
|
340
|
-
|
|
341
|
-
|
|
386
|
+
y as MomentSdk,
|
|
387
|
+
w as createMomentButton
|
|
342
388
|
};
|
|
@@ -5,7 +5,8 @@ import type { MomentTriggerType, CalendarProvider } from './types';
|
|
|
5
5
|
*/
|
|
6
6
|
export declare function createMomentButton(options: {
|
|
7
7
|
teamSlug: string;
|
|
8
|
-
|
|
8
|
+
/** Brand-level moment slug. */
|
|
9
|
+
momentSlug?: string;
|
|
9
10
|
listSlug?: string;
|
|
10
11
|
triggerType?: MomentTriggerType;
|
|
11
12
|
ids?: string[];
|
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Subscription target type forwarded to the Live embed and ultimately mapped
|
|
3
|
+
* to the backend `subscriptionType`.
|
|
4
|
+
*
|
|
5
|
+
* - `moment` → subscribe to one or more specific moments
|
|
6
|
+
* - `list` → subscribe to a curated list of moments
|
|
7
|
+
* - `team` → subscribe to a team / brand schedule (all published moments)
|
|
8
|
+
*/
|
|
9
|
+
export type MomentTriggerType = 'moment' | 'list' | 'team';
|
|
2
10
|
export type CalendarProvider = 'google' | 'outlook';
|
|
3
11
|
export interface MomentSdkInitOptions {
|
|
4
12
|
/** CSS selector for trigger elements. Default: ".moment-sync-trigger" */
|
|
@@ -12,14 +20,29 @@ export interface MomentSdkInitOptions {
|
|
|
12
20
|
/** Optional analytics callback for tracking embed events. */
|
|
13
21
|
onAnalytics?: (event: MomentAnalyticsEvent) => void;
|
|
14
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* Payload accepted by `MomentSdk.open()` and parsed from trigger element
|
|
25
|
+
* `data-moment-*` attributes.
|
|
26
|
+
*
|
|
27
|
+
* Required fields by `triggerType`:
|
|
28
|
+
* - `moment` → `teamSlug` plus EITHER `momentSlug` (brand-level moment slug)
|
|
29
|
+
* OR `ids`
|
|
30
|
+
* - `list` → `teamSlug` plus `listSlug` (`ids` not required — list resolves
|
|
31
|
+
* to a single list-level subscription)
|
|
32
|
+
* - `team` → `teamSlug` only (resolves to the brand's team-level
|
|
33
|
+
* subscription; `listSlug`, `momentSlug`, and `ids` are ignored)
|
|
34
|
+
*/
|
|
15
35
|
export interface MomentSdkOpenPayload {
|
|
16
36
|
teamSlug: string;
|
|
17
|
-
|
|
37
|
+
/** Brand-level moment slug. */
|
|
38
|
+
momentSlug?: string;
|
|
18
39
|
listSlug?: string;
|
|
19
40
|
triggerType: MomentTriggerType;
|
|
20
41
|
ids?: string[];
|
|
21
42
|
calendar?: CalendarProvider;
|
|
22
43
|
}
|
|
44
|
+
/** Backend subscription resource type that the embed will create */
|
|
45
|
+
export type MomentSubscriptionType = 'moment' | 'list' | 'team';
|
|
23
46
|
/** Iframe → Parent: request to start OAuth via popup */
|
|
24
47
|
export interface MomentOAuthStartPayload {
|
|
25
48
|
source: 'moment-live-embed';
|
|
@@ -28,6 +51,14 @@ export interface MomentOAuthStartPayload {
|
|
|
28
51
|
teamSlug: string;
|
|
29
52
|
ids: string[];
|
|
30
53
|
triggerType: MomentTriggerType;
|
|
54
|
+
/**
|
|
55
|
+
* Authoritative backend subscription type for `ids`.
|
|
56
|
+
* The iframe is the single source of truth: when present this should be
|
|
57
|
+
* forwarded verbatim to the popup so the popup does not need to re-derive
|
|
58
|
+
* it from `triggerType` (which would mis-handle cherry-picked moment IDs
|
|
59
|
+
* under a `list`/`team` trigger).
|
|
60
|
+
*/
|
|
61
|
+
subscriptionType?: MomentSubscriptionType;
|
|
31
62
|
returnOrigin: string;
|
|
32
63
|
}
|
|
33
64
|
/** Parent → Iframe: relay OAuth popup status */
|
package/package.json
CHANGED