@trycourier/courier-react-components 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,8 @@
1
+ # `courier-react-components`
2
+
3
+ > Adding Courier to a React app? Check out [`courier-react`](../courier-react/).
4
+ >
5
+ > Adding Courier to a React 17 app? Check out [`courier-react-17`](../courier-react-17/).
6
+
7
+ This package contains React version agnostic components for Courier. `courier-react`
8
+ uses the components here and provides a React version-specific render method.
@@ -0,0 +1,6 @@
1
+ import { default as React } from '../../../../node_modules/react';
2
+ interface CourierClientProps {
3
+ children: React.ReactNode;
4
+ }
5
+ export declare const CourierClientComponent: React.FC<CourierClientProps>;
6
+ export {};
@@ -0,0 +1,34 @@
1
+ import { ReactNode } from '../../../../node_modules/react';
2
+ import { CourierInboxListItemActionFactoryProps, CourierInboxListItemFactoryProps, CourierInboxTheme, CourierInbox as CourierInboxElement, CourierInboxHeaderFactoryProps, CourierInboxStateEmptyFactoryProps, CourierInboxStateLoadingFactoryProps, CourierInboxStateErrorFactoryProps, CourierInboxPaginationItemFactoryProps, CourierInboxFeedType } from '@trycourier/courier-ui-inbox';
3
+ import { CourierComponentThemeMode } from '@trycourier/courier-ui-core';
4
+ export interface CourierInboxProps {
5
+ /** Height of the inbox container. Defaults to "auto" and will resize itself based on it's children. */
6
+ height?: string;
7
+ /** Theme object for light mode */
8
+ lightTheme?: CourierInboxTheme;
9
+ /** Theme object for dark mode */
10
+ darkTheme?: CourierInboxTheme;
11
+ /** Theme mode: "light", "dark", or "system". Defaults to "system" */
12
+ mode?: CourierComponentThemeMode;
13
+ /** Type of feed to display in the inbox ("inbox" or "archive"). Defaults to "inbox" */
14
+ feedType?: CourierInboxFeedType;
15
+ /** Callback fired when a message is clicked. */
16
+ onMessageClick?: (props: CourierInboxListItemFactoryProps) => void;
17
+ /** Callback fired when a message action (e.g., button) is clicked. */
18
+ onMessageActionClick?: (props: CourierInboxListItemActionFactoryProps) => void;
19
+ /** Callback fired when a message is long-pressed (for mobile/gesture support). Only works on devices that support touch. */
20
+ onMessageLongPress?: (props: CourierInboxListItemFactoryProps) => void;
21
+ /** Allows you to pass a custom component as the header. */
22
+ renderHeader?: (props: CourierInboxHeaderFactoryProps | undefined | null) => ReactNode;
23
+ /** Allows you to pass a custom component as the list item. */
24
+ renderListItem?: (props: CourierInboxListItemFactoryProps | undefined | null) => ReactNode;
25
+ /** Allows you to pass a custom component as the empty state. */
26
+ renderEmptyState?: (props: CourierInboxStateEmptyFactoryProps | undefined | null) => ReactNode;
27
+ /** Allows you to pass a custom component as the loading state. */
28
+ renderLoadingState?: (props: CourierInboxStateLoadingFactoryProps | undefined | null) => ReactNode;
29
+ /** Allows you to pass a custom component as the error state. */
30
+ renderErrorState?: (props: CourierInboxStateErrorFactoryProps | undefined | null) => ReactNode;
31
+ /** Allows you to pass a custom component as the pagination list item. */
32
+ renderPaginationItem?: (props: CourierInboxPaginationItemFactoryProps | undefined | null) => ReactNode;
33
+ }
34
+ export declare const CourierInboxComponent: import('../../../../node_modules/react').ForwardRefExoticComponent<CourierInboxProps & import('../../../../node_modules/react').RefAttributes<CourierInboxElement>>;
@@ -0,0 +1,48 @@
1
+ import { ReactNode } from '../../../../node_modules/react';
2
+ import { CourierInboxFeedType, CourierInboxHeaderFactoryProps, CourierInboxListItemActionFactoryProps, CourierInboxListItemFactoryProps, CourierInboxMenuButtonFactoryProps, CourierInboxPopupMenu as CourierInboxPopupMenuElement, CourierInboxPaginationItemFactoryProps, CourierInboxPopupAlignment, CourierInboxStateEmptyFactoryProps, CourierInboxStateErrorFactoryProps, CourierInboxStateLoadingFactoryProps, CourierInboxTheme } from '@trycourier/courier-ui-inbox';
3
+ import { CourierComponentThemeMode } from '@trycourier/courier-ui-core';
4
+ export interface CourierInboxPopupMenuProps {
5
+ /** Alignment of the popup menu: 'top-right', 'top-left', 'top-center', 'bottom-right', 'bottom-left', 'bottom-center', 'center-right', 'center-left', 'center-center'. */
6
+ popupAlignment?: CourierInboxPopupAlignment;
7
+ /** Width of the popup menu container. */
8
+ popupWidth?: string;
9
+ /** Height of the popup menu container. */
10
+ popupHeight?: string;
11
+ /** CSS left position for the popup menu. */
12
+ left?: string;
13
+ /** CSS top position for the popup menu. */
14
+ top?: string;
15
+ /** CSS right position for the popup menu. */
16
+ right?: string;
17
+ /** CSS bottom position for the popup menu. */
18
+ bottom?: string;
19
+ /** Theme object for light mode. */
20
+ lightTheme?: CourierInboxTheme;
21
+ /** Theme object for dark mode. */
22
+ darkTheme?: CourierInboxTheme;
23
+ /** Theme mode: 'light', 'dark', or 'system'. */
24
+ mode?: CourierComponentThemeMode;
25
+ /** Type of feed to display in the popup menu ('inbox' or 'archive'). */
26
+ feedType?: CourierInboxFeedType;
27
+ /** Callback fired when a message is clicked. */
28
+ onMessageClick?: (props: CourierInboxListItemFactoryProps) => void;
29
+ /** Callback fired when a message action (e.g., button) is clicked. */
30
+ onMessageActionClick?: (props: CourierInboxListItemActionFactoryProps) => void;
31
+ /** Callback fired when a message is long-pressed (for mobile/gesture support). */
32
+ onMessageLongPress?: (props: CourierInboxListItemFactoryProps) => void;
33
+ /** Allows you to pass a custom component as the header. */
34
+ renderHeader?: (props: CourierInboxHeaderFactoryProps | undefined | null) => ReactNode;
35
+ /** Allows you to pass a custom component as the list item. */
36
+ renderListItem?: (props: CourierInboxListItemFactoryProps | undefined | null) => ReactNode;
37
+ /** Allows you to pass a custom component as the empty state. */
38
+ renderEmptyState?: (props: CourierInboxStateEmptyFactoryProps | undefined | null) => ReactNode;
39
+ /** Allows you to pass a custom component as the loading state. */
40
+ renderLoadingState?: (props: CourierInboxStateLoadingFactoryProps | undefined | null) => ReactNode;
41
+ /** Allows you to pass a custom component as the error state. */
42
+ renderErrorState?: (props: CourierInboxStateErrorFactoryProps | undefined | null) => ReactNode;
43
+ /** Allows you to pass a custom component as the pagination list item. */
44
+ renderPaginationItem?: (props: CourierInboxPaginationItemFactoryProps | undefined | null) => ReactNode;
45
+ /** Allows you to pass a custom component as the menu button. */
46
+ renderMenuButton?: (props: CourierInboxMenuButtonFactoryProps | undefined | null) => ReactNode;
47
+ }
48
+ export declare const CourierInboxPopupMenuComponent: import('../../../../node_modules/react').ForwardRefExoticComponent<CourierInboxPopupMenuProps & import('../../../../node_modules/react').RefAttributes<CourierInboxPopupMenuElement>>;
@@ -0,0 +1,34 @@
1
+ import { Courier, CourierProps, InboxMessage } from '@trycourier/courier-js';
2
+ import { CourierInboxFeedType, InboxDataSet } from '@trycourier/courier-ui-inbox';
3
+ type AuthenticationHooks = {
4
+ userId?: string;
5
+ signIn: (props: CourierProps) => void;
6
+ signOut: () => void;
7
+ };
8
+ type InboxHooks = {
9
+ load: (props?: {
10
+ feedType: CourierInboxFeedType;
11
+ canUseCache: boolean;
12
+ }) => Promise<void>;
13
+ fetchNextPageOfMessages: (props: {
14
+ feedType: CourierInboxFeedType;
15
+ }) => Promise<InboxDataSet | null>;
16
+ setPaginationLimit: (limit: number) => void;
17
+ readMessage: (message: InboxMessage) => Promise<void>;
18
+ unreadMessage: (message: InboxMessage) => Promise<void>;
19
+ clickMessage: (message: InboxMessage) => Promise<void>;
20
+ archiveMessage: (message: InboxMessage) => Promise<void>;
21
+ openMessage: (message: InboxMessage) => Promise<void>;
22
+ unarchiveMessage: (message: InboxMessage) => Promise<void>;
23
+ readAllMessages: () => Promise<void>;
24
+ inbox?: InboxDataSet;
25
+ archive?: InboxDataSet;
26
+ unreadCount?: number;
27
+ error?: Error;
28
+ };
29
+ export declare const useCourier: () => {
30
+ shared: Courier;
31
+ auth: AuthenticationHooks;
32
+ inbox: InboxHooks;
33
+ };
34
+ export {};
package/dist/index.cjs ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("@trycourier/courier-js"),r=require("@trycourier/courier-ui-inbox"),t=require("react"),n=require("react/jsx-runtime"),s=({children:e})=>{const[r,s]=t.useState(!1);return t.useEffect((()=>{s(!0)}),[]),"undefined"==typeof window?null:r?n.jsx(n.Fragment,{children:e}):null},o=t.createContext(null),a=t.forwardRef(((e,r)=>{const a=t.useContext(o);if(!a)throw new Error("RenderContext not found. Ensure CourierInbox is wrapped in a CourierRenderContext.");const i=t.useRef(null);function u(){return i.current}t.useEffect((()=>{const r=u();r&&r.onMessageClick(e.onMessageClick)}),[e.onMessageClick]),t.useEffect((()=>{const r=u();r&&r.onMessageActionClick(e.onMessageActionClick)}),[e.onMessageActionClick]),t.useEffect((()=>{const r=u();r&&r.onMessageLongPress(e.onMessageLongPress)}),[e.onMessageLongPress]),t.useEffect((()=>{const r=u();r&&e.renderHeader&&queueMicrotask((()=>{r.setHeader((r=>{const t=e.renderHeader(r);return a(t)}))}))}),[e.renderHeader]),t.useEffect((()=>{const r=u();r&&e.renderListItem&&queueMicrotask((()=>{r.setListItem((r=>{const t=e.renderListItem(r);return a(t)}))}))}),[e.renderListItem]),t.useEffect((()=>{const r=u();r&&e.renderEmptyState&&queueMicrotask((()=>{r.setEmptyState((r=>{const t=e.renderEmptyState(r);return a(t)}))}))}),[e.renderEmptyState]),t.useEffect((()=>{const r=u();r&&e.renderLoadingState&&queueMicrotask((()=>{r.setLoadingState((r=>{const t=e.renderLoadingState(r);return a(t)}))}))}),[e.renderLoadingState]),t.useEffect((()=>{const r=u();r&&e.renderErrorState&&queueMicrotask((()=>{r.setErrorState((r=>{const t=e.renderErrorState(r);return a(t)}))}))}),[e.renderErrorState]),t.useEffect((()=>{const r=u();r&&e.renderPaginationItem&&queueMicrotask((()=>{r.setPaginationItem((r=>{const t=e.renderPaginationItem(r);return a(t)}))}))}),[e.renderPaginationItem]),t.useEffect((()=>{const r=u();r&&queueMicrotask((()=>{r.setFeedType(e.feedType||"inbox")}))}),[e.feedType]);const c=n.jsx("courier-inbox",{ref:function(e){r&&("function"==typeof r?r(e):r.current=e),i.current=e},height:e.height,"light-theme":e.lightTheme?JSON.stringify(e.lightTheme):void 0,"dark-theme":e.darkTheme?JSON.stringify(e.darkTheme):void 0,mode:e.mode});return n.jsx(s,{children:c})})),i=t.forwardRef(((e,r)=>{const a=t.useContext(o);if(!a)throw new Error("RenderContext not found. Ensure CourierInboxPopupMenu is wrapped in a CourierRenderContext.");const i=t.useRef(null);function u(){return i.current}const c=t.useRef(void 0);t.useEffect((()=>{const r=u();r&&e.feedType!==c.current&&(c.current=e.feedType,queueMicrotask((()=>{var t;null==(t=r.setFeedType)||t.call(r,e.feedType??"inbox")})))}),[e.feedType]),t.useEffect((()=>{const r=u();r&&r.onMessageClick(e.onMessageClick)}),[e.onMessageClick]),t.useEffect((()=>{const r=u();r&&r.onMessageActionClick(e.onMessageActionClick)}),[e.onMessageActionClick]),t.useEffect((()=>{const r=u();r&&r.onMessageLongPress(e.onMessageLongPress)}),[e.onMessageLongPress]),t.useEffect((()=>{const r=u();r&&e.renderHeader&&queueMicrotask((()=>{r.setHeader((r=>{const t=e.renderHeader(r);return a(t)}))}))}),[e.renderHeader]),t.useEffect((()=>{const r=u();r&&e.renderListItem&&queueMicrotask((()=>{r.setListItem((r=>{const t=e.renderListItem(r);return a(t)}))}))}),[e.renderListItem]),t.useEffect((()=>{const r=u();r&&e.renderEmptyState&&queueMicrotask((()=>{r.setEmptyState((r=>{const t=e.renderEmptyState(r);return a(t)}))}))}),[e.renderEmptyState]),t.useEffect((()=>{const r=u();r&&e.renderLoadingState&&queueMicrotask((()=>{r.setLoadingState((r=>{const t=e.renderLoadingState(r);return a(t)}))}))}),[e.renderLoadingState]),t.useEffect((()=>{const r=u();r&&e.renderErrorState&&queueMicrotask((()=>{r.setErrorState((r=>{const t=e.renderErrorState(r);return a(t)}))}))}),[e.renderErrorState]),t.useEffect((()=>{const r=u();r&&e.renderPaginationItem&&queueMicrotask((()=>{r.setPaginationItem((r=>{const t=e.renderPaginationItem(r);return a(t)}))}))}),[e.renderPaginationItem]),t.useEffect((()=>{const r=u();r&&e.renderMenuButton&&queueMicrotask((()=>{r.setMenuButton((r=>{const t=e.renderMenuButton(r);return a(t)}))}))}),[e.renderMenuButton]);const d=n.jsx("courier-inbox-popup-menu",{ref:function(e){r&&("function"==typeof r?r(e):r.current=e),i.current=e},"popup-alignment":e.popupAlignment,"popup-width":e.popupWidth,"popup-height":e.popupHeight,left:e.left,top:e.top,right:e.right,bottom:e.bottom,"light-theme":e.lightTheme?JSON.stringify(e.lightTheme):void 0,"dark-theme":e.darkTheme?JSON.stringify(e.darkTheme):void 0,mode:e.mode});return n.jsx(s,{children:d})}));exports.CourierInboxComponent=a,exports.CourierInboxPopupMenuComponent=i,exports.CourierRenderContext=o,exports.useCourier=()=>{const n=r=>e.Courier.shared.signIn(r),s=()=>e.Courier.shared.signOut(),o=e=>r.CourierInboxDatastore.shared.load(e),a=e=>r.CourierInboxDatastore.shared.fetchNextPageOfMessages(e),i=r=>e.Courier.shared.paginationLimit=r,u=e=>r.CourierInboxDatastore.shared.readMessage({message:e}),c=e=>r.CourierInboxDatastore.shared.unreadMessage({message:e}),d=e=>r.CourierInboxDatastore.shared.clickMessage({message:e}),g=e=>r.CourierInboxDatastore.shared.archiveMessage({message:e}),f=e=>r.CourierInboxDatastore.shared.openMessage({message:e}),h=e=>r.CourierInboxDatastore.shared.unarchiveMessage({message:e}),M=()=>r.CourierInboxDatastore.shared.readAllMessages(),[p,m]=t.useState({userId:void 0,signIn:n,signOut:s}),[l,C]=t.useState({load:o,fetchNextPageOfMessages:a,setPaginationLimit:i,readMessage:u,unreadMessage:c,clickMessage:d,archiveMessage:g,openMessage:f,unarchiveMessage:h,readAllMessages:M});t.useEffect((()=>{const t=e.Courier.shared.addAuthenticationListener((()=>x())),n=new r.CourierInboxDataStoreListener({onError:e=>E(e),onDataSetChange:()=>E(),onPageAdded:()=>E(),onMessageAdd:()=>E(),onMessageRemove:()=>E(),onMessageUpdate:()=>E(),onUnreadCountChange:()=>E()});return r.CourierInboxDatastore.shared.addDataStoreListener(n),x(),E(),()=>{t.remove(),n.remove()}}),[]);const x=()=>{var r;const t=null==(r=e.Courier.shared.client)?void 0:r.options;m({userId:null==t?void 0:t.userId,signIn:n,signOut:s})},E=e=>{const t=r.CourierInboxDatastore.shared;C({load:o,fetchNextPageOfMessages:a,setPaginationLimit:i,readMessage:u,unreadMessage:c,clickMessage:d,archiveMessage:g,openMessage:f,unarchiveMessage:h,readAllMessages:M,inbox:t.inboxDataSet,archive:t.archiveDataSet,unreadCount:t.unreadCount,error:e})};return{shared:e.Courier.shared,auth:p,inbox:l}};
2
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","sources":["../src/components/courier-client-component.tsx","../src/context/render-context.ts","../src/components/courier-inbox-component.tsx","../src/components/courier-inbox-popup-menu-component.tsx","../src/hooks/use-courier.tsx"],"sourcesContent":["import React, { useState, useEffect } from 'react';\n\ninterface CourierClientProps {\n children: React.ReactNode;\n}\n\n// This class prevents issues with server side rendering react components\n// It will force the component to only render client side\n// A future update could support server side rendering if there is enough demand\nexport const CourierClientComponent: React.FC<CourierClientProps> = ({ children }) => {\n const [isMounted, setIsMounted] = useState(false);\n\n useEffect(() => {\n setIsMounted(true);\n }, []);\n\n // During SSR, render nothing or fallback\n if (typeof window === 'undefined') {\n return null;\n }\n\n if (!isMounted) {\n return null;\n }\n\n return <>{children}</>;\n};","import { createContext, ReactNode } from \"react\";\n\ntype RenderFn = (node: ReactNode) => HTMLElement;\n\n/**\n * Context providing a function to render a React component.\n *\n * Courier's React package renders as follows:\n *\n * - React engine (client application)\n * - Courier React components\n * - Courier web components\n * - [Optional] User-provided React components (ex. a list item)\n *\n * By default, React will not render the user-provided React components within Courier's\n * web components. We instead manually render the user-provided React components and inject\n * them into the Courier web components.\n *\n * Client rendering changed between React 17 and 18, so the SDKs provide React version-specific\n * rendering functions. See\n * https://18.react.dev/blog/2022/03/08/react-18-upgrade-guide#updates-to-client-rendering-apis.\n */\nexport const CourierRenderContext = createContext<RenderFn | null>(null);\n","import { useRef, useEffect, forwardRef, ReactNode, useContext } from \"react\";\nimport { CourierInboxListItemActionFactoryProps, CourierInboxListItemFactoryProps, CourierInboxTheme, CourierInbox as CourierInboxElement, CourierInboxHeaderFactoryProps, CourierInboxStateEmptyFactoryProps, CourierInboxStateLoadingFactoryProps, CourierInboxStateErrorFactoryProps, CourierInboxPaginationItemFactoryProps, CourierInboxFeedType } from \"@trycourier/courier-ui-inbox\";\nimport { CourierComponentThemeMode } from \"@trycourier/courier-ui-core\";\nimport { CourierClientComponent } from \"./courier-client-component\";\nimport { CourierRenderContext } from \"../context/render-context\";\n\nexport interface CourierInboxProps {\n /** Height of the inbox container. Defaults to \"auto\" and will resize itself based on it's children. */\n height?: string;\n\n /** Theme object for light mode */\n lightTheme?: CourierInboxTheme;\n\n /** Theme object for dark mode */\n darkTheme?: CourierInboxTheme;\n\n /** Theme mode: \"light\", \"dark\", or \"system\". Defaults to \"system\" */\n mode?: CourierComponentThemeMode;\n\n /** Type of feed to display in the inbox (\"inbox\" or \"archive\"). Defaults to \"inbox\" */\n feedType?: CourierInboxFeedType;\n\n /** Callback fired when a message is clicked. */\n onMessageClick?: (props: CourierInboxListItemFactoryProps) => void;\n\n /** Callback fired when a message action (e.g., button) is clicked. */\n onMessageActionClick?: (props: CourierInboxListItemActionFactoryProps) => void;\n\n /** Callback fired when a message is long-pressed (for mobile/gesture support). Only works on devices that support touch. */\n onMessageLongPress?: (props: CourierInboxListItemFactoryProps) => void;\n\n /** Allows you to pass a custom component as the header. */\n renderHeader?: (props: CourierInboxHeaderFactoryProps | undefined | null) => ReactNode;\n\n /** Allows you to pass a custom component as the list item. */\n renderListItem?: (props: CourierInboxListItemFactoryProps | undefined | null) => ReactNode;\n\n /** Allows you to pass a custom component as the empty state. */\n renderEmptyState?: (props: CourierInboxStateEmptyFactoryProps | undefined | null) => ReactNode;\n\n /** Allows you to pass a custom component as the loading state. */\n renderLoadingState?: (props: CourierInboxStateLoadingFactoryProps | undefined | null) => ReactNode;\n\n /** Allows you to pass a custom component as the error state. */\n renderErrorState?: (props: CourierInboxStateErrorFactoryProps | undefined | null) => ReactNode;\n\n /** Allows you to pass a custom component as the pagination list item. */\n renderPaginationItem?: (props: CourierInboxPaginationItemFactoryProps | undefined | null) => ReactNode;\n}\n\nexport const CourierInboxComponent = forwardRef<CourierInboxElement, CourierInboxProps>((props, ref) => {\n const render = useContext(CourierRenderContext);\n if (!render) {\n throw new Error(\"RenderContext not found. Ensure CourierInbox is wrapped in a CourierRenderContext.\");\n }\n\n // Element ref for use in effects, updated by handleRef.\n const inboxRef = useRef<CourierInboxElement | null>(null);\n\n // Callback ref passed to rendered component, used to propagate the DOM element's ref to the parent component.\n // We use a callback ref (rather than a React.RefObject) since we want the parent ref to be up-to-date with\n // rendered component. Updating the parent ref via useEffect does not work, since mutating a RefObject\n // does not trigger useEffect (see https://stackoverflow.com/a/60476525).\n function handleRef(el: CourierInboxElement | null) {\n if (ref) {\n\n // Propagate ref to ref callback functions\n if (typeof ref === 'function') {\n ref(el);\n } else {\n // Propagate ref to ref objects\n // @ts-ignore - RefObject.current is readonly in React 17, however it's not frozen and is equivalent the widened type MutableRefObject\n (ref as React.RefObject<CourierInboxElement | null>).current = el;\n }\n }\n\n // Store the element for use in effects\n inboxRef.current = el;\n }\n\n // Helper to get the current element\n function getEl(): CourierInboxElement | null {\n return inboxRef.current;\n }\n\n // Handle message click\n useEffect(() => {\n const inbox = getEl();\n if (!inbox) return;\n inbox.onMessageClick(props.onMessageClick);\n }, [props.onMessageClick]);\n\n // Handle message action click\n useEffect(() => {\n const inbox = getEl();\n if (!inbox) return;\n inbox.onMessageActionClick(props.onMessageActionClick);\n }, [props.onMessageActionClick]);\n\n // Handle message long press\n useEffect(() => {\n const inbox = getEl();\n if (!inbox) return;\n inbox.onMessageLongPress(props.onMessageLongPress);\n }, [props.onMessageLongPress]);\n\n // Render header\n useEffect(() => {\n const inbox = getEl();\n if (!inbox || !props.renderHeader) return;\n queueMicrotask(() => {\n inbox.setHeader((headerProps?: CourierInboxHeaderFactoryProps | undefined | null): HTMLElement => {\n const reactNode = props.renderHeader!(headerProps);\n return render(reactNode);\n });\n });\n }, [props.renderHeader]);\n\n // Render list item\n useEffect(() => {\n const inbox = getEl();\n if (!inbox || !props.renderListItem) return;\n queueMicrotask(() => {\n inbox.setListItem((itemProps?: CourierInboxListItemFactoryProps | undefined | null): HTMLElement => {\n const reactNode = props.renderListItem!(itemProps);\n return render(reactNode);\n });\n });\n }, [props.renderListItem]);\n\n // Render empty state\n useEffect(() => {\n const inbox = getEl();\n if (!inbox || !props.renderEmptyState) return;\n queueMicrotask(() => {\n inbox.setEmptyState((emptyStateProps?: CourierInboxStateEmptyFactoryProps | undefined | null): HTMLElement => {\n const reactNode = props.renderEmptyState!(emptyStateProps);\n return render(reactNode);\n });\n });\n }, [props.renderEmptyState]);\n\n // Render loading state\n useEffect(() => {\n const inbox = getEl();\n if (!inbox || !props.renderLoadingState) return;\n queueMicrotask(() => {\n inbox.setLoadingState((loadingStateProps?: CourierInboxStateLoadingFactoryProps | undefined | null): HTMLElement => {\n const reactNode = props.renderLoadingState!(loadingStateProps);\n return render(reactNode);\n });\n });\n }, [props.renderLoadingState]);\n\n // Render error state\n useEffect(() => {\n const inbox = getEl();\n if (!inbox || !props.renderErrorState) return;\n queueMicrotask(() => {\n inbox.setErrorState((errorStateProps?: CourierInboxStateErrorFactoryProps | undefined | null): HTMLElement => {\n const reactNode = props.renderErrorState!(errorStateProps);\n return render(reactNode);\n });\n });\n }, [props.renderErrorState]);\n\n // Render pagination item\n useEffect(() => {\n const inbox = getEl();\n if (!inbox || !props.renderPaginationItem) return;\n queueMicrotask(() => {\n inbox.setPaginationItem((paginationProps?: CourierInboxPaginationItemFactoryProps | undefined | null): HTMLElement => {\n const reactNode = props.renderPaginationItem!(paginationProps);\n return render(reactNode);\n });\n });\n }, [props.renderPaginationItem]);\n\n // Set feed type\n useEffect(() => {\n const inbox = getEl();\n if (!inbox) return;\n queueMicrotask(() => {\n inbox.setFeedType(props.feedType || 'inbox');\n });\n }, [props.feedType]);\n\n const children = (\n /* @ts-ignore */\n <courier-inbox\n ref={handleRef}\n height={props.height}\n light-theme={props.lightTheme ? JSON.stringify(props.lightTheme) : undefined}\n dark-theme={props.darkTheme ? JSON.stringify(props.darkTheme) : undefined}\n mode={props.mode}\n />\n );\n\n return (\n <CourierClientComponent children={children} />\n );\n});\n","import { useEffect, useRef, forwardRef, ReactNode, useContext } from 'react';\nimport {\n CourierInboxFeedType,\n CourierInboxHeaderFactoryProps,\n CourierInboxListItemActionFactoryProps,\n CourierInboxListItemFactoryProps,\n CourierInboxMenuButtonFactoryProps,\n CourierInboxPopupMenu as CourierInboxPopupMenuElement,\n CourierInboxPaginationItemFactoryProps,\n CourierInboxPopupAlignment,\n CourierInboxStateEmptyFactoryProps,\n CourierInboxStateErrorFactoryProps,\n CourierInboxStateLoadingFactoryProps,\n CourierInboxTheme,\n} from '@trycourier/courier-ui-inbox';\nimport { CourierComponentThemeMode } from '@trycourier/courier-ui-core';\nimport { CourierClientComponent } from './courier-client-component';\nimport { CourierRenderContext } from '../context/render-context';\n\nexport interface CourierInboxPopupMenuProps {\n /** Alignment of the popup menu: 'top-right', 'top-left', 'top-center', 'bottom-right', 'bottom-left', 'bottom-center', 'center-right', 'center-left', 'center-center'. */\n popupAlignment?: CourierInboxPopupAlignment;\n\n /** Width of the popup menu container. */\n popupWidth?: string;\n\n /** Height of the popup menu container. */\n popupHeight?: string;\n\n /** CSS left position for the popup menu. */\n left?: string;\n\n /** CSS top position for the popup menu. */\n top?: string;\n\n /** CSS right position for the popup menu. */\n right?: string;\n\n /** CSS bottom position for the popup menu. */\n bottom?: string;\n\n /** Theme object for light mode. */\n lightTheme?: CourierInboxTheme;\n\n /** Theme object for dark mode. */\n darkTheme?: CourierInboxTheme;\n\n /** Theme mode: 'light', 'dark', or 'system'. */\n mode?: CourierComponentThemeMode;\n\n /** Type of feed to display in the popup menu ('inbox' or 'archive'). */\n feedType?: CourierInboxFeedType;\n\n /** Callback fired when a message is clicked. */\n onMessageClick?: (props: CourierInboxListItemFactoryProps) => void;\n\n /** Callback fired when a message action (e.g., button) is clicked. */\n onMessageActionClick?: (props: CourierInboxListItemActionFactoryProps) => void;\n\n /** Callback fired when a message is long-pressed (for mobile/gesture support). */\n onMessageLongPress?: (props: CourierInboxListItemFactoryProps) => void;\n\n /** Allows you to pass a custom component as the header. */\n renderHeader?: (props: CourierInboxHeaderFactoryProps | undefined | null) => ReactNode;\n\n /** Allows you to pass a custom component as the list item. */\n renderListItem?: (props: CourierInboxListItemFactoryProps | undefined | null) => ReactNode;\n\n /** Allows you to pass a custom component as the empty state. */\n renderEmptyState?: (props: CourierInboxStateEmptyFactoryProps | undefined | null) => ReactNode;\n\n /** Allows you to pass a custom component as the loading state. */\n renderLoadingState?: (props: CourierInboxStateLoadingFactoryProps | undefined | null) => ReactNode;\n\n /** Allows you to pass a custom component as the error state. */\n renderErrorState?: (props: CourierInboxStateErrorFactoryProps | undefined | null) => ReactNode;\n\n /** Allows you to pass a custom component as the pagination list item. */\n renderPaginationItem?: (props: CourierInboxPaginationItemFactoryProps | undefined | null) => ReactNode;\n\n /** Allows you to pass a custom component as the menu button. */\n renderMenuButton?: (props: CourierInboxMenuButtonFactoryProps | undefined | null) => ReactNode;\n}\n\nexport const CourierInboxPopupMenuComponent = forwardRef<CourierInboxPopupMenuElement, CourierInboxPopupMenuProps>(\n (props, ref) => {\n const render = useContext(CourierRenderContext);\n if (!render) {\n throw new Error(\"RenderContext not found. Ensure CourierInboxPopupMenu is wrapped in a CourierRenderContext.\");\n }\n\n // Element ref for use in effects, updated by handleRef.\n const inboxRef = useRef<CourierInboxPopupMenuElement | null>(null);\n\n // Callback ref passed to rendered component, used to propagate the DOM element's ref to the parent component.\n // We use a callback ref (rather than a React.RefObject) since we want the parent ref to be up-to-date with\n // rendered component. Updating the parent ref via useEffect does not work, since mutating a RefObject\n // does not trigger useEffect (see https://stackoverflow.com/a/60476525).\n function handleRef(el: CourierInboxPopupMenuElement | null) {\n if (ref) {\n if (typeof ref === 'function') {\n ref(el);\n } else {\n // @ts-ignore - RefObject.current is readonly in React 17, however it's not frozen and is equivalent the widened type MutableRefObject\n (ref as React.RefObject<CourierInboxPopupMenuElement | null>).current = el;\n }\n }\n\n // Store the element for use in effects\n inboxRef.current = el;\n }\n\n // Helper to get the current element\n function getEl(): CourierInboxPopupMenuElement | null {\n return inboxRef.current;\n }\n\n // Use a ref to track the last set feedType to prevent duplicate state changes\n const lastFeedTypeRef = useRef<CourierInboxFeedType | undefined>(undefined);\n\n useEffect(() => {\n const menu = getEl();\n if (!menu) return;\n // Only set feedType if it has changed from the last set value\n if (props.feedType !== lastFeedTypeRef.current) {\n lastFeedTypeRef.current = props.feedType;\n queueMicrotask(() => {\n menu.setFeedType?.(props.feedType ?? 'inbox');\n });\n }\n }, [props.feedType]);\n\n // Handle message click\n useEffect(() => {\n const menu = getEl();\n if (!menu) return;\n menu.onMessageClick(props.onMessageClick);\n }, [props.onMessageClick]);\n\n // Handle message action click\n useEffect(() => {\n const menu = getEl();\n if (!menu) return;\n menu.onMessageActionClick(props.onMessageActionClick);\n }, [props.onMessageActionClick]);\n\n // Handle message long press\n useEffect(() => {\n const menu = getEl();\n if (!menu) return;\n menu.onMessageLongPress(props.onMessageLongPress);\n }, [props.onMessageLongPress]);\n\n // Render header\n useEffect(() => {\n const menu = getEl();\n if (!menu || !props.renderHeader) return;\n queueMicrotask(() => {\n menu.setHeader((headerProps?: CourierInboxHeaderFactoryProps | undefined | null): HTMLElement => {\n const reactNode = props.renderHeader!(headerProps);\n return render(reactNode);\n });\n });\n }, [props.renderHeader]);\n\n // Render list item\n useEffect(() => {\n const menu = getEl();\n if (!menu || !props.renderListItem) return;\n queueMicrotask(() => {\n menu.setListItem((itemProps?: CourierInboxListItemFactoryProps | undefined | null): HTMLElement => {\n const reactNode = props.renderListItem!(itemProps);\n return render(reactNode);\n });\n });\n }, [props.renderListItem]);\n\n // Render empty state\n useEffect(() => {\n const menu = getEl();\n if (!menu || !props.renderEmptyState) return;\n queueMicrotask(() => {\n menu.setEmptyState((emptyStateProps?: CourierInboxStateEmptyFactoryProps | undefined | null): HTMLElement => {\n const reactNode = props.renderEmptyState!(emptyStateProps);\n return render(reactNode);\n });\n });\n }, [props.renderEmptyState]);\n\n // Render loading state\n useEffect(() => {\n const menu = getEl();\n if (!menu || !props.renderLoadingState) return;\n queueMicrotask(() => {\n menu.setLoadingState((loadingStateProps?: CourierInboxStateLoadingFactoryProps | undefined | null): HTMLElement => {\n const reactNode = props.renderLoadingState!(loadingStateProps);\n return render(reactNode);\n });\n });\n }, [props.renderLoadingState]);\n\n // Render error state\n useEffect(() => {\n const menu = getEl();\n if (!menu || !props.renderErrorState) return;\n queueMicrotask(() => {\n menu.setErrorState((errorStateProps?: CourierInboxStateErrorFactoryProps | undefined | null): HTMLElement => {\n const reactNode = props.renderErrorState!(errorStateProps);\n return render(reactNode);\n });\n });\n }, [props.renderErrorState]);\n\n // Render pagination item\n useEffect(() => {\n const menu = getEl();\n if (!menu || !props.renderPaginationItem) return;\n queueMicrotask(() => {\n menu.setPaginationItem((paginationProps?: CourierInboxPaginationItemFactoryProps | undefined | null): HTMLElement => {\n const reactNode = props.renderPaginationItem!(paginationProps);\n return render(reactNode);\n });\n });\n }, [props.renderPaginationItem]);\n\n // Render menu button\n useEffect(() => {\n const menu = getEl();\n if (!menu || !props.renderMenuButton) return;\n queueMicrotask(() => {\n menu.setMenuButton((buttonProps?: CourierInboxMenuButtonFactoryProps | undefined | null): HTMLElement => {\n const reactNode = props.renderMenuButton!(buttonProps);\n return render(reactNode);\n });\n });\n }, [props.renderMenuButton]);\n\n const children = (\n /* @ts-ignore */\n <courier-inbox-popup-menu\n ref={handleRef}\n popup-alignment={props.popupAlignment}\n popup-width={props.popupWidth}\n popup-height={props.popupHeight}\n left={props.left}\n top={props.top}\n right={props.right}\n bottom={props.bottom}\n light-theme={props.lightTheme ? JSON.stringify(props.lightTheme) : undefined}\n dark-theme={props.darkTheme ? JSON.stringify(props.darkTheme) : undefined}\n mode={props.mode}\n />\n );\n\n return (\n <CourierClientComponent children={children} />\n );\n }\n);\n","import React from 'react';\nimport { Courier, CourierProps, InboxMessage } from '@trycourier/courier-js';\nimport { CourierInboxDatastore, CourierInboxDataStoreListener, CourierInboxFeedType, InboxDataSet } from '@trycourier/courier-ui-inbox';\n\ntype AuthenticationHooks = {\n userId?: string,\n signIn: (props: CourierProps) => void,\n signOut: () => void\n}\n\ntype InboxHooks = {\n load: (props?: { feedType: CourierInboxFeedType, canUseCache: boolean }) => Promise<void>,\n fetchNextPageOfMessages: (props: { feedType: CourierInboxFeedType }) => Promise<InboxDataSet | null>,\n setPaginationLimit: (limit: number) => void,\n readMessage: (message: InboxMessage) => Promise<void>,\n unreadMessage: (message: InboxMessage) => Promise<void>,\n clickMessage: (message: InboxMessage) => Promise<void>,\n archiveMessage: (message: InboxMessage) => Promise<void>,\n openMessage: (message: InboxMessage) => Promise<void>,\n unarchiveMessage: (message: InboxMessage) => Promise<void>,\n readAllMessages: () => Promise<void>,\n inbox?: InboxDataSet,\n archive?: InboxDataSet,\n unreadCount?: number,\n error?: Error\n}\n\n// A hook for managing the shared state of Courier\n// If you want to use more functions, checkout the Courier JS SDK which\n// can be used directly by importing from '@trycourier/courier-js'\nexport const useCourier = () => {\n\n // Authentication Functions\n const signIn = (props: CourierProps) => Courier.shared.signIn(props);\n const signOut = () => Courier.shared.signOut();\n\n // Inbox Functions\n const loadInbox = (props?: { feedType: CourierInboxFeedType, canUseCache: boolean }) => CourierInboxDatastore.shared.load(props);\n const fetchNextPageOfMessages = (props: { feedType: CourierInboxFeedType }) => CourierInboxDatastore.shared.fetchNextPageOfMessages(props);\n const setPaginationLimit = (limit: number) => Courier.shared.paginationLimit = limit;\n const readMessage = (message: InboxMessage) => CourierInboxDatastore.shared.readMessage({ message });\n const unreadMessage = (message: InboxMessage) => CourierInboxDatastore.shared.unreadMessage({ message });\n const clickMessage = (message: InboxMessage) => CourierInboxDatastore.shared.clickMessage({ message });\n const archiveMessage = (message: InboxMessage) => CourierInboxDatastore.shared.archiveMessage({ message });\n const openMessage = (message: InboxMessage) => CourierInboxDatastore.shared.openMessage({ message });\n const unarchiveMessage = (message: InboxMessage) => CourierInboxDatastore.shared.unarchiveMessage({ message });\n const readAllMessages = () => CourierInboxDatastore.shared.readAllMessages();\n\n // State\n const [auth, setAuth] = React.useState<AuthenticationHooks>({\n userId: undefined,\n signIn,\n signOut\n });\n\n const [inbox, setInbox] = React.useState<InboxHooks>({\n load: loadInbox,\n fetchNextPageOfMessages,\n setPaginationLimit,\n readMessage,\n unreadMessage,\n clickMessage,\n archiveMessage,\n openMessage,\n unarchiveMessage,\n readAllMessages\n });\n\n React.useEffect(() => {\n\n // Add a listener to the Courier instance\n const listener = Courier.shared.addAuthenticationListener(() => refreshAuth());\n\n // Add inbox data store listener\n const inboxListener = new CourierInboxDataStoreListener({\n onError: (error: Error) => refreshInbox(error),\n onDataSetChange: () => refreshInbox(),\n onPageAdded: () => refreshInbox(),\n onMessageAdd: () => refreshInbox(),\n onMessageRemove: () => refreshInbox(),\n onMessageUpdate: () => refreshInbox(),\n onUnreadCountChange: () => refreshInbox()\n });\n CourierInboxDatastore.shared.addDataStoreListener(inboxListener);\n\n // Set initial values\n refreshAuth();\n refreshInbox();\n\n // Remove listeners when the component unmounts\n return () => {\n listener.remove();\n inboxListener.remove();\n };\n }, []);\n\n const refreshAuth = () => {\n const options = Courier.shared.client?.options;\n setAuth({\n userId: options?.userId,\n signIn,\n signOut\n });\n }\n\n const refreshInbox = (error?: Error) => {\n const datastore = CourierInboxDatastore.shared;\n setInbox({\n load: loadInbox,\n fetchNextPageOfMessages,\n setPaginationLimit,\n readMessage,\n unreadMessage,\n clickMessage,\n archiveMessage,\n openMessage,\n unarchiveMessage,\n readAllMessages,\n inbox: datastore.inboxDataSet,\n archive: datastore.archiveDataSet,\n unreadCount: datastore.unreadCount,\n error: error,\n });\n }\n\n return {\n shared: Courier.shared,\n auth: auth,\n inbox: inbox,\n };\n};\n"],"names":["CourierClientComponent","children","isMounted","setIsMounted","useState","useEffect","window","CourierRenderContext","createContext","CourierInboxComponent","forwardRef","props","ref","render","useContext","Error","inboxRef","useRef","getEl","current","inbox","onMessageClick","onMessageActionClick","onMessageLongPress","renderHeader","queueMicrotask","setHeader","headerProps","reactNode","renderListItem","setListItem","itemProps","renderEmptyState","setEmptyState","emptyStateProps","renderLoadingState","setLoadingState","loadingStateProps","renderErrorState","setErrorState","errorStateProps","renderPaginationItem","setPaginationItem","paginationProps","setFeedType","feedType","jsx","el","height","lightTheme","JSON","stringify","darkTheme","mode","CourierInboxPopupMenuComponent","lastFeedTypeRef","menu","_a","call","renderMenuButton","setMenuButton","buttonProps","popupAlignment","popupWidth","popupHeight","left","top","right","bottom","signIn","Courier","shared","signOut","loadInbox","CourierInboxDatastore","load","fetchNextPageOfMessages","setPaginationLimit","limit","paginationLimit","readMessage","message","unreadMessage","clickMessage","archiveMessage","openMessage","unarchiveMessage","readAllMessages","auth","setAuth","React","userId","setInbox","listener","addAuthenticationListener","refreshAuth","inboxListener","CourierInboxDataStoreListener","onError","error","refreshInbox","onDataSetChange","onPageAdded","onMessageAdd","onMessageRemove","onMessageUpdate","onUnreadCountChange","addDataStoreListener","remove","options","client","datastore","inboxDataSet","archive","archiveDataSet","unreadCount"],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export { useCourier } from './hooks/use-courier';
2
+ export { CourierInboxComponent } from './components/courier-inbox-component';
3
+ export { CourierInboxPopupMenuComponent } from './components/courier-inbox-popup-menu-component';
4
+ export type { CourierInboxProps } from './components/courier-inbox-component';
5
+ export type { CourierInboxPopupMenuProps, } from './components/courier-inbox-popup-menu-component';
6
+ export { CourierRenderContext } from './context/render-context';
package/dist/index.mjs ADDED
@@ -0,0 +1,363 @@
1
+ import { Courier } from "@trycourier/courier-js";
2
+ import { CourierInboxDatastore, CourierInboxDataStoreListener } from "@trycourier/courier-ui-inbox";
3
+ import React, { useState, useEffect, createContext, forwardRef, useContext, useRef } from "react";
4
+ import { jsx, Fragment } from "react/jsx-runtime";
5
+ const useCourier = () => {
6
+ const signIn = (props) => Courier.shared.signIn(props);
7
+ const signOut = () => Courier.shared.signOut();
8
+ const loadInbox = (props) => CourierInboxDatastore.shared.load(props);
9
+ const fetchNextPageOfMessages = (props) => CourierInboxDatastore.shared.fetchNextPageOfMessages(props);
10
+ const setPaginationLimit = (limit) => Courier.shared.paginationLimit = limit;
11
+ const readMessage = (message) => CourierInboxDatastore.shared.readMessage({ message });
12
+ const unreadMessage = (message) => CourierInboxDatastore.shared.unreadMessage({ message });
13
+ const clickMessage = (message) => CourierInboxDatastore.shared.clickMessage({ message });
14
+ const archiveMessage = (message) => CourierInboxDatastore.shared.archiveMessage({ message });
15
+ const openMessage = (message) => CourierInboxDatastore.shared.openMessage({ message });
16
+ const unarchiveMessage = (message) => CourierInboxDatastore.shared.unarchiveMessage({ message });
17
+ const readAllMessages = () => CourierInboxDatastore.shared.readAllMessages();
18
+ const [auth, setAuth] = React.useState({
19
+ userId: void 0,
20
+ signIn,
21
+ signOut
22
+ });
23
+ const [inbox, setInbox] = React.useState({
24
+ load: loadInbox,
25
+ fetchNextPageOfMessages,
26
+ setPaginationLimit,
27
+ readMessage,
28
+ unreadMessage,
29
+ clickMessage,
30
+ archiveMessage,
31
+ openMessage,
32
+ unarchiveMessage,
33
+ readAllMessages
34
+ });
35
+ React.useEffect(() => {
36
+ const listener = Courier.shared.addAuthenticationListener(() => refreshAuth());
37
+ const inboxListener = new CourierInboxDataStoreListener({
38
+ onError: (error) => refreshInbox(error),
39
+ onDataSetChange: () => refreshInbox(),
40
+ onPageAdded: () => refreshInbox(),
41
+ onMessageAdd: () => refreshInbox(),
42
+ onMessageRemove: () => refreshInbox(),
43
+ onMessageUpdate: () => refreshInbox(),
44
+ onUnreadCountChange: () => refreshInbox()
45
+ });
46
+ CourierInboxDatastore.shared.addDataStoreListener(inboxListener);
47
+ refreshAuth();
48
+ refreshInbox();
49
+ return () => {
50
+ listener.remove();
51
+ inboxListener.remove();
52
+ };
53
+ }, []);
54
+ const refreshAuth = () => {
55
+ var _a;
56
+ const options = (_a = Courier.shared.client) == null ? void 0 : _a.options;
57
+ setAuth({
58
+ userId: options == null ? void 0 : options.userId,
59
+ signIn,
60
+ signOut
61
+ });
62
+ };
63
+ const refreshInbox = (error) => {
64
+ const datastore = CourierInboxDatastore.shared;
65
+ setInbox({
66
+ load: loadInbox,
67
+ fetchNextPageOfMessages,
68
+ setPaginationLimit,
69
+ readMessage,
70
+ unreadMessage,
71
+ clickMessage,
72
+ archiveMessage,
73
+ openMessage,
74
+ unarchiveMessage,
75
+ readAllMessages,
76
+ inbox: datastore.inboxDataSet,
77
+ archive: datastore.archiveDataSet,
78
+ unreadCount: datastore.unreadCount,
79
+ error
80
+ });
81
+ };
82
+ return {
83
+ shared: Courier.shared,
84
+ auth,
85
+ inbox
86
+ };
87
+ };
88
+ const CourierClientComponent = ({ children }) => {
89
+ const [isMounted, setIsMounted] = useState(false);
90
+ useEffect(() => {
91
+ setIsMounted(true);
92
+ }, []);
93
+ if (typeof window === "undefined") {
94
+ return null;
95
+ }
96
+ if (!isMounted) {
97
+ return null;
98
+ }
99
+ return /* @__PURE__ */ jsx(Fragment, { children });
100
+ };
101
+ const CourierRenderContext = createContext(null);
102
+ const CourierInboxComponent = forwardRef((props, ref) => {
103
+ const render = useContext(CourierRenderContext);
104
+ if (!render) {
105
+ throw new Error("RenderContext not found. Ensure CourierInbox is wrapped in a CourierRenderContext.");
106
+ }
107
+ const inboxRef = useRef(null);
108
+ function handleRef(el) {
109
+ if (ref) {
110
+ if (typeof ref === "function") {
111
+ ref(el);
112
+ } else {
113
+ ref.current = el;
114
+ }
115
+ }
116
+ inboxRef.current = el;
117
+ }
118
+ function getEl() {
119
+ return inboxRef.current;
120
+ }
121
+ useEffect(() => {
122
+ const inbox = getEl();
123
+ if (!inbox) return;
124
+ inbox.onMessageClick(props.onMessageClick);
125
+ }, [props.onMessageClick]);
126
+ useEffect(() => {
127
+ const inbox = getEl();
128
+ if (!inbox) return;
129
+ inbox.onMessageActionClick(props.onMessageActionClick);
130
+ }, [props.onMessageActionClick]);
131
+ useEffect(() => {
132
+ const inbox = getEl();
133
+ if (!inbox) return;
134
+ inbox.onMessageLongPress(props.onMessageLongPress);
135
+ }, [props.onMessageLongPress]);
136
+ useEffect(() => {
137
+ const inbox = getEl();
138
+ if (!inbox || !props.renderHeader) return;
139
+ queueMicrotask(() => {
140
+ inbox.setHeader((headerProps) => {
141
+ const reactNode = props.renderHeader(headerProps);
142
+ return render(reactNode);
143
+ });
144
+ });
145
+ }, [props.renderHeader]);
146
+ useEffect(() => {
147
+ const inbox = getEl();
148
+ if (!inbox || !props.renderListItem) return;
149
+ queueMicrotask(() => {
150
+ inbox.setListItem((itemProps) => {
151
+ const reactNode = props.renderListItem(itemProps);
152
+ return render(reactNode);
153
+ });
154
+ });
155
+ }, [props.renderListItem]);
156
+ useEffect(() => {
157
+ const inbox = getEl();
158
+ if (!inbox || !props.renderEmptyState) return;
159
+ queueMicrotask(() => {
160
+ inbox.setEmptyState((emptyStateProps) => {
161
+ const reactNode = props.renderEmptyState(emptyStateProps);
162
+ return render(reactNode);
163
+ });
164
+ });
165
+ }, [props.renderEmptyState]);
166
+ useEffect(() => {
167
+ const inbox = getEl();
168
+ if (!inbox || !props.renderLoadingState) return;
169
+ queueMicrotask(() => {
170
+ inbox.setLoadingState((loadingStateProps) => {
171
+ const reactNode = props.renderLoadingState(loadingStateProps);
172
+ return render(reactNode);
173
+ });
174
+ });
175
+ }, [props.renderLoadingState]);
176
+ useEffect(() => {
177
+ const inbox = getEl();
178
+ if (!inbox || !props.renderErrorState) return;
179
+ queueMicrotask(() => {
180
+ inbox.setErrorState((errorStateProps) => {
181
+ const reactNode = props.renderErrorState(errorStateProps);
182
+ return render(reactNode);
183
+ });
184
+ });
185
+ }, [props.renderErrorState]);
186
+ useEffect(() => {
187
+ const inbox = getEl();
188
+ if (!inbox || !props.renderPaginationItem) return;
189
+ queueMicrotask(() => {
190
+ inbox.setPaginationItem((paginationProps) => {
191
+ const reactNode = props.renderPaginationItem(paginationProps);
192
+ return render(reactNode);
193
+ });
194
+ });
195
+ }, [props.renderPaginationItem]);
196
+ useEffect(() => {
197
+ const inbox = getEl();
198
+ if (!inbox) return;
199
+ queueMicrotask(() => {
200
+ inbox.setFeedType(props.feedType || "inbox");
201
+ });
202
+ }, [props.feedType]);
203
+ const children = (
204
+ /* @ts-ignore */
205
+ /* @__PURE__ */ jsx(
206
+ "courier-inbox",
207
+ {
208
+ ref: handleRef,
209
+ height: props.height,
210
+ "light-theme": props.lightTheme ? JSON.stringify(props.lightTheme) : void 0,
211
+ "dark-theme": props.darkTheme ? JSON.stringify(props.darkTheme) : void 0,
212
+ mode: props.mode
213
+ }
214
+ )
215
+ );
216
+ return /* @__PURE__ */ jsx(CourierClientComponent, { children });
217
+ });
218
+ const CourierInboxPopupMenuComponent = forwardRef(
219
+ (props, ref) => {
220
+ const render = useContext(CourierRenderContext);
221
+ if (!render) {
222
+ throw new Error("RenderContext not found. Ensure CourierInboxPopupMenu is wrapped in a CourierRenderContext.");
223
+ }
224
+ const inboxRef = useRef(null);
225
+ function handleRef(el) {
226
+ if (ref) {
227
+ if (typeof ref === "function") {
228
+ ref(el);
229
+ } else {
230
+ ref.current = el;
231
+ }
232
+ }
233
+ inboxRef.current = el;
234
+ }
235
+ function getEl() {
236
+ return inboxRef.current;
237
+ }
238
+ const lastFeedTypeRef = useRef(void 0);
239
+ useEffect(() => {
240
+ const menu = getEl();
241
+ if (!menu) return;
242
+ if (props.feedType !== lastFeedTypeRef.current) {
243
+ lastFeedTypeRef.current = props.feedType;
244
+ queueMicrotask(() => {
245
+ var _a;
246
+ (_a = menu.setFeedType) == null ? void 0 : _a.call(menu, props.feedType ?? "inbox");
247
+ });
248
+ }
249
+ }, [props.feedType]);
250
+ useEffect(() => {
251
+ const menu = getEl();
252
+ if (!menu) return;
253
+ menu.onMessageClick(props.onMessageClick);
254
+ }, [props.onMessageClick]);
255
+ useEffect(() => {
256
+ const menu = getEl();
257
+ if (!menu) return;
258
+ menu.onMessageActionClick(props.onMessageActionClick);
259
+ }, [props.onMessageActionClick]);
260
+ useEffect(() => {
261
+ const menu = getEl();
262
+ if (!menu) return;
263
+ menu.onMessageLongPress(props.onMessageLongPress);
264
+ }, [props.onMessageLongPress]);
265
+ useEffect(() => {
266
+ const menu = getEl();
267
+ if (!menu || !props.renderHeader) return;
268
+ queueMicrotask(() => {
269
+ menu.setHeader((headerProps) => {
270
+ const reactNode = props.renderHeader(headerProps);
271
+ return render(reactNode);
272
+ });
273
+ });
274
+ }, [props.renderHeader]);
275
+ useEffect(() => {
276
+ const menu = getEl();
277
+ if (!menu || !props.renderListItem) return;
278
+ queueMicrotask(() => {
279
+ menu.setListItem((itemProps) => {
280
+ const reactNode = props.renderListItem(itemProps);
281
+ return render(reactNode);
282
+ });
283
+ });
284
+ }, [props.renderListItem]);
285
+ useEffect(() => {
286
+ const menu = getEl();
287
+ if (!menu || !props.renderEmptyState) return;
288
+ queueMicrotask(() => {
289
+ menu.setEmptyState((emptyStateProps) => {
290
+ const reactNode = props.renderEmptyState(emptyStateProps);
291
+ return render(reactNode);
292
+ });
293
+ });
294
+ }, [props.renderEmptyState]);
295
+ useEffect(() => {
296
+ const menu = getEl();
297
+ if (!menu || !props.renderLoadingState) return;
298
+ queueMicrotask(() => {
299
+ menu.setLoadingState((loadingStateProps) => {
300
+ const reactNode = props.renderLoadingState(loadingStateProps);
301
+ return render(reactNode);
302
+ });
303
+ });
304
+ }, [props.renderLoadingState]);
305
+ useEffect(() => {
306
+ const menu = getEl();
307
+ if (!menu || !props.renderErrorState) return;
308
+ queueMicrotask(() => {
309
+ menu.setErrorState((errorStateProps) => {
310
+ const reactNode = props.renderErrorState(errorStateProps);
311
+ return render(reactNode);
312
+ });
313
+ });
314
+ }, [props.renderErrorState]);
315
+ useEffect(() => {
316
+ const menu = getEl();
317
+ if (!menu || !props.renderPaginationItem) return;
318
+ queueMicrotask(() => {
319
+ menu.setPaginationItem((paginationProps) => {
320
+ const reactNode = props.renderPaginationItem(paginationProps);
321
+ return render(reactNode);
322
+ });
323
+ });
324
+ }, [props.renderPaginationItem]);
325
+ useEffect(() => {
326
+ const menu = getEl();
327
+ if (!menu || !props.renderMenuButton) return;
328
+ queueMicrotask(() => {
329
+ menu.setMenuButton((buttonProps) => {
330
+ const reactNode = props.renderMenuButton(buttonProps);
331
+ return render(reactNode);
332
+ });
333
+ });
334
+ }, [props.renderMenuButton]);
335
+ const children = (
336
+ /* @ts-ignore */
337
+ /* @__PURE__ */ jsx(
338
+ "courier-inbox-popup-menu",
339
+ {
340
+ ref: handleRef,
341
+ "popup-alignment": props.popupAlignment,
342
+ "popup-width": props.popupWidth,
343
+ "popup-height": props.popupHeight,
344
+ left: props.left,
345
+ top: props.top,
346
+ right: props.right,
347
+ bottom: props.bottom,
348
+ "light-theme": props.lightTheme ? JSON.stringify(props.lightTheme) : void 0,
349
+ "dark-theme": props.darkTheme ? JSON.stringify(props.darkTheme) : void 0,
350
+ mode: props.mode
351
+ }
352
+ )
353
+ );
354
+ return /* @__PURE__ */ jsx(CourierClientComponent, { children });
355
+ }
356
+ );
357
+ export {
358
+ CourierInboxComponent,
359
+ CourierInboxPopupMenuComponent,
360
+ CourierRenderContext,
361
+ useCourier
362
+ };
363
+ //# sourceMappingURL=index.mjs.map