UNPKG

@trycourier/courier-ui-inbox

Version:

Inbox components for the Courier web UI

1,295 lines (1,271 loc) 191 kB
var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); import { Courier, InboxMessageEvent } from "@trycourier/courier-js"; import { Courier as Courier2 } from "@trycourier/courier-js"; var __defProp2 = Object.defineProperty; var __typeError = (msg) => { throw TypeError(msg); }; var __defNormalProp2 = (obj, key, value) => key in obj ? __defProp2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField2 = (obj, key, value) => __defNormalProp2(obj, typeof key !== "symbol" ? key + "" : key, value); var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg); var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), member.get(obj)); var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value); var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), member.set(obj, value), value); var _isInitialised; const CourierColors = { black: { 500: "#171717", 50010: "#1717171A", 50020: "#17171733" }, gray: { 200: "#F5F5F5", 400: "#3A3A3A", 500: "#E5E5E5", 600: "#737373" }, white: { 500: "#FFFFFF", 50010: "#FFFFFF1A", 50020: "#FFFFFF33" }, blue: { 400: "#60A5FA", 500: "#2563EB" } }; const theme = { light: { colors: { primary: CourierColors.black[500], secondary: CourierColors.white[500], border: CourierColors.gray[500], link: CourierColors.blue[500], icon: CourierColors.black[500] }, button: { cornerRadius: "4px" } }, dark: { colors: { primary: CourierColors.white[500], secondary: CourierColors.black[500], border: CourierColors.gray[400], link: CourierColors.blue[400], icon: CourierColors.white[500] }, button: { cornerRadius: "4px" } } }; const getSystemThemeMode = () => { if (typeof window === "undefined") { return "light"; } return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"; }; const addSystemThemeModeListener = (callback) => { if (typeof window === "undefined") { return () => { }; } const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)"); const handler = (e) => { callback(e.matches ? "dark" : "light"); }; mediaQuery.addEventListener("change", handler); return () => { mediaQuery.removeEventListener("change", handler); }; }; const HTMLElementBase = (() => { try { return typeof HTMLElement === "undefined" ? class { } : HTMLElement; } catch { return class { }; } })(); class CourierBaseElement extends HTMLElementBase { constructor() { super(...arguments); __privateAdd(this, _isInitialised, false); } /** Tag-name you’ll use in `customElements.define()` */ static get id() { return "courier-base-element"; } /* ------------------------------------------------------------------ */ /* Custom-elements lifecycle hooks */ /* ------------------------------------------------------------------ */ connectedCallback() { var _a; if (__privateGet(this, _isInitialised)) return; __privateSet(this, _isInitialised, true); (_a = this.onComponentMounted) == null ? void 0 : _a.call(this); } disconnectedCallback() { var _a; __privateSet(this, _isInitialised, false); (_a = this.onComponentUnmounted) == null ? void 0 : _a.call(this); } /* ------------------------------------------------------------------ */ /* Overridable hooks */ /* ------------------------------------------------------------------ */ /** Called **once** when the element first becomes part of the DOM. */ // eslint-disable-next-line @typescript-eslint/no-empty-function onComponentMounted() { } /** Called when the element is removed from the DOM. */ // eslint-disable-next-line @typescript-eslint/no-empty-function onComponentUnmounted() { } } _isInitialised = /* @__PURE__ */ new WeakMap(); class CourierSystemThemeElement extends CourierBaseElement { constructor() { super(); __publicField2(this, "_currentSystemTheme"); __publicField2(this, "_systemThemeCleanup"); this._currentSystemTheme = getSystemThemeMode(); this._systemThemeCleanup = addSystemThemeModeListener((mode) => { this._currentSystemTheme = mode; this.onSystemThemeChange(mode); }); } static get id() { return "courier-system-theme-element"; } get currentSystemTheme() { return this._currentSystemTheme; } onComponentUnmounted() { var _a; (_a = this._systemThemeCleanup) == null ? void 0 : _a.call(this); super.onComponentUnmounted(); } onSystemThemeChange(_) { } } const baseButtonStyles = { borderRadius: "4px", fontSize: "14px" }; const CourierButtonVariants = { primary: (mode) => { return { ...baseButtonStyles, backgroundColor: theme[mode].colors.primary, textColor: theme[mode].colors.secondary, fontWeight: "500", shadow: "none" }; }, secondary: (mode) => { return { ...baseButtonStyles, backgroundColor: theme[mode].colors.secondary, textColor: theme[mode].colors.primary, fontWeight: "500", border: `1px solid ${theme[mode].colors.border}`, shadow: mode === "light" ? "0px 1px 2px 0px rgba(0, 0, 0, 0.06)" : "0px 1px 2px 0px rgba(255, 255, 255, 0.1)" }; }, tertiary: (mode) => { return { ...baseButtonStyles, backgroundColor: theme[mode].colors.border, textColor: theme[mode].colors.primary, fontWeight: "500", border: "none", shadow: "none" }; } }; class CourierButton extends CourierSystemThemeElement { constructor(props) { super(); __publicField2(this, "_button"); __publicField2(this, "_style"); const shadow = this.attachShadow({ mode: "open" }); this._button = document.createElement("button"); this._button.setAttribute("part", "button"); this._style = document.createElement("style"); this._style.textContent = this.getStyles(props); shadow.appendChild(this._style); shadow.appendChild(this._button); this.updateButton(props); this._button.addEventListener("click", (e) => { e.preventDefault(); e.stopPropagation(); if (props.onClick) { props.onClick(); } }); } static get id() { return "courier-button"; } getStyles(props) { const mode = props.mode === "system" ? this.currentSystemTheme : props.mode; const defaultTextColor = () => { const secondary = CourierButtonVariants.secondary(mode); return secondary.textColor; }; const defaultBackgroundColor = () => { const secondary = CourierButtonVariants.secondary(mode); return secondary.backgroundColor; }; const defaultBorder = () => { const secondary = CourierButtonVariants.secondary(mode); return secondary.border; }; const defaultShadow = () => { const secondary = CourierButtonVariants.secondary(mode); return secondary.shadow; }; const defaultBorderRadius = () => { const secondary = CourierButtonVariants.secondary(mode); return secondary.borderRadius; }; const defaultFontSize = () => { const secondary = CourierButtonVariants.secondary(mode); return secondary.fontSize; }; const defaultFontWeight = () => { const secondary = CourierButtonVariants.secondary(mode); return secondary.fontWeight; }; return ` :host { display: inline-block; } button { border: none; border-radius: ${props.borderRadius ?? defaultBorderRadius()}; font-weight: ${props.fontWeight ?? defaultFontWeight()}; font-family: ${props.fontFamily ?? "inherit"}; font-size: ${props.fontSize ?? defaultFontSize()}; padding: 6px 10px; cursor: pointer; width: 100%; height: 100%; background-color: ${props.backgroundColor ?? defaultBackgroundColor()}; color: ${props.textColor ?? defaultTextColor()}; border: ${props.border ?? defaultBorder()}; box-shadow: ${props.shadow ?? defaultShadow()}; touch-action: manipulation; } button:hover { ${props.hoverBackgroundColor ? `background-color: ${props.hoverBackgroundColor};` : "filter: brightness(0.9);"} } button:active { ${props.activeBackgroundColor ? `background-color: ${props.activeBackgroundColor};` : "filter: brightness(0.8);"} } button:disabled { opacity: 0.5; cursor: not-allowed; } `; } updateButton(props) { if (props.text) { this._button.textContent = props.text; } this._style.textContent = this.getStyles(props); } } const CourierIconSVGs = { inbox: `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M5.5 14.5V17C5.5 17.2812 5.71875 17.5 6 17.5H18C18.25 17.5 18.5 17.2812 18.5 17V14.5H15.9375L15.2812 15.8125C15.0938 16.25 14.6562 16.5 14.1875 16.5H9.78125C9.3125 16.5 8.875 16.25 8.6875 15.8125L8.03125 14.5H5.5ZM18.1875 13L16.6562 6.90625C16.5938 6.65625 16.4062 6.5 16.1875 6.5H7.8125C7.5625 6.5 7.375 6.65625 7.3125 6.90625L5.78125 13H8.1875C8.65625 13 9.09375 13.2812 9.3125 13.7188L9.9375 15H14.0312L14.6875 13.7188C14.875 13.2812 15.3125 13 15.7812 13H18.1875ZM4 14.25C4 14.0938 4 13.9375 4.03125 13.7812L5.84375 6.53125C6.09375 5.625 6.875 5 7.8125 5H16.1875C17.0938 5 17.9062 5.625 18.125 6.53125L19.9375 13.7812C19.9688 13.9375 20 14.0938 20 14.25V17C20 18.125 19.0938 19 18 19H6C4.875 19 4 18.125 4 17V14.25Z" fill="currentColor"/> </svg>`, archive: `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M5.5 6.5V8H18.5V6.5H5.5ZM5 5H19C19.5312 5 20 5.46875 20 6V8.5C20 9.0625 19.5312 9.5 19 9.5H5C4.4375 9.5 4 9.0625 4 8.5V6C4 5.46875 4.4375 5 5 5ZM9 11.75C9 11.3438 9.3125 11 9.75 11H14.25C14.6562 11 15 11.3438 15 11.75C15 12.1875 14.6562 12.5 14.25 12.5H9.75C9.3125 12.5 9 12.1875 9 11.75ZM5 17V10.5H6.5V17C6.5 17.2812 6.71875 17.5 7 17.5H17C17.25 17.5 17.5 17.2812 17.5 17V10.5H19V17C19 18.125 18.0938 19 17 19H7C5.875 19 5 18.125 5 17Z" fill="currentColor"/> </svg>`, check: `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M18.793 7.33203C19.0742 7.64453 19.0742 8.11328 18.793 8.39453L10.543 16.6445C10.2305 16.957 9.76172 16.957 9.48047 16.6445L5.23047 12.3945C4.91797 12.1133 4.91797 11.6445 5.23047 11.3633C5.51172 11.0508 5.98047 11.0508 6.26172 11.3633L9.98047 15.082L17.7305 7.33203C18.0117 7.05078 18.4805 7.05078 18.7617 7.33203H18.793Z" fill="currentColor"/> </svg>`, filter: `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M5 7C5 6.59375 5.3125 6.25 5.75 6.25H18.25C18.6562 6.25 19 6.59375 19 7C19 7.4375 18.6562 7.75 18.25 7.75H5.75C5.3125 7.75 5 7.4375 5 7ZM7 12C7 11.5938 7.3125 11.25 7.75 11.25H16.25C16.6562 11.25 17 11.5938 17 12C17 12.4375 16.6562 12.75 16.25 12.75H7.75C7.3125 12.75 7 12.4375 7 12ZM14 17C14 17.4375 13.6562 17.75 13.25 17.75H10.75C10.3125 17.75 10 17.4375 10 17C10 16.5938 10.3125 16.25 10.75 16.25H13.25C13.6562 16.25 14 16.5938 14 17Z" fill="currentColor"/> </svg>`, overflow: `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M18.5117 11.9883C18.5117 12.5508 18.1992 13.0195 17.7617 13.3008C17.293 13.582 16.6992 13.582 16.2617 13.3008C15.793 13.0195 15.5117 12.5508 15.5117 11.9883C15.5117 11.457 15.793 10.9883 16.2617 10.707C16.6992 10.4258 17.293 10.4258 17.7617 10.707C18.1992 10.9883 18.5117 11.457 18.5117 11.9883ZM13.5117 11.9883C13.5117 12.5508 13.1992 13.0195 12.7617 13.3008C12.293 13.582 11.6992 13.582 11.2617 13.3008C10.793 13.0195 10.5117 12.5508 10.5117 11.9883C10.5117 11.457 10.793 10.9883 11.2617 10.707C11.6992 10.4258 12.293 10.4258 12.7617 10.707C13.1992 10.9883 13.5117 11.457 13.5117 11.9883ZM7.01172 13.4883C6.44922 13.4883 5.98047 13.207 5.69922 12.7383C5.41797 12.3008 5.41797 11.707 5.69922 11.2383C5.98047 10.8008 6.44922 10.4883 7.01172 10.4883C7.54297 10.4883 8.01172 10.8008 8.29297 11.2383C8.57422 11.707 8.57422 12.3008 8.29297 12.7383C8.01172 13.207 7.54297 13.4883 7.01172 13.4883Z" fill="currentColor"/> </svg>`, read: `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M7 6.5C6.71875 6.5 6.5 6.75 6.5 7V17C6.5 17.2812 6.71875 17.5 7 17.5H17C17.25 17.5 17.5 17.2812 17.5 17V7C17.5 6.75 17.25 6.5 17 6.5H7ZM5 7C5 5.90625 5.875 5 7 5H17C18.0938 5 19 5.90625 19 7V17C19 18.125 18.0938 19 17 19H7C5.875 19 5 18.125 5 17V7ZM15.5312 10.5312L11.5312 14.5312C11.2188 14.8438 10.75 14.8438 10.4688 14.5312L8.46875 12.5312C8.15625 12.25 8.15625 11.7812 8.46875 11.5C8.75 11.1875 9.21875 11.1875 9.53125 11.5L11 12.9688L14.4688 9.46875C14.75 9.1875 15.2188 9.1875 15.5 9.46875C15.8125 9.78125 15.8125 10.25 15.5 10.5312H15.5312Z" fill="currentColor"/> </svg>`, archiveRead: `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M7.5 6.5V15.25H16.5V6.5H7.5ZM6 15.25V6.5C6 5.6875 6.65625 5 7.5 5H16.5C17.3125 5 18 5.6875 18 6.5V15.25C18.4062 15.25 18.75 15.5938 18.75 16C18.75 16.4375 18.4062 16.75 18 16.75H6C5.5625 16.75 5.25 16.4375 5.25 16C5.25 15.5938 5.5625 15.25 6 15.25ZM5 13V14.5H4.5V17.5H19.5V14.5H19V13H19.5C20.3125 13 21 13.6875 21 14.5V17.5C21 18.3438 20.3125 19 19.5 19H4.5C3.65625 19 3 18.3438 3 17.5V14.5C3 13.6875 3.65625 13 4.5 13H5ZM15.0312 9.625L11.6875 12.9688C11.5312 13.0938 11.3438 13.1875 11.1562 13.1875C10.9375 13.1875 10.75 13.0938 10.625 12.9688L8.96875 11.2812C8.65625 11 8.65625 10.5312 8.96875 10.25C9.25 9.9375 9.71875 9.9375 10 10.25L11.1562 11.375L13.9688 8.5625C14.25 8.28125 14.7188 8.28125 15 8.5625C15.3125 8.875 15.3125 9.34375 15 9.625H15.0312Z" fill="currentColor"/> </svg>`, unread: `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M17 6.5H7C6.71875 6.5 6.5 6.75 6.5 7V17C6.5 17.2812 6.71875 17.5 7 17.5H17C17.25 17.5 17.5 17.2812 17.5 17V7C17.5 6.75 17.25 6.5 17 6.5ZM7 5H17C18.0938 5 19 5.90625 19 7V17C19 18.125 18.0938 19 17 19H7C5.875 19 5 18.125 5 17V7C5 5.90625 5.875 5 7 5Z" fill="currentColor"/> </svg>`, unarchive: `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M5.5 11C5.0625 11 4.75 10.6875 4.75 10.25V5.75C4.75 5.34375 5.0625 5 5.5 5C5.90625 5 6.25 5.34375 6.25 5.75V8.28125L6.875 7.53125C8.15625 6 10.0625 5 12.25 5C16.0938 5 19.25 8.15625 19.25 12C19.25 15.875 16.0938 19 12.25 19C10.6562 19 9.21875 18.5 8.03125 17.625C7.71875 17.375 7.625 16.9062 7.875 16.5625C8.125 16.2188 8.59375 16.1562 8.9375 16.4062C9.84375 17.0938 11 17.5 12.25 17.5C15.2812 17.5 17.75 15.0625 17.75 12C17.75 8.96875 15.2812 6.5 12.25 6.5C10.5312 6.5 9.03125 7.28125 8 8.5L7.15625 9.5H10C10.4062 9.5 10.75 9.84375 10.75 10.25C10.75 10.6875 10.4062 11 10 11H5.5Z" fill="currentColor"/> </svg>` }; class CourierIcon extends CourierBaseElement { constructor(color, svg) { super(); __publicField2(this, "_color"); __publicField2(this, "_svg"); __publicField2(this, "_iconContainer"); __publicField2(this, "_style"); this._color = color ?? CourierColors.black[500]; this._svg = svg; const shadow = this.attachShadow({ mode: "open" }); this._iconContainer = document.createElement("div"); shadow.appendChild(this._iconContainer); this._style = document.createElement("style"); this._style.textContent = this.getStyles(this._color); shadow.appendChild(this._style); this.refresh(); } static get id() { return "courier-icon"; } getStyles(color) { return ` :host { display: inline-block; line-height: 0; display: flex; align-items: center; justify-content: center; } svg { width: 24px; height: 24px; color: ${color}; } `; } refresh() { if (this._svg) { this._iconContainer.innerHTML = this._svg; } if (this._color) { this._style.textContent = this.getStyles(this._color); } } updateColor(color) { this._color = color; this.refresh(); } updateSVG(svg) { this._svg = svg; this.refresh(); } } class CourierLink extends CourierBaseElement { constructor() { super(); __publicField2(this, "link"); const shadow = this.attachShadow({ mode: "open" }); this.link = document.createElement("a"); this.link.setAttribute("part", "link"); const style = document.createElement("style"); style.textContent = ` :host { display: inline-block; } a { text-decoration: none; border-radius: 4px; cursor: pointer; font-weight: 500; transition: all 0.2s ease; font-family: var(--courier-link-font-family, inherit); font-size: var(--courier-link-font-size, inherit); } /* Variants */ a[data-variant="primary"][data-mode="light"] { color: var(--courier-link-color, ${theme.light.colors.link}); } a[data-variant="primary"][data-mode="light"]:hover { opacity: 0.8; } a[data-variant="primary"][data-mode="light"]:active { opacity: 0.6; } a[data-variant="primary"][data-mode="dark"] { color: var(--courier-link-color, ${theme.dark.colors.link}); } a[data-variant="primary"][data-mode="dark"]:hover { opacity: 0.8; } a[data-variant="primary"][data-mode="dark"]:active { opacity: 0.6; } a[data-underline="true"] { text-decoration: underline; } a:disabled { opacity: 0.6; cursor: not-allowed; pointer-events: none; } `; shadow.appendChild(style); shadow.appendChild(this.link); this.updateVariant(); this.updateUnderline(); this.updateMode(); } static get id() { return "courier-link"; } connectedCallback() { const slot = document.createElement("slot"); this.link.appendChild(slot); this.updateHref(); } attributeChangedCallback(name, oldValue, newValue) { if (oldValue === newValue) return; switch (name) { case "href": this.updateHref(); break; case "variant": case "mode": this.updateVariant(); break; case "disabled": this.link.style.pointerEvents = this.hasAttribute("disabled") ? "none" : "auto"; this.link.style.opacity = this.hasAttribute("disabled") ? "0.6" : "1"; break; case "color": this.updateColor(); break; case "underline": this.updateUnderline(); break; case "target": this.updateTarget(); break; case "font-family": this.updateFontFamily(); break; case "font-size": this.updateFontSize(); break; } } updateHref() { const href = this.getAttribute("href"); if (href) { this.link.href = href; } } updateVariant() { const variant = this.getAttribute("variant") || "primary"; const mode = this.getAttribute("mode") || "light"; this.link.setAttribute("data-variant", variant); this.link.setAttribute("data-mode", mode); } updateColor() { const color = this.getAttribute("color"); if (color) { this.link.style.setProperty("--courier-link-color", color); } else { this.link.style.removeProperty("--courier-link-color"); } } updateUnderline() { const underline = this.getAttribute("underline") === "true"; this.link.setAttribute("data-underline", underline.toString()); } updateMode() { const mode = this.getAttribute("mode") || "light"; this.link.setAttribute("data-mode", mode); } updateTarget() { const target = this.getAttribute("target"); if (target) { this.link.target = target; } } updateFontFamily() { const fontFamily = this.getAttribute("font-family"); if (fontFamily) { this.link.style.setProperty("--courier-link-font-family", fontFamily); } else { this.link.style.removeProperty("--courier-link-font-family"); } } updateFontSize() { const fontSize = this.getAttribute("font-size"); if (fontSize) { this.link.style.setProperty("--courier-link-font-size", fontSize); } else { this.link.style.removeProperty("--courier-link-font-size"); } } } __publicField2(CourierLink, "observedAttributes", [ "href", "variant", "disabled", "color", "underline", "mode", "target", "font-family", "font-size" ]); class CourierFactoryElement extends CourierSystemThemeElement { constructor() { super(); } // Build the element with a factory function build(newElement) { if (newElement === null) { this.replaceChildren(); return; } const element = newElement ?? this.defaultElement(); this.replaceChildren(element); } // Default element to be used if no factory is provided defaultElement() { const element = document.createElement("div"); element.textContent = "Default Element Factory"; element.style.cssText = ` background-color: red; text-align: center; padding: 12px; `; return element; } } class CourierInfoState extends CourierFactoryElement { constructor(props) { super(); __publicField2(this, "_props"); __publicField2(this, "_title"); __publicField2(this, "_button"); __publicField2(this, "_style"); this._props = props; } static get id() { return "courier-info-state"; } defaultElement() { var _a; const container = document.createElement("div"); this._title = document.createElement("h2"); if ((_a = this._props.title) == null ? void 0 : _a.text) { this._title.textContent = this._props.title.text; } this._button = new CourierButton(this._props.button ?? CourierButtonVariants.secondary(this.currentSystemTheme)); this._style = document.createElement("style"); this._style.textContent = this.getStyles(this._props); container.className = "container"; container.appendChild(this._style); container.appendChild(this._title); container.appendChild(this._button); this.appendChild(container); return container; } onSystemThemeChange(_) { this.updateStyles(this._props); } getStyles(props) { var _a, _b, _c, _d; return ` :host { display: flex; align-items: center; justify-content: center; height: 100%; width: 100%; } .container { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 16px; text-align: center; padding: 24px; box-sizing: border-box; height: 100%; } .container h2 { margin: 0; color: ${((_a = props.title) == null ? void 0 : _a.textColor) ?? "red"}; font-size: ${((_b = props.title) == null ? void 0 : _b.fontSize) ?? "16px"}; font-weight: ${((_c = props.title) == null ? void 0 : _c.fontWeight) ?? "500"}; font-family: ${((_d = props.title) == null ? void 0 : _d.fontFamily) ?? "inherit"}; } `; } updateStyles(props) { this._props = props; if (this._style) { this._style.textContent = this.getStyles(props); } if (this._button) { this._button.updateButton(props.button); } } } class CourierIconButton extends CourierBaseElement { constructor(svg, color, backgroundColor, hoverBackgroundColor, activeBackgroundColor, borderRadius, height, width) { super(); __publicField2(this, "_backgroundColor"); __publicField2(this, "_hoverBackgroundColor"); __publicField2(this, "_activeBackgroundColor"); __publicField2(this, "_borderRadius"); __publicField2(this, "_height"); __publicField2(this, "_width"); __publicField2(this, "_style"); __publicField2(this, "_button"); __publicField2(this, "_icon"); this._borderRadius = borderRadius; this._backgroundColor = backgroundColor; this._hoverBackgroundColor = hoverBackgroundColor; this._activeBackgroundColor = activeBackgroundColor; this._height = height; this._width = width; const shadow = this.attachShadow({ mode: "open" }); this._button = document.createElement("button"); this._button.setAttribute("part", "button"); this._icon = new CourierIcon(color, svg); this._style = document.createElement("style"); this.refresh(); shadow.appendChild(this._style); this._button.appendChild(this._icon); shadow.appendChild(this._button); } static get id() { return "courier-icon-button"; } refresh() { this._style.textContent = this.getStyles(); } getStyles() { return ` :host { display: inline-block; border-radius: ${this._borderRadius ?? "50%"}; } button { border: none; border-radius: ${this._borderRadius ?? "50%"}; cursor: pointer; width: ${this._width ?? "36px"}; height: ${this._height ?? "36px"}; display: flex; align-items: center; justify-content: center; background: ${this._backgroundColor ?? "transparent"}; transition: background-color 0.2s ease; touch-action: manipulation; } button:hover { background-color: ${this._hoverBackgroundColor ?? "red"}; } button:active { background-color: ${this._activeBackgroundColor ?? "red"}; } button:disabled { opacity: 0.6; cursor: not-allowed; } [part="icon"] { display: flex; align-items: center; justify-content: center; width: 24px; height: 24px; } `; } updateIconColor(color) { this._icon.updateColor(color); } updateIconSVG(svg) { this._icon.updateSVG(svg); } updateBackgroundColor(color) { this._backgroundColor = color; this.refresh(); } updateHoverBackgroundColor(color) { this._hoverBackgroundColor = color; this.refresh(); } updateActiveBackgroundColor(color) { this._activeBackgroundColor = color; this.refresh(); } } function registerElement(element) { if (typeof window !== "undefined" && !customElements.get(element.id)) { customElements.define(element.id, element); } } function injectGlobalStyle(styleId, styles) { const selector = `style[data-${styleId}]`; const existingStyle = document.querySelector(selector); if (!existingStyle) { const style = document.createElement("style"); style.setAttribute(`data-${styleId}`, ""); style.textContent = styles; document.head.appendChild(style); return style; } return existingStyle; } registerElement(CourierButton); registerElement(CourierIcon); registerElement(CourierLink); registerElement(CourierInfoState); registerElement(CourierIconButton); registerElement(CourierSystemThemeElement); function copyMessage(message) { const copy = { ...message }; if (message.actions) { copy.actions = message.actions.map((action) => copyInboxAction(action)); } if (message.data) { copy.data = JSON.parse(JSON.stringify(message.data)); } if (message.tags) { copy.tags = [...message.tags]; } if (message.trackingIds) { copy.trackingIds = { ...message.trackingIds }; } return copy; } function copyInboxAction(action) { const copy = { ...action }; if (action.data) { copy.data = JSON.parse(JSON.stringify(action.data)); } return copy; } function copyInboxDataSet(dataSet) { if (!dataSet) { return void 0; } return { ...dataSet, messages: dataSet.messages.map((message) => copyMessage(message)) }; } function getMessageTime(message) { if (!message.created) return "Now"; const now = /* @__PURE__ */ new Date(); const messageDate = new Date(message.created); const diffInSeconds = Math.floor((now.getTime() - messageDate.getTime()) / 1e3); if (diffInSeconds < 5) return "Now"; if (diffInSeconds < 60) return `${diffInSeconds}s`; if (diffInSeconds < 3600) return `${Math.floor(diffInSeconds / 60)}m`; if (diffInSeconds < 86400) return `${Math.floor(diffInSeconds / 3600)}h`; if (diffInSeconds < 604800) return `${Math.floor(diffInSeconds / 86400)}d`; if (diffInSeconds < 31536e3) return `${Math.floor(diffInSeconds / 604800)}w`; return `${Math.floor(diffInSeconds / 31536e3)}y`; } class CourierInboxListItemMenu extends CourierBaseElement { constructor(theme2) { super(); // State __publicField(this, "_theme"); __publicField(this, "_options", []); this._theme = theme2; } static get id() { return "courier-inbox-list-item-menu"; } onComponentMounted() { const menu = document.createElement("ul"); menu.className = "menu"; this.appendChild(menu); } static getStyles(theme2) { var _a, _b, _c; const menu = (_c = (_b = (_a = theme2.inbox) == null ? void 0 : _a.list) == null ? void 0 : _b.item) == null ? void 0 : _c.menu; return ` ${CourierInboxListItemMenu.id} { display: none; position: absolute; background: ${(menu == null ? void 0 : menu.backgroundColor) ?? "red"}; border: ${(menu == null ? void 0 : menu.border) ?? "1px solid red"}; border-radius: ${(menu == null ? void 0 : menu.borderRadius) ?? "0px"}; box-shadow: ${(menu == null ? void 0 : menu.shadow) ?? "0 2px 8px red"}; user-select: none; opacity: 0; pointer-events: none; transition: opacity 0.15s; overflow: hidden; } ${CourierInboxListItemMenu.id}.visible { display: block; opacity: 1; pointer-events: auto; } ${CourierInboxListItemMenu.id} ul.menu { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: row; } ${CourierInboxListItemMenu.id} li.menu-item { display: flex; align-items: center; justify-content: center; cursor: pointer; border-bottom: none; background: transparent; } `; } setOptions(options) { this._options = options; this.renderMenu(); } renderMenu() { var _a, _b, _c; const menu = this.querySelector("ul.menu"); if (!menu) return; menu.innerHTML = ""; const menuTheme = (_c = (_b = (_a = this._theme.inbox) == null ? void 0 : _a.list) == null ? void 0 : _b.item) == null ? void 0 : _c.menu; const cancelEvent = (e) => { e.stopPropagation(); e.preventDefault(); }; this._options.forEach((opt) => { var _a2, _b2, _c2; const icon = new CourierIconButton(opt.icon.svg, opt.icon.color, menuTheme == null ? void 0 : menuTheme.backgroundColor, (_a2 = menuTheme == null ? void 0 : menuTheme.item) == null ? void 0 : _a2.hoverBackgroundColor, (_b2 = menuTheme == null ? void 0 : menuTheme.item) == null ? void 0 : _b2.activeBackgroundColor, (_c2 = menuTheme == null ? void 0 : menuTheme.item) == null ? void 0 : _c2.borderRadius); const handleInteraction = (e) => { cancelEvent(e); opt.onClick(); }; icon.addEventListener("click", handleInteraction); icon.addEventListener("touchstart", cancelEvent); icon.addEventListener("touchend", handleInteraction); icon.addEventListener("touchmove", cancelEvent); icon.addEventListener("mousedown", cancelEvent); icon.addEventListener("mouseup", cancelEvent); menu.appendChild(icon); }); } show() { this.style.display = "block"; this.classList.add("visible"); } hide() { this.style.display = "none"; this.classList.remove("visible"); } } registerElement(CourierInboxListItemMenu); const _CourierInboxDatastore = class _CourierInboxDatastore { constructor() { __publicField(this, "_inboxDataSet"); __publicField(this, "_archiveDataSet"); __publicField(this, "_dataStoreListeners", []); __publicField(this, "_unreadCount"); __publicField(this, "isPaginatingInbox", false); __publicField(this, "isPaginatingArchive", false); } static get shared() { if (!_CourierInboxDatastore.instance) { _CourierInboxDatastore.instance = new _CourierInboxDatastore(); } return _CourierInboxDatastore.instance; } get unreadCount() { return this._unreadCount ?? 0; } get inboxDataSet() { return this._inboxDataSet ?? { feedType: "inbox", messages: [], canPaginate: false, paginationCursor: null }; } get archiveDataSet() { return this._archiveDataSet ?? { feedType: "archive", messages: [], canPaginate: false, paginationCursor: null }; } addDataStoreListener(listener) { this._dataStoreListeners.push(listener); } removeDataStoreListener(listener) { this._dataStoreListeners = this._dataStoreListeners.filter((l) => l !== listener); } async fetchCachableDataSet(props) { var _a, _b, _c, _d, _e, _f, _g, _h; if (props.canUseCache) { if (props.feedType === "inbox" && this._inboxDataSet) { return this._inboxDataSet; } if (props.feedType === "archive" && this._archiveDataSet) { return this._archiveDataSet; } } const response = await props.fetch; return { feedType: props.feedType, messages: ((_b = (_a = response.data) == null ? void 0 : _a.messages) == null ? void 0 : _b.nodes) ?? [], canPaginate: ((_e = (_d = (_c = response.data) == null ? void 0 : _c.messages) == null ? void 0 : _d.pageInfo) == null ? void 0 : _e.hasNextPage) ?? false, paginationCursor: ((_h = (_g = (_f = response.data) == null ? void 0 : _f.messages) == null ? void 0 : _g.pageInfo) == null ? void 0 : _h.startCursor) ?? null }; } async fetchUnreadCount(props) { var _a; if (props.canUseCache && this._unreadCount !== void 0) { return this._unreadCount; } const unreadCount = await ((_a = Courier.shared.client) == null ? void 0 : _a.inbox.getUnreadMessageCount()); return unreadCount ?? 0; } async load(props) { var _a, _b; try { const client = Courier.shared.client; if (!(client == null ? void 0 : client.options.userId)) { throw new Error("User is not signed in"); } const properties = props ?? { canUseCache: true }; const [inboxDataSet, archiveDataSet, unreadCount] = await Promise.all([ this.fetchCachableDataSet({ fetch: client.inbox.getMessages(), feedType: "inbox", canUseCache: properties.canUseCache }), this.fetchCachableDataSet({ fetch: client.inbox.getArchivedMessages(), feedType: "archive", canUseCache: properties.canUseCache }), this.fetchUnreadCount(properties) ]); this._inboxDataSet = inboxDataSet; this._archiveDataSet = archiveDataSet; this._unreadCount = unreadCount; this._dataStoreListeners.forEach((listener) => { var _a2, _b2, _c, _d, _e, _f; if (this._inboxDataSet) { (_b2 = (_a2 = listener.events).onDataSetChange) == null ? void 0 : _b2.call(_a2, this._inboxDataSet, "inbox"); } if (this._archiveDataSet) { (_d = (_c = listener.events).onDataSetChange) == null ? void 0 : _d.call(_c, this._archiveDataSet, "archive"); } (_f = (_e = listener.events).onUnreadCountChange) == null ? void 0 : _f.call(_e, this._unreadCount ?? 0); }); } catch (error) { (_b = (_a = Courier.shared.client) == null ? void 0 : _a.options.logger) == null ? void 0 : _b.error("Error loading inbox:", error); this._dataStoreListeners.forEach((listener) => { var _a2, _b2; (_b2 = (_a2 = listener.events).onError) == null ? void 0 : _b2.call(_a2, error); }); } } // Connect the socket async listenForUpdates() { var _a, _b; try { await this.connectSocket(); } catch (error) { (_b = (_a = Courier.shared.client) == null ? void 0 : _a.options.logger) == null ? void 0 : _b.error("Error listening for updates:", error); this._dataStoreListeners.forEach((listener) => { var _a2, _b2; (_b2 = (_a2 = listener.events).onError) == null ? void 0 : _b2.call(_a2, error); }); } } async connectSocket() { var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k; const socket = (_a = Courier.shared.client) == null ? void 0 : _a.inbox.socket; try { if (!socket) { (_c = (_b = Courier.shared.client) == null ? void 0 : _b.options.logger) == null ? void 0 : _c.info("CourierInbox socket not available"); return; } if (socket.isConnecting || socket.isOpen) { (_f = (_d = Courier.shared.client) == null ? void 0 : _d.options.logger) == null ? void 0 : _f.info(`Inbox socket already connecting or open for client ID: [${(_e = Courier.shared.client) == null ? void 0 : _e.options.connectionId}]`); return; } socket.addMessageEventListener((event) => { if (event.event === InboxMessageEvent.NewMessage) { const message2 = event.data; this.addMessage(message2, 0, "inbox"); return; } const message = this.getMessage({ messageId: event.messageId }); switch (event.event) { case InboxMessageEvent.MarkAllRead: this.readAllMessages({ canCallApi: false }); break; case InboxMessageEvent.Read: if (message) { this.readMessage({ message, canCallApi: false }); } break; case InboxMessageEvent.Unread: if (message) { this.unreadMessage({ message, canCallApi: false }); } break; case InboxMessageEvent.Opened: if (message) { this.openMessage({ message, canCallApi: false }); } break; case InboxMessageEvent.Archive: if (message) { this.archiveMessage({ message, canCallApi: false }); } break; case InboxMessageEvent.ArchiveRead: this.archiveReadMessages({ canCallApi: false }); break; case InboxMessageEvent.ArchiveAll: this.archiveAllMessages({ canCallApi: false }); break; case InboxMessageEvent.Clicked: if (message) { this.clickMessage({ message, canCallApi: false }); } break; case InboxMessageEvent.Unarchive: if (message) { this.unarchiveMessage({ message, canCallApi: false }); } break; case InboxMessageEvent.Unopened: break; } }); await socket.connect(); (_i = (_g = Courier.shared.client) == null ? void 0 : _g.options.logger) == null ? void 0 : _i.info(`Inbox socket connected for client ID: [${(_h = Courier.shared.client) == null ? void 0 : _h.options.connectionId}]`); } catch (error) { (_k = (_j = Courier.shared.client) == null ? void 0 : _j.options.logger) == null ? void 0 : _k.error("Failed to connect socket:", error); } } /** * Get a message by messageId from the inbox or archive data set * @param props - The message ID * @returns The message or undefined if it is not found */ getMessage(props) { var _a, _b; if (!props.messageId) { return void 0; } return ((_a = this._inboxDataSet) == null ? void 0 : _a.messages.find((m) => m.messageId === props.messageId)) ?? ((_b = this._archiveDataSet) == null ? void 0 : _b.messages.find((m) => m.messageId === props.messageId)); } /** * Fetch the next page of messages * @param props - The feed type * @returns The next page of messages or null if there is no next page */ async fetchNextPageOfMessages(props) { var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x; switch (props.feedType) { case "inbox": if (this.isPaginatingInbox) { return null; } if (((_a = this._inboxDataSet) == null ? void 0 : _a.canPaginate) && this._inboxDataSet.paginationCursor) { try { this.isPaginatingInbox = true; const response = await ((_b = Courier.shared.client) == null ? void 0 : _b.inbox.getMessages({ paginationLimit: Courier.shared.paginationLimit, startCursor: this._inboxDataSet.paginationCursor })); const dataSet = { feedType: "inbox", messages: ((_d = (_c = response == null ? void 0 : response.data) == null ? void 0 : _c.messages) == null ? void 0 : _d.nodes) ?? [], canPaginate: ((_g = (_f = (_e = response == null ? void 0 : response.data) == null ? void 0 : _e.messages) == null ? void 0 : _f.pageInfo) == null ? void 0 : _g.hasNextPage) ?? false, paginationCursor: ((_j = (_i = (_h = response == null ? void 0 : response.data) == null ? void 0 : _h.messages) == null ? void 0 : _i.pageInfo) == null ? void 0 : _j.startCursor) ?? null }; this.addPage(dataSet); return dataSet; } catch (error) { (_l = (_k = Courier.shared.client) == null ? void 0 : _k.options.logger) == null ? void 0 : _l.error("Error fetching next page of inbox messages:", error); return null; } finally { this.isPaginatingInbox = false; } } break; case "archive": if (this.isPaginatingArchive) { return null; } if (((_m = this._archiveDataSet) == null ? void 0 : _m.canPaginate) && this._archiveDataSet.paginationCursor) { try { this.isPaginatingArchive = true; const response = await ((_n = Courier.shared.client) == null ? void 0 : _n.inbox.getArchivedMessages({ paginationLimit: Courier.shared.paginationLimit, startCursor: this._archiveDataSet.paginationCursor })); const dataSet = { feedType: "archive", messages: ((_p = (_o = response == null ? void 0 : response.data) == null ? void 0 : _o.messages) == null ? void 0 : _p.nodes) ?? [], canPaginate: ((_s = (_r = (_q = response == null ? void 0 : response.data) == null ? void 0 : _q.messages) == null ? void 0 : _r.pageInfo) == null ? void 0 : _s.hasNextPage) ?? false, paginationCursor: ((_v = (_u = (_t = response == null ? void 0 : response.data) == null ? void 0 : _t.messages) == null ? void 0 : _u.pageInfo) == null ? void 0 : _v.startCursor) ?? null }; this.addPage(dataSet); return dataSet; } catch (error) { (_x = (_w = Courier.shared.client) == null ? void 0 : _w.options.logger) == null ? void 0 : _x.error("Error fetching next page of archived messages:", error); return null; } finally { this.isPaginatingArchive = false; } } break; } return null; } /** * Check if the datastore is loaded and ready to perform mutations * @returns True if the datastore is loaded and ready to perform mutations, false otherwise */ canMutate() { return !!(Courier.shared.client && this._inboxDataSet && this._archiveDataSet); } async readMessage({ message, canCallApi = true }) { var _a, _b, _c; if (!this.canMutate()) { return; } const datastoreSnapshot = this.getDatastoreSnapshot(this.unreadCount, this._inboxDataSet, this._archiveDataSet); const snapshot = this.getMessageSnapshot(message); if (snapshot.message.read) { return; } try { snapshot.message.read = (/* @__PURE__ */ new Date()).toISOString(); this.applyMessageSnapshot(snapshot); this._unreadCount = datastoreSnapshot.unreadCount - 1; this._dataStoreListeners.forEach((listener) => { var _a2, _b2; (_b2 = (_a2 = listener.events).onUnreadCountChange) == null ? void 0 : _b2.call(_a2, this._unreadCount); }); if (canCallApi) { await ((_a = Courier.shared.client) == null ? void 0 : _a.inbox.read({ messageId: message.messageId })); } } catch (error) { (_c = (_b = Courier.shared.client) == null ? void 0 : _b.options.logger) == null ? void 0 : _c.error("Error reading message:", error); this.applyDatastoreSnapshot(datastoreSnapshot); } } async unreadMessage({ message, canCallApi = true }) { var _a, _b, _c; if (!this.canMutate()) { return; } const datastoreSnapshot = this.getDatastoreSnapshot(this.unreadCount, this._inboxDataSet, this._archiveDataSet); const snapshot = this.getMessageSnapshot(message); if (!snapshot.message.read) { return; } try { snapshot.message.read = void 0; this.applyMessageSnapshot(snapshot); this._unreadCount = datastoreSnapshot.unreadCount + 1; this._dataStoreListeners.forEach((listener) => { var _a2, _b2; (_b2 = (_a2 = listener.events).onUnreadCountChange) == null ? void 0 : _b2.call(_a2, this._unreadCount); }); if (canCallApi) { await ((_a = Courier.shared.client) == null ? void 0 : _a.inbox.unread({ messageId: message.messageId })); } } catch (error) { (_c = (_b = Courier.shared.client) == null ? void 0 : _b.options.logger) == null ? void 0 : _c.error("Error unreading message:", error); this.applyDatastoreSnapshot(datastoreSnapshot); } } async openMessage({ message, canCallApi = true }) { var _a, _b, _c; if (!this.canMutate()) { return; } const datastoreSnapshot = this.getDatastoreSnapshot(this.unreadCount, this._inboxDataSet, this._archiveDataSet); const snapshot = this.getMessageSnapshot(message); if (snapshot.inboxIndex === void 0 && snapshot.archiveIndex === void 0) { return; } if (snapshot.message.opened) { return; } try { snapshot.message.opened = (/* @__PURE__ */ new Date()).toISOString(); this.applyMessageSnapshot(snapshot); if (canCallApi) { await ((_a = Courier.shared.client) == null ? void 0 : _a.inbox.open({ messageId: message.messageId })); } } catch (error) { (_c = (_b = Courier.shared.client) == null ? void 0 : _b.options.logger) == null ? void 0 : _c.error("Error opening message:", error); this.applyDatastoreSnapshot(datastoreSnapshot); } } async clickMessage({ message, canCallApi = true }) { var _a, _b, _c, _d, _e; if (!this.canMutate()) { return; } try { if (((_a = message.trackingIds) == null ? void 0 : _a.clickTrackingId) && canCallApi) { await ((_c = Courier.shared.client) == null ? void 0 : _c.inbox.click({ messageId: message.messageId, trackingId: (_b = message.trackingIds) == null ? void 0 : _b.clickTrackingId })); } } catch (error) { (_e = (_d = Courier.shared.client) == null ? void 0 : _d.options.logger) == null ? void 0 : _e.error("Error clicking message:", error); } } async archiveMessage({ message, canCallApi = true }) { var _a, _b, _c, _d; if (!this.canMutate()) { return; } const messageSnapshot = this.getMessageSnapshot(message); if (messageSnapshot.inboxIndex === void 0) { return; } const datastoreSnapshot = this.getDatastoreSnapshot(this.unreadCount, this._inboxDataSet, this._archiveDataSet); try { message.archived = (/* @__PURE__ */ new Date()).toISOString(); this.removeMessage(message, messageSnapshot.inboxIndex, "inbox"); if ((_a = this._archiveDataSet) == null ? void 0 : _a.messages) { const insertIndex = this.findInsertIndex(message, this._archiveDataSet); this.addMessage(message, insertIndex, "archive"); } if (canCallApi) { await ((_b = Courier.shared.client) == null ? void 0 : _b.inbox.archive({ messageId: message.messageId })); } } catch (error) { (_d = (_c = Courier.shared.client) == null ? void 0 : _c.options.logger) == null ? void 0 : _d.error("Error archiving message:", error); this.applyDatastoreSnapshot(datastoreSnapshot); } } async unarchiveMessage({ message, canCallApi = true }) { var _a, _b, _c, _d; if (!this.canMutate()) { return; } const datastoreSnapshot = this.getDatastoreSnapshot(this.unreadCount, this._inboxDataSet, this._archiveDataSet); const messageSnapshot = this.getMessageSnapshot(message); if (messageSnapshot.archiveIndex === void 0) { return; } try { messageSnapshot.message.archived = void 0; this.removeMessage(message, messageSnapshot.archiveIndex, "archive"); if ((_a = this._inboxDataSet) == null ? void 0 : _a.messages) { const insertIndex = this.findInsertIndex(message, this._inboxDataSet); this.addMessage(message, insertIndex, "inbox"); } if (canCallApi) { await ((_b = Courier.shared.client) == null ? void 0 : _b.inbox.unarchive({ messageId: message.messageId })); } } catch (error) { (_d = (_c = Courier.shared.client) == null ? void 0 : _c.options.logger) == null ? void 0 : _d.error("Error unarchiving message:", error); th