@novu/react 3.3.1 → 3.5.0-rc.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.
Files changed (44) hide show
  1. package/dist/cjs/components/Inbox.cjs +65 -61
  2. package/dist/cjs/components/Inbox.cjs.map +1 -1
  3. package/dist/cjs/components/NovuUI.cjs +59 -10
  4. package/dist/cjs/components/NovuUI.cjs.map +1 -1
  5. package/dist/cjs/components/NovuUI.d.cts +6 -2
  6. package/dist/cjs/components/ShadowRootDetector.cjs +63 -0
  7. package/dist/cjs/components/ShadowRootDetector.cjs.map +1 -0
  8. package/dist/cjs/components/ShadowRootDetector.d.cts +5 -0
  9. package/dist/cjs/hooks/NovuProvider.cjs +1 -1
  10. package/dist/cjs/hooks/useNotifications.cjs +8 -7
  11. package/dist/cjs/hooks/useNotifications.cjs.map +1 -1
  12. package/dist/cjs/hooks/useNotifications.d.cts +1 -0
  13. package/dist/cjs/index.cjs.map +1 -1
  14. package/dist/cjs/index.d.cts +1 -1
  15. package/dist/cjs/server/index.cjs +3 -0
  16. package/dist/cjs/server/index.cjs.map +1 -1
  17. package/dist/cjs/server/index.d.cts +3 -3
  18. package/dist/cjs/utils/appearance.cjs +53 -0
  19. package/dist/cjs/utils/appearance.cjs.map +1 -0
  20. package/dist/cjs/utils/appearance.d.cts +10 -0
  21. package/dist/cjs/utils/types.cjs.map +1 -1
  22. package/dist/cjs/utils/types.d.cts +18 -3
  23. package/dist/esm/components/Inbox.js +65 -61
  24. package/dist/esm/components/Inbox.js.map +1 -1
  25. package/dist/esm/components/NovuUI.d.ts +6 -2
  26. package/dist/esm/components/NovuUI.js +61 -12
  27. package/dist/esm/components/NovuUI.js.map +1 -1
  28. package/dist/esm/components/ShadowRootDetector.d.ts +5 -0
  29. package/dist/esm/components/ShadowRootDetector.js +28 -0
  30. package/dist/esm/components/ShadowRootDetector.js.map +1 -0
  31. package/dist/esm/hooks/NovuProvider.js +1 -1
  32. package/dist/esm/hooks/useNotifications.d.ts +1 -0
  33. package/dist/esm/hooks/useNotifications.js +8 -7
  34. package/dist/esm/hooks/useNotifications.js.map +1 -1
  35. package/dist/esm/index.d.ts +1 -1
  36. package/dist/esm/index.js.map +1 -1
  37. package/dist/esm/server/index.d.ts +3 -3
  38. package/dist/esm/server/index.js +3 -0
  39. package/dist/esm/server/index.js.map +1 -1
  40. package/dist/esm/utils/appearance.d.ts +10 -0
  41. package/dist/esm/utils/appearance.js +28 -0
  42. package/dist/esm/utils/appearance.js.map +1 -0
  43. package/dist/esm/utils/types.d.ts +18 -3
  44. package/package.json +9 -9
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/utils/appearance.ts
21
+ var appearance_exports = {};
22
+ __export(appearance_exports, {
23
+ adaptAppearanceForJs: () => adaptAppearanceForJs
24
+ });
25
+ module.exports = __toCommonJS(appearance_exports);
26
+ function adaptAppearanceForJs(appearance, mountElement) {
27
+ if (!appearance) {
28
+ return void 0;
29
+ }
30
+ const jsAppearance = JSON.parse(JSON.stringify(appearance));
31
+ if (appearance.icons) {
32
+ const jsIcons = {};
33
+ const reactIcons = appearance.icons;
34
+ const iconKeys = Object.keys(reactIcons);
35
+ for (const iconKey of iconKeys) {
36
+ const reactRenderer = reactIcons[iconKey];
37
+ if (reactRenderer) {
38
+ jsIcons[iconKey] = (el, props) => {
39
+ return mountElement(el, reactRenderer(props));
40
+ };
41
+ }
42
+ }
43
+ jsAppearance.icons = jsIcons;
44
+ } else {
45
+ delete jsAppearance.icons;
46
+ }
47
+ return jsAppearance;
48
+ }
49
+ // Annotate the CommonJS export names for ESM import in node:
50
+ 0 && (module.exports = {
51
+ adaptAppearanceForJs
52
+ });
53
+ //# sourceMappingURL=appearance.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/utils/appearance.ts"],"sourcesContent":["import type { Appearance as JsAppearance, IconRenderer, IconOverrides as JsIconOverrides, IconKey } from '@novu/js/ui';\n\nimport type { ReactAppearance, ReactIconRenderer } from './types';\nimport { MountedElement } from '../context/RendererContext';\n\nexport function adaptAppearanceForJs(\n appearance: ReactAppearance,\n mountElement: (el: HTMLElement, mountedElement: MountedElement) => () => void\n): JsAppearance | undefined {\n if (!appearance) {\n return undefined;\n }\n\n const jsAppearance: JsAppearance = JSON.parse(JSON.stringify(appearance));\n\n if (appearance.icons) {\n const jsIcons: JsIconOverrides = {};\n const reactIcons = appearance.icons;\n const iconKeys = Object.keys(reactIcons) as IconKey[];\n\n for (const iconKey of iconKeys) {\n const reactRenderer = reactIcons[iconKey];\n\n if (reactRenderer) {\n jsIcons[iconKey] = (el: HTMLDivElement, props: { class?: string }) => {\n return mountElement(el, reactRenderer(props));\n };\n }\n }\n\n // JsAppearance also has .icons directly (from JsTheme part of JsAppearance)\n jsAppearance.icons = jsIcons;\n } else {\n // If original didn't have icons, ensure the clone doesn't either\n delete jsAppearance.icons;\n }\n\n return jsAppearance;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAKO,SAAS,qBACd,YACA,cAC0B;AAC1B,MAAI,CAAC,YAAY;AACf,WAAO;AAAA,EACT;AAEA,QAAM,eAA6B,KAAK,MAAM,KAAK,UAAU,UAAU,CAAC;AAExE,MAAI,WAAW,OAAO;AACpB,UAAM,UAA2B,CAAC;AAClC,UAAM,aAAa,WAAW;AAC9B,UAAM,WAAW,OAAO,KAAK,UAAU;AAEvC,eAAW,WAAW,UAAU;AAC9B,YAAM,gBAAgB,WAAW,OAAO;AAExC,UAAI,eAAe;AACjB,gBAAQ,OAAO,IAAI,CAAC,IAAoB,UAA8B;AACpE,iBAAO,aAAa,IAAI,cAAc,KAAK,CAAC;AAAA,QAC9C;AAAA,MACF;AAAA,IACF;AAGA,iBAAa,QAAQ;AAAA,EACvB,OAAO;AAEL,WAAO,aAAa;AAAA,EACtB;AAEA,SAAO;AACT;","names":[]}
@@ -0,0 +1,10 @@
1
+ import { Appearance } from '@novu/js/ui';
2
+ import { ReactAppearance } from './types.cjs';
3
+ import { MountedElement } from '../context/RendererContext.cjs';
4
+ import '@novu/js';
5
+ import 'react';
6
+ import 'react/jsx-runtime';
7
+
8
+ declare function adaptAppearanceForJs(appearance: ReactAppearance, mountElement: (el: HTMLElement, mountedElement: MountedElement) => () => void): Appearance | undefined;
9
+
10
+ export { adaptAppearanceForJs };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/utils/types.ts"],"sourcesContent":["import type {\n Notification,\n NotificationClickHandler,\n NotificationActionClickHandler,\n Tab,\n Appearance,\n Localization,\n RouterPush,\n PreferencesFilter,\n InboxProps,\n} from '@novu/js/ui';\nimport type { Subscriber } from '@novu/js';\n\nexport type NotificationsRenderer = (notification: Notification) => React.ReactNode;\nexport type SubjectRenderer = (notification: Notification) => React.ReactNode;\nexport type BodyRenderer = (notification: Notification) => React.ReactNode;\nexport type BellRenderer = (unreadCount: number) => React.ReactNode;\n\nexport type DefaultInboxProps = {\n open?: boolean;\n renderNotification?: NotificationsRenderer;\n renderSubject?: SubjectRenderer;\n renderBody?: BodyRenderer;\n renderBell?: BellRenderer;\n onNotificationClick?: NotificationClickHandler;\n onPrimaryActionClick?: NotificationActionClickHandler;\n onSecondaryActionClick?: NotificationActionClickHandler;\n placement?: InboxProps['placement'];\n placementOffset?: InboxProps['placementOffset'];\n};\n\nexport type BaseProps = {\n applicationIdentifier: string;\n subscriberHash?: string;\n backendUrl?: string;\n socketUrl?: string;\n appearance?: Appearance;\n localization?: Localization;\n tabs?: Array<Tab>;\n preferencesFilter?: PreferencesFilter;\n routerPush?: RouterPush;\n} & (\n | {\n // TODO: Backward compatibility support - remove in future versions (see NV-5801)\n /** @deprecated Use subscriber prop instead */\n subscriberId: string;\n subscriber?: never;\n }\n | {\n subscriber: Subscriber | string;\n subscriberId?: never;\n }\n);\n\nexport type NotificationRendererProps = {\n renderNotification: NotificationsRenderer;\n renderSubject?: never;\n renderBody?: never;\n};\n\nexport type SubjectBodyRendererProps = {\n renderNotification?: never;\n renderSubject?: SubjectRenderer;\n renderBody?: BodyRenderer;\n};\n\nexport type NoRendererProps = {\n renderNotification?: undefined;\n renderSubject?: undefined;\n renderBody?: undefined;\n};\n\nexport type DefaultProps = BaseProps &\n DefaultInboxProps & {\n children?: never;\n } & (NotificationRendererProps | SubjectBodyRendererProps | NoRendererProps);\n\nexport type WithChildrenProps = BaseProps & {\n children: React.ReactNode;\n};\n"],"mappings":";;;;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
1
+ {"version":3,"sources":["../../../src/utils/types.ts"],"sourcesContent":["import type {\n Notification,\n NotificationClickHandler,\n NotificationActionClickHandler,\n Tab,\n Appearance as JsAppearance,\n Theme as JsTheme,\n IconKey,\n Localization,\n RouterPush,\n PreferencesFilter,\n PreferenceGroups,\n InboxProps,\n InboxPage,\n} from '@novu/js/ui';\nimport type { Subscriber } from '@novu/js';\nimport type { ReactNode } from 'react';\n\nexport type NotificationsRenderer = (notification: Notification) => React.ReactNode;\nexport type SubjectRenderer = (notification: Notification) => React.ReactNode;\nexport type BodyRenderer = (notification: Notification) => React.ReactNode;\nexport type BellRenderer = (unreadCount: number) => React.ReactNode;\n\nexport type ReactIconRendererProps = { class?: string };\nexport type ReactIconRenderer = (props: ReactIconRendererProps) => ReactNode;\n\nexport type ReactIconOverrides = {\n [key in IconKey]?: ReactIconRenderer;\n};\n\nexport type ReactTheme = Omit<JsTheme, 'icons'> & {\n icons?: ReactIconOverrides;\n};\n\nexport type ReactAppearance = ReactTheme & {\n baseTheme?: JsTheme | JsTheme[];\n};\n\nexport type DefaultInboxProps = {\n open?: boolean;\n renderNotification?: NotificationsRenderer;\n renderSubject?: SubjectRenderer;\n renderBody?: BodyRenderer;\n renderBell?: BellRenderer;\n onNotificationClick?: NotificationClickHandler;\n onPrimaryActionClick?: NotificationActionClickHandler;\n onSecondaryActionClick?: NotificationActionClickHandler;\n placement?: InboxProps['placement'];\n placementOffset?: InboxProps['placementOffset'];\n};\n\nexport type BaseProps = {\n applicationIdentifier: string;\n subscriberHash?: string;\n backendUrl?: string;\n socketUrl?: string;\n appearance?: ReactAppearance;\n localization?: Localization;\n tabs?: Array<Tab>;\n preferencesFilter?: PreferencesFilter;\n preferenceGroups?: PreferenceGroups;\n routerPush?: RouterPush;\n} & (\n | {\n // TODO: Backward compatibility support - remove in future versions (see NV-5801)\n /** @deprecated Use subscriber prop instead */\n subscriberId: string;\n subscriber?: never;\n }\n | {\n subscriber: Subscriber | string;\n subscriberId?: never;\n }\n);\n\nexport type NotificationRendererProps = {\n renderNotification: NotificationsRenderer;\n renderSubject?: never;\n renderBody?: never;\n};\n\nexport type SubjectBodyRendererProps = {\n renderNotification?: never;\n renderSubject?: SubjectRenderer;\n renderBody?: BodyRenderer;\n};\n\nexport type NoRendererProps = {\n renderNotification?: undefined;\n renderSubject?: undefined;\n renderBody?: undefined;\n};\n\nexport type DefaultProps = BaseProps &\n DefaultInboxProps & {\n children?: never;\n } & (NotificationRendererProps | SubjectBodyRendererProps | NoRendererProps);\n\nexport type WithChildrenProps = BaseProps & {\n children: React.ReactNode;\n};\n"],"mappings":";;;;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
@@ -1,10 +1,24 @@
1
- import { Notification, NotificationClickHandler, NotificationActionClickHandler, InboxProps, Appearance, Localization, Tab, PreferencesFilter, RouterPush } from '@novu/js/ui';
1
+ import { Notification, IconKey, Theme, NotificationClickHandler, NotificationActionClickHandler, InboxProps, Localization, Tab, PreferencesFilter, PreferenceGroups, RouterPush } from '@novu/js/ui';
2
2
  import { Subscriber } from '@novu/js';
3
+ import { ReactNode } from 'react';
3
4
 
4
5
  type NotificationsRenderer = (notification: Notification) => React.ReactNode;
5
6
  type SubjectRenderer = (notification: Notification) => React.ReactNode;
6
7
  type BodyRenderer = (notification: Notification) => React.ReactNode;
7
8
  type BellRenderer = (unreadCount: number) => React.ReactNode;
9
+ type ReactIconRendererProps = {
10
+ class?: string;
11
+ };
12
+ type ReactIconRenderer = (props: ReactIconRendererProps) => ReactNode;
13
+ type ReactIconOverrides = {
14
+ [key in IconKey]?: ReactIconRenderer;
15
+ };
16
+ type ReactTheme = Omit<Theme, 'icons'> & {
17
+ icons?: ReactIconOverrides;
18
+ };
19
+ type ReactAppearance = ReactTheme & {
20
+ baseTheme?: Theme | Theme[];
21
+ };
8
22
  type DefaultInboxProps = {
9
23
  open?: boolean;
10
24
  renderNotification?: NotificationsRenderer;
@@ -22,10 +36,11 @@ type BaseProps = {
22
36
  subscriberHash?: string;
23
37
  backendUrl?: string;
24
38
  socketUrl?: string;
25
- appearance?: Appearance;
39
+ appearance?: ReactAppearance;
26
40
  localization?: Localization;
27
41
  tabs?: Array<Tab>;
28
42
  preferencesFilter?: PreferencesFilter;
43
+ preferenceGroups?: PreferenceGroups;
29
44
  routerPush?: RouterPush;
30
45
  } & ({
31
46
  /** @deprecated Use subscriber prop instead */
@@ -57,4 +72,4 @@ type WithChildrenProps = BaseProps & {
57
72
  children: React.ReactNode;
58
73
  };
59
74
 
60
- export type { BaseProps, BellRenderer, BodyRenderer, DefaultInboxProps, DefaultProps, NoRendererProps, NotificationRendererProps, NotificationsRenderer, SubjectBodyRendererProps, SubjectRenderer, WithChildrenProps };
75
+ export type { BaseProps, BellRenderer, BodyRenderer, DefaultInboxProps, DefaultProps, NoRendererProps, NotificationRendererProps, NotificationsRenderer, ReactAppearance, ReactIconOverrides, ReactIconRenderer, ReactIconRendererProps, ReactTheme, SubjectBodyRendererProps, SubjectRenderer, WithChildrenProps };
@@ -7,7 +7,7 @@ import { InternalNovuProvider, useNovu, useUnsafeNovu } from "../hooks/NovuProvi
7
7
  import { NovuUI } from "./NovuUI.js";
8
8
  import { withRenderer } from "./Renderer.js";
9
9
  import { jsx } from "react/jsx-runtime";
10
- var _DefaultInbox = (props) => {
10
+ var DefaultInbox = (props) => {
11
11
  const {
12
12
  open,
13
13
  renderNotification,
@@ -69,7 +69,6 @@ var _DefaultInbox = (props) => {
69
69
  );
70
70
  return /* @__PURE__ */ jsx(Mounter, { mount });
71
71
  };
72
- var DefaultInbox = withRenderer(_DefaultInbox);
73
72
  var Inbox = React.memo((props) => {
74
73
  const { applicationIdentifier, subscriberHash, backendUrl, socketUrl } = props;
75
74
  const novu = useUnsafeNovu();
@@ -89,65 +88,55 @@ var Inbox = React.memo((props) => {
89
88
  }
90
89
  );
91
90
  });
92
- var InboxChild = React.memo((props) => {
93
- const {
94
- localization,
95
- appearance,
96
- tabs,
97
- preferencesFilter,
98
- routerPush,
99
- applicationIdentifier,
100
- subscriberId,
101
- subscriberHash,
102
- backendUrl,
103
- socketUrl
104
- } = props;
105
- const novu = useNovu();
106
- const options = useMemo(() => {
107
- return {
91
+ var InboxChild = withRenderer(
92
+ React.memo((props) => {
93
+ const {
108
94
  localization,
109
95
  appearance,
110
96
  tabs,
111
97
  preferencesFilter,
98
+ preferenceGroups,
112
99
  routerPush,
113
- options: {
114
- applicationIdentifier,
115
- subscriberHash,
116
- backendUrl,
117
- socketUrl,
118
- subscriber: buildSubscriber(props)
119
- }
120
- };
121
- }, [
122
- localization,
123
- appearance,
124
- tabs,
125
- preferencesFilter,
126
- applicationIdentifier,
127
- subscriberId,
128
- subscriberHash,
129
- backendUrl,
130
- socketUrl,
131
- props.subscriber
132
- ]);
133
- if (isWithChildrenProps(props)) {
134
- return /* @__PURE__ */ jsx(NovuUI, { options, novu, children: props.children });
135
- }
136
- const {
137
- open,
138
- renderNotification,
139
- renderSubject,
140
- renderBody,
141
- renderBell,
142
- onNotificationClick,
143
- onPrimaryActionClick,
144
- onSecondaryActionClick,
145
- placementOffset,
146
- placement
147
- } = props;
148
- return /* @__PURE__ */ jsx(NovuUI, { options, novu, children: /* @__PURE__ */ jsx(
149
- DefaultInbox,
150
- {
100
+ applicationIdentifier,
101
+ subscriberId,
102
+ subscriberHash,
103
+ backendUrl,
104
+ socketUrl
105
+ } = props;
106
+ const novu = useNovu();
107
+ const options = useMemo(() => {
108
+ return {
109
+ localization,
110
+ appearance,
111
+ tabs,
112
+ preferencesFilter,
113
+ preferenceGroups,
114
+ routerPush,
115
+ options: {
116
+ applicationIdentifier,
117
+ subscriberHash,
118
+ backendUrl,
119
+ socketUrl,
120
+ subscriber: buildSubscriber(props)
121
+ }
122
+ };
123
+ }, [
124
+ localization,
125
+ appearance,
126
+ tabs,
127
+ preferencesFilter,
128
+ preferenceGroups,
129
+ applicationIdentifier,
130
+ subscriberId,
131
+ subscriberHash,
132
+ backendUrl,
133
+ socketUrl,
134
+ props.subscriber
135
+ ]);
136
+ if (isWithChildrenProps(props)) {
137
+ return /* @__PURE__ */ jsx(NovuUI, { options, novu, children: props.children });
138
+ }
139
+ const {
151
140
  open,
152
141
  renderNotification,
153
142
  renderSubject,
@@ -156,11 +145,26 @@ var InboxChild = React.memo((props) => {
156
145
  onNotificationClick,
157
146
  onPrimaryActionClick,
158
147
  onSecondaryActionClick,
159
- placement,
160
- placementOffset
161
- }
162
- ) });
163
- });
148
+ placementOffset,
149
+ placement
150
+ } = props;
151
+ return /* @__PURE__ */ jsx(NovuUI, { options, novu, children: /* @__PURE__ */ jsx(
152
+ DefaultInbox,
153
+ {
154
+ open,
155
+ renderNotification,
156
+ renderSubject,
157
+ renderBody,
158
+ renderBell,
159
+ onNotificationClick,
160
+ onPrimaryActionClick,
161
+ onSecondaryActionClick,
162
+ placement,
163
+ placementOffset
164
+ }
165
+ ) });
166
+ })
167
+ );
164
168
  function isWithChildrenProps(props) {
165
169
  return "children" in props;
166
170
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/Inbox.tsx"],"sourcesContent":["import React, { useMemo } from 'react';\nimport { Subscriber } from '@novu/js';\nimport { DefaultProps, DefaultInboxProps, WithChildrenProps } from '../utils/types';\nimport { Mounter } from './Mounter';\nimport { useNovuUI } from '../context/NovuUIContext';\nimport { useRenderer } from '../context/RendererContext';\nimport { InternalNovuProvider, useNovu, useUnsafeNovu } from '../hooks/NovuProvider';\nimport { NovuUI } from './NovuUI';\nimport { withRenderer } from './Renderer';\n\nexport type InboxProps = DefaultProps | WithChildrenProps;\n\nconst _DefaultInbox = (props: DefaultInboxProps) => {\n const {\n open,\n renderNotification,\n renderSubject,\n renderBody,\n renderBell,\n onNotificationClick,\n onPrimaryActionClick,\n onSecondaryActionClick,\n placement,\n placementOffset,\n } = props;\n const { novuUI } = useNovuUI();\n const { mountElement } = useRenderer();\n\n const mount = React.useCallback(\n (element: HTMLElement) => {\n if (renderNotification) {\n return novuUI.mountComponent({\n name: 'Inbox',\n props: {\n open,\n renderNotification: renderNotification\n ? (el, notification) => mountElement(el, renderNotification(notification))\n : undefined,\n renderBell: renderBell ? (el, unreadCount) => mountElement(el, renderBell(unreadCount)) : undefined,\n onNotificationClick,\n onPrimaryActionClick,\n onSecondaryActionClick,\n placementOffset,\n placement,\n },\n element,\n });\n }\n\n return novuUI.mountComponent({\n name: 'Inbox',\n props: {\n open,\n renderSubject: renderSubject\n ? (el, notification) => mountElement(el, renderSubject(notification))\n : undefined,\n renderBody: renderBody ? (el, notification) => mountElement(el, renderBody(notification)) : undefined,\n renderBell: renderBell ? (el, unreadCount) => mountElement(el, renderBell(unreadCount)) : undefined,\n onNotificationClick,\n onPrimaryActionClick,\n onSecondaryActionClick,\n placementOffset,\n placement,\n },\n element,\n });\n },\n [\n open,\n renderNotification,\n renderSubject,\n renderBody,\n renderBell,\n onNotificationClick,\n onPrimaryActionClick,\n onSecondaryActionClick,\n ]\n );\n\n return <Mounter mount={mount} />;\n};\n\nconst DefaultInbox = withRenderer(_DefaultInbox);\n\nexport const Inbox = React.memo((props: InboxProps) => {\n const { applicationIdentifier, subscriberHash, backendUrl, socketUrl } = props;\n const novu = useUnsafeNovu();\n\n if (novu) {\n return <InboxChild {...props} />;\n }\n\n return (\n <InternalNovuProvider\n applicationIdentifier={applicationIdentifier}\n subscriberHash={subscriberHash}\n backendUrl={backendUrl}\n socketUrl={socketUrl}\n subscriber={buildSubscriber(props)}\n userAgentType=\"components\"\n >\n <InboxChild {...props} />\n </InternalNovuProvider>\n );\n});\n\nconst InboxChild = React.memo((props: InboxProps) => {\n const {\n localization,\n appearance,\n tabs,\n preferencesFilter,\n routerPush,\n applicationIdentifier,\n subscriberId,\n subscriberHash,\n backendUrl,\n socketUrl,\n } = props;\n const novu = useNovu();\n\n const options = useMemo(() => {\n return {\n localization,\n appearance,\n tabs,\n preferencesFilter,\n routerPush,\n options: {\n applicationIdentifier,\n subscriberHash,\n backendUrl,\n socketUrl,\n subscriber: buildSubscriber(props),\n },\n };\n }, [\n localization,\n appearance,\n tabs,\n preferencesFilter,\n applicationIdentifier,\n subscriberId,\n subscriberHash,\n backendUrl,\n socketUrl,\n props.subscriber,\n ]);\n\n if (isWithChildrenProps(props)) {\n return (\n <NovuUI options={options} novu={novu}>\n {props.children}\n </NovuUI>\n );\n }\n\n const {\n open,\n renderNotification,\n renderSubject,\n renderBody,\n renderBell,\n onNotificationClick,\n onPrimaryActionClick,\n onSecondaryActionClick,\n placementOffset,\n placement,\n } = props;\n\n return (\n <NovuUI options={options} novu={novu}>\n <DefaultInbox\n open={open}\n renderNotification={renderNotification}\n renderSubject={renderSubject}\n renderBody={renderBody}\n renderBell={renderBell}\n onNotificationClick={onNotificationClick}\n onPrimaryActionClick={onPrimaryActionClick}\n onSecondaryActionClick={onSecondaryActionClick}\n placement={placement}\n placementOffset={placementOffset}\n />\n </NovuUI>\n );\n});\n\nfunction isWithChildrenProps(props: InboxProps): props is WithChildrenProps {\n return 'children' in props;\n}\n\nfunction buildSubscriber(options: InboxProps): Subscriber {\n let subscriberObj: Subscriber;\n\n if (options.subscriber) {\n subscriberObj = typeof options.subscriber === 'string' ? { subscriberId: options.subscriber } : options.subscriber;\n } else {\n subscriberObj = { subscriberId: options.subscriberId as string };\n }\n\n return subscriberObj;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/components/Inbox.tsx"],"sourcesContent":["import React, { useMemo } from 'react';\nimport { Subscriber } from '@novu/js';\nimport { DefaultProps, DefaultInboxProps, WithChildrenProps } from '../utils/types';\nimport { Mounter } from './Mounter';\nimport { useNovuUI } from '../context/NovuUIContext';\nimport { useRenderer } from '../context/RendererContext';\nimport { InternalNovuProvider, useNovu, useUnsafeNovu } from '../hooks/NovuProvider';\nimport { NovuUI } from './NovuUI';\nimport { withRenderer } from './Renderer';\n\nexport type InboxProps = DefaultProps | WithChildrenProps;\n\nconst DefaultInbox = (props: DefaultInboxProps) => {\n const {\n open,\n renderNotification,\n renderSubject,\n renderBody,\n renderBell,\n onNotificationClick,\n onPrimaryActionClick,\n onSecondaryActionClick,\n placement,\n placementOffset,\n } = props;\n const { novuUI } = useNovuUI();\n const { mountElement } = useRenderer();\n\n const mount = React.useCallback(\n (element: HTMLElement) => {\n if (renderNotification) {\n return novuUI.mountComponent({\n name: 'Inbox',\n props: {\n open,\n renderNotification: renderNotification\n ? (el, notification) => mountElement(el, renderNotification(notification))\n : undefined,\n renderBell: renderBell ? (el, unreadCount) => mountElement(el, renderBell(unreadCount)) : undefined,\n onNotificationClick,\n onPrimaryActionClick,\n onSecondaryActionClick,\n placementOffset,\n placement,\n },\n element,\n });\n }\n\n return novuUI.mountComponent({\n name: 'Inbox',\n props: {\n open,\n renderSubject: renderSubject\n ? (el, notification) => mountElement(el, renderSubject(notification))\n : undefined,\n renderBody: renderBody ? (el, notification) => mountElement(el, renderBody(notification)) : undefined,\n renderBell: renderBell ? (el, unreadCount) => mountElement(el, renderBell(unreadCount)) : undefined,\n onNotificationClick,\n onPrimaryActionClick,\n onSecondaryActionClick,\n placementOffset,\n placement,\n },\n element,\n });\n },\n [\n open,\n renderNotification,\n renderSubject,\n renderBody,\n renderBell,\n onNotificationClick,\n onPrimaryActionClick,\n onSecondaryActionClick,\n ]\n );\n\n return <Mounter mount={mount} />;\n};\n\nexport const Inbox = React.memo((props: InboxProps) => {\n const { applicationIdentifier, subscriberHash, backendUrl, socketUrl } = props;\n const novu = useUnsafeNovu();\n\n if (novu) {\n return <InboxChild {...props} />;\n }\n\n return (\n <InternalNovuProvider\n applicationIdentifier={applicationIdentifier}\n subscriberHash={subscriberHash}\n backendUrl={backendUrl}\n socketUrl={socketUrl}\n subscriber={buildSubscriber(props)}\n userAgentType=\"components\"\n >\n <InboxChild {...props} />\n </InternalNovuProvider>\n );\n});\n\nconst InboxChild = withRenderer(\n React.memo((props: InboxProps) => {\n const {\n localization,\n appearance,\n tabs,\n preferencesFilter,\n preferenceGroups,\n routerPush,\n applicationIdentifier,\n subscriberId,\n subscriberHash,\n backendUrl,\n socketUrl,\n } = props;\n const novu = useNovu();\n\n const options = useMemo(() => {\n return {\n localization,\n appearance,\n tabs,\n preferencesFilter,\n preferenceGroups,\n routerPush,\n options: {\n applicationIdentifier,\n subscriberHash,\n backendUrl,\n socketUrl,\n subscriber: buildSubscriber(props),\n },\n };\n }, [\n localization,\n appearance,\n tabs,\n preferencesFilter,\n preferenceGroups,\n applicationIdentifier,\n subscriberId,\n subscriberHash,\n backendUrl,\n socketUrl,\n props.subscriber,\n ]);\n\n if (isWithChildrenProps(props)) {\n return (\n <NovuUI options={options} novu={novu}>\n {props.children}\n </NovuUI>\n );\n }\n\n const {\n open,\n renderNotification,\n renderSubject,\n renderBody,\n renderBell,\n onNotificationClick,\n onPrimaryActionClick,\n onSecondaryActionClick,\n placementOffset,\n placement,\n } = props;\n\n return (\n <NovuUI options={options} novu={novu}>\n <DefaultInbox\n open={open}\n renderNotification={renderNotification}\n renderSubject={renderSubject}\n renderBody={renderBody}\n renderBell={renderBell}\n onNotificationClick={onNotificationClick}\n onPrimaryActionClick={onPrimaryActionClick}\n onSecondaryActionClick={onSecondaryActionClick}\n placement={placement}\n placementOffset={placementOffset}\n />\n </NovuUI>\n );\n })\n);\n\nfunction isWithChildrenProps(props: InboxProps): props is WithChildrenProps {\n return 'children' in props;\n}\n\nfunction buildSubscriber(options: InboxProps): Subscriber {\n let subscriberObj: Subscriber;\n\n if (options.subscriber) {\n subscriberObj = typeof options.subscriber === 'string' ? { subscriberId: options.subscriber } : options.subscriber;\n } else {\n subscriberObj = { subscriberId: options.subscriberId as string };\n }\n\n return subscriberObj;\n}\n"],"mappings":"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","names":[]}
@@ -2,11 +2,15 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { Novu } from '@novu/js';
3
3
  import { NovuUIOptions } from '@novu/js/ui';
4
4
  import React__default from 'react';
5
+ import { ReactAppearance } from '../utils/types.js';
5
6
 
7
+ type NovuUIProps = Omit<NovuUIOptions, 'appearance'> & {
8
+ appearance?: ReactAppearance;
9
+ };
6
10
  type RendererProps = React__default.PropsWithChildren<{
7
- options: NovuUIOptions;
11
+ options: NovuUIProps;
8
12
  novu?: Novu;
9
13
  }>;
10
- declare const NovuUI: ({ options, novu, children }: RendererProps) => react_jsx_runtime.JSX.Element | null;
14
+ declare const NovuUI: ({ options, novu, children }: RendererProps) => react_jsx_runtime.JSX.Element;
11
15
 
12
16
  export { NovuUI };
@@ -1,33 +1,82 @@
1
1
  // src/components/NovuUI.tsx
2
2
  import { NovuUI as NovuUIClass } from "@novu/js/ui";
3
- import { useEffect, useState } from "react";
3
+ import { useEffect, useMemo, useRef, useState } from "react";
4
4
  import { NovuUIProvider } from "../context/NovuUIContext.js";
5
5
  import { useDataRef } from "../hooks/internal/useDataRef.js";
6
- import { jsx } from "react/jsx-runtime";
6
+ import { adaptAppearanceForJs } from "../utils/appearance.js";
7
+ import { useRenderer } from "../context/RendererContext.js";
8
+ import { ShadowRootDetector } from "./ShadowRootDetector.js";
9
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
10
+ var findParentShadowRoot = (child) => {
11
+ if (!child) {
12
+ return null;
13
+ }
14
+ let node = child;
15
+ while (node) {
16
+ if (node instanceof Element && node.shadowRoot) {
17
+ return node.shadowRoot;
18
+ }
19
+ if (node instanceof ShadowRoot) {
20
+ return node;
21
+ }
22
+ node = node.parentNode;
23
+ if (!node || node === document) {
24
+ break;
25
+ }
26
+ }
27
+ return null;
28
+ };
7
29
  var NovuUI = ({ options, novu, children }) => {
8
- const optionsRef = useDataRef({ ...options, novu });
30
+ const shadowRootDetector = useRef(null);
31
+ const { mountElement } = useRenderer();
32
+ const adaptedAppearanceForUpdate = useMemo(
33
+ () => adaptAppearanceForJs(options.appearance || {}, mountElement),
34
+ [options.appearance, mountElement]
35
+ );
36
+ const adaptedOptions = useMemo(() => {
37
+ return {
38
+ ...options,
39
+ appearance: adaptedAppearanceForUpdate,
40
+ novu
41
+ };
42
+ }, [options, novu, adaptedAppearanceForUpdate]);
43
+ const optionsRef = useDataRef(adaptedOptions);
9
44
  const [novuUI, setNovuUI] = useState();
10
45
  useEffect(() => {
11
- const novu2 = new NovuUIClass(optionsRef.current);
12
- setNovuUI(novu2);
46
+ const parentShadowRoot = findParentShadowRoot(shadowRootDetector.current);
47
+ const instance = new NovuUIClass({
48
+ ...optionsRef.current,
49
+ container: optionsRef.current.container ?? parentShadowRoot
50
+ });
51
+ setNovuUI(instance);
13
52
  return () => {
14
- novu2.unmount();
53
+ instance.unmount();
15
54
  };
16
55
  }, []);
17
56
  useEffect(() => {
18
57
  if (!novuUI) {
19
58
  return;
20
59
  }
21
- novuUI.updateAppearance(options.appearance);
60
+ const parentShadowRoot = findParentShadowRoot(shadowRootDetector.current);
61
+ novuUI.updateContainer(options.container ?? parentShadowRoot);
62
+ novuUI.updateAppearance(adaptedAppearanceForUpdate);
22
63
  novuUI.updateLocalization(options.localization);
23
64
  novuUI.updateTabs(options.tabs);
24
65
  novuUI.updateOptions(options.options);
25
66
  novuUI.updateRouterPush(options.routerPush);
26
- }, [options]);
27
- if (!novuUI) {
28
- return null;
29
- }
30
- return /* @__PURE__ */ jsx(NovuUIProvider, { value: { novuUI }, children });
67
+ }, [
68
+ shadowRootDetector,
69
+ novuUI,
70
+ adaptedAppearanceForUpdate,
71
+ options.localization,
72
+ options.tabs,
73
+ options.options,
74
+ options.routerPush
75
+ ]);
76
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
77
+ /* @__PURE__ */ jsx(ShadowRootDetector, { ref: shadowRootDetector }),
78
+ novuUI && /* @__PURE__ */ jsx(NovuUIProvider, { value: { novuUI }, children })
79
+ ] });
31
80
  };
32
81
  export {
33
82
  NovuUI
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/NovuUI.tsx"],"sourcesContent":["import { Novu } from '@novu/js';\nimport type { NovuUIOptions } from '@novu/js/ui';\nimport { NovuUI as NovuUIClass } from '@novu/js/ui';\nimport React, { useEffect, useState } from 'react';\nimport { NovuUIProvider } from '../context/NovuUIContext';\nimport { useDataRef } from '../hooks/internal/useDataRef';\n\ntype RendererProps = React.PropsWithChildren<{\n options: NovuUIOptions;\n novu?: Novu;\n}>;\n\nexport const NovuUI = ({ options, novu, children }: RendererProps) => {\n const optionsRef = useDataRef({ ...options, novu });\n const [novuUI, setNovuUI] = useState<NovuUIClass | undefined>();\n\n useEffect(() => {\n const novu = new NovuUIClass(optionsRef.current);\n setNovuUI(novu);\n\n return () => {\n novu.unmount();\n };\n }, []);\n\n useEffect(() => {\n if (!novuUI) {\n return;\n }\n\n novuUI.updateAppearance(options.appearance);\n novuUI.updateLocalization(options.localization);\n novuUI.updateTabs(options.tabs);\n novuUI.updateOptions(options.options);\n novuUI.updateRouterPush(options.routerPush);\n }, [options]);\n\n if (!novuUI) {\n return null;\n }\n\n return <NovuUIProvider value={{ novuUI }}>{children}</NovuUIProvider>;\n};\n"],"mappings":";AAEA,SAAS,UAAU,mBAAmB;AACtC,SAAgB,WAAW,gBAAgB;AAC3C,SAAS,sBAAsB;AAC/B,SAAS,kBAAkB;AAoClB;AA7BF,IAAM,SAAS,CAAC,EAAE,SAAS,MAAM,SAAS,MAAqB;AACpE,QAAM,aAAa,WAAW,EAAE,GAAG,SAAS,KAAK,CAAC;AAClD,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAkC;AAE9D,YAAU,MAAM;AACd,UAAMA,QAAO,IAAI,YAAY,WAAW,OAAO;AAC/C,cAAUA,KAAI;AAEd,WAAO,MAAM;AACX,MAAAA,MAAK,QAAQ;AAAA,IACf;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,YAAU,MAAM;AACd,QAAI,CAAC,QAAQ;AACX;AAAA,IACF;AAEA,WAAO,iBAAiB,QAAQ,UAAU;AAC1C,WAAO,mBAAmB,QAAQ,YAAY;AAC9C,WAAO,WAAW,QAAQ,IAAI;AAC9B,WAAO,cAAc,QAAQ,OAAO;AACpC,WAAO,iBAAiB,QAAQ,UAAU;AAAA,EAC5C,GAAG,CAAC,OAAO,CAAC;AAEZ,MAAI,CAAC,QAAQ;AACX,WAAO;AAAA,EACT;AAEA,SAAO,oBAAC,kBAAe,OAAO,EAAE,OAAO,GAAI,UAAS;AACtD;","names":["novu"]}
1
+ {"version":3,"sources":["../../../src/components/NovuUI.tsx"],"sourcesContent":["import { Novu } from '@novu/js';\nimport type { NovuUIOptions as JsNovuUIOptions } from '@novu/js/ui';\nimport { NovuUI as NovuUIClass } from '@novu/js/ui';\nimport React, { useEffect, useMemo, useRef, useState } from 'react';\nimport { NovuUIProvider } from '../context/NovuUIContext';\nimport { useDataRef } from '../hooks/internal/useDataRef';\nimport type { ReactAppearance } from '../utils/types';\nimport { adaptAppearanceForJs } from '../utils/appearance';\nimport { useRenderer } from '../context/RendererContext';\nimport { ShadowRootDetector } from './ShadowRootDetector';\n\ntype NovuUIProps = Omit<JsNovuUIOptions, 'appearance'> & {\n appearance?: ReactAppearance;\n};\n\ntype RendererProps = React.PropsWithChildren<{\n options: NovuUIProps;\n novu?: Novu;\n}>;\n\nconst findParentShadowRoot = (child?: HTMLDivElement | null): Node | null => {\n if (!child) {\n return null;\n }\n\n let node: Node | null = child;\n\n while (node) {\n if (node instanceof Element && node.shadowRoot) {\n return node.shadowRoot;\n }\n\n if (node instanceof ShadowRoot) {\n return node;\n }\n\n node = node.parentNode;\n\n if (!node || node === document) {\n break;\n }\n }\n\n return null;\n};\n\nexport const NovuUI = ({ options, novu, children }: RendererProps) => {\n const shadowRootDetector = useRef<HTMLDivElement>(null);\n const { mountElement } = useRenderer();\n\n const adaptedAppearanceForUpdate = useMemo(\n () => adaptAppearanceForJs(options.appearance || {}, mountElement),\n [options.appearance, mountElement]\n );\n\n const adaptedOptions = useMemo(() => {\n return {\n ...options,\n appearance: adaptedAppearanceForUpdate,\n novu,\n };\n }, [options, novu, adaptedAppearanceForUpdate]);\n\n const optionsRef = useDataRef(adaptedOptions);\n const [novuUI, setNovuUI] = useState<NovuUIClass | undefined>();\n\n useEffect(() => {\n const parentShadowRoot = findParentShadowRoot(shadowRootDetector.current);\n const instance = new NovuUIClass({\n ...optionsRef.current,\n container: optionsRef.current.container ?? parentShadowRoot,\n });\n setNovuUI(instance);\n\n return () => {\n instance.unmount();\n };\n }, []);\n\n useEffect(() => {\n if (!novuUI) {\n return;\n }\n\n const parentShadowRoot = findParentShadowRoot(shadowRootDetector.current);\n novuUI.updateContainer(options.container ?? parentShadowRoot);\n novuUI.updateAppearance(adaptedAppearanceForUpdate);\n novuUI.updateLocalization(options.localization);\n novuUI.updateTabs(options.tabs);\n novuUI.updateOptions(options.options);\n novuUI.updateRouterPush(options.routerPush);\n }, [\n shadowRootDetector,\n novuUI,\n adaptedAppearanceForUpdate,\n options.localization,\n options.tabs,\n options.options,\n options.routerPush,\n ]);\n\n return (\n <>\n <ShadowRootDetector ref={shadowRootDetector} />\n {novuUI && <NovuUIProvider value={{ novuUI }}>{children}</NovuUIProvider>}\n </>\n );\n};\n"],"mappings":";AAEA,SAAS,UAAU,mBAAmB;AACtC,SAAgB,WAAW,SAAS,QAAQ,gBAAgB;AAC5D,SAAS,sBAAsB;AAC/B,SAAS,kBAAkB;AAE3B,SAAS,4BAA4B;AACrC,SAAS,mBAAmB;AAC5B,SAAS,0BAA0B;AA6F/B,mBACE,KADF;AAlFJ,IAAM,uBAAuB,CAAC,UAA+C;AAC3E,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AAEA,MAAI,OAAoB;AAExB,SAAO,MAAM;AACX,QAAI,gBAAgB,WAAW,KAAK,YAAY;AAC9C,aAAO,KAAK;AAAA,IACd;AAEA,QAAI,gBAAgB,YAAY;AAC9B,aAAO;AAAA,IACT;AAEA,WAAO,KAAK;AAEZ,QAAI,CAAC,QAAQ,SAAS,UAAU;AAC9B;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAEO,IAAM,SAAS,CAAC,EAAE,SAAS,MAAM,SAAS,MAAqB;AACpE,QAAM,qBAAqB,OAAuB,IAAI;AACtD,QAAM,EAAE,aAAa,IAAI,YAAY;AAErC,QAAM,6BAA6B;AAAA,IACjC,MAAM,qBAAqB,QAAQ,cAAc,CAAC,GAAG,YAAY;AAAA,IACjE,CAAC,QAAQ,YAAY,YAAY;AAAA,EACnC;AAEA,QAAM,iBAAiB,QAAQ,MAAM;AACnC,WAAO;AAAA,MACL,GAAG;AAAA,MACH,YAAY;AAAA,MACZ;AAAA,IACF;AAAA,EACF,GAAG,CAAC,SAAS,MAAM,0BAA0B,CAAC;AAE9C,QAAM,aAAa,WAAW,cAAc;AAC5C,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAkC;AAE9D,YAAU,MAAM;AACd,UAAM,mBAAmB,qBAAqB,mBAAmB,OAAO;AACxE,UAAM,WAAW,IAAI,YAAY;AAAA,MAC/B,GAAG,WAAW;AAAA,MACd,WAAW,WAAW,QAAQ,aAAa;AAAA,IAC7C,CAAC;AACD,cAAU,QAAQ;AAElB,WAAO,MAAM;AACX,eAAS,QAAQ;AAAA,IACnB;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,YAAU,MAAM;AACd,QAAI,CAAC,QAAQ;AACX;AAAA,IACF;AAEA,UAAM,mBAAmB,qBAAqB,mBAAmB,OAAO;AACxE,WAAO,gBAAgB,QAAQ,aAAa,gBAAgB;AAC5D,WAAO,iBAAiB,0BAA0B;AAClD,WAAO,mBAAmB,QAAQ,YAAY;AAC9C,WAAO,WAAW,QAAQ,IAAI;AAC9B,WAAO,cAAc,QAAQ,OAAO;AACpC,WAAO,iBAAiB,QAAQ,UAAU;AAAA,EAC5C,GAAG;AAAA,IACD;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,EACV,CAAC;AAED,SACE,iCACE;AAAA,wBAAC,sBAAmB,KAAK,oBAAoB;AAAA,IAC5C,UAAU,oBAAC,kBAAe,OAAO,EAAE,OAAO,GAAI,UAAS;AAAA,KAC1D;AAEJ;","names":[]}
@@ -0,0 +1,5 @@
1
+ import React__default from 'react';
2
+
3
+ declare const ShadowRootDetector: React__default.ForwardRefExoticComponent<React__default.RefAttributes<HTMLDivElement>>;
4
+
5
+ export { ShadowRootDetector };
@@ -0,0 +1,28 @@
1
+ // src/components/ShadowRootDetector.tsx
2
+ import React from "react";
3
+ import { jsx } from "react/jsx-runtime";
4
+ var ShadowRootDetector = React.forwardRef((props, ref) => {
5
+ return /* @__PURE__ */ jsx(
6
+ "div",
7
+ {
8
+ ref,
9
+ style: {
10
+ position: "absolute",
11
+ width: 1,
12
+ height: 1,
13
+ padding: 0,
14
+ margin: -1,
15
+ overflow: "hidden",
16
+ clip: "rect(0, 0, 0, 0)",
17
+ whiteSpace: "nowrap",
18
+ borderWidth: 0
19
+ },
20
+ "data-shadow-root-detector": true,
21
+ ...props
22
+ }
23
+ );
24
+ });
25
+ export {
26
+ ShadowRootDetector
27
+ };
28
+ //# sourceMappingURL=ShadowRootDetector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/ShadowRootDetector.tsx"],"sourcesContent":["import React from 'react';\n\nexport const ShadowRootDetector = React.forwardRef<HTMLDivElement>((props, ref) => {\n return (\n <div\n ref={ref}\n style={{\n position: 'absolute',\n width: 1,\n height: 1,\n padding: 0,\n margin: -1,\n overflow: 'hidden',\n clip: 'rect(0, 0, 0, 0)',\n whiteSpace: 'nowrap',\n borderWidth: 0,\n }}\n data-shadow-root-detector\n {...props}\n />\n );\n});\n"],"mappings":";AAAA,OAAO,WAAW;AAId;AAFG,IAAM,qBAAqB,MAAM,WAA2B,CAAC,OAAO,QAAQ;AACjF,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,OAAO;AAAA,QACL,UAAU;AAAA,QACV,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,MAAM;AAAA,QACN,YAAY;AAAA,QACZ,aAAa;AAAA,MACf;AAAA,MACA,6BAAyB;AAAA,MACxB,GAAG;AAAA;AAAA,EACN;AAEJ,CAAC;","names":[]}
@@ -2,7 +2,7 @@
2
2
  import { Novu } from "@novu/js";
3
3
  import { createContext, useContext, useMemo } from "react";
4
4
  import { jsx } from "react/jsx-runtime";
5
- var version = "3.3.1";
5
+ var version = "3.5.0-rc.1";
6
6
  var name = "@novu/react";
7
7
  var baseUserAgent = `${name}@${version}`;
8
8
  var NovuContext = createContext(void 0);
@@ -2,6 +2,7 @@ import { Notification, NovuError } from '@novu/js';
2
2
 
3
3
  type UseNotificationsProps = {
4
4
  tags?: string[];
5
+ data?: Record<string, unknown>;
5
6
  read?: boolean;
6
7
  archived?: boolean;
7
8
  snoozed?: boolean;
@@ -3,7 +3,7 @@ import { useState, useEffect, useRef } from "react";
3
3
  import { isSameFilter } from "@novu/js";
4
4
  import { useNovu } from "./NovuProvider.js";
5
5
  var useNotifications = (props) => {
6
- const { tags, read, archived = false, snoozed = false, limit, onSuccess, onError } = props || {};
6
+ const { tags, data: dataFilter, read, archived = false, snoozed = false, limit, onSuccess, onError } = props || {};
7
7
  const filterRef = useRef(void 0);
8
8
  const { notifications, on } = useNovu();
9
9
  const [data, setData] = useState();
@@ -27,14 +27,14 @@ var useNotifications = (props) => {
27
27
  };
28
28
  }, []);
29
29
  useEffect(() => {
30
- const newFilter = { tags, read, archived, snoozed };
30
+ const newFilter = { tags, data: dataFilter, read, archived, snoozed };
31
31
  if (filterRef.current && isSameFilter(filterRef.current, newFilter)) {
32
32
  return;
33
33
  }
34
34
  notifications.clearCache({ filter: filterRef.current });
35
35
  filterRef.current = newFilter;
36
36
  fetchNotifications({ refetch: true });
37
- }, [tags, read, archived, snoozed]);
37
+ }, [tags, dataFilter, read, archived, snoozed]);
38
38
  const fetchNotifications = async (options) => {
39
39
  if (options?.refetch) {
40
40
  setError(void 0);
@@ -44,6 +44,7 @@ var useNotifications = (props) => {
44
44
  setIsFetching(true);
45
45
  const response = await notifications.list({
46
46
  tags,
47
+ data: dataFilter,
47
48
  read,
48
49
  archived,
49
50
  snoozed,
@@ -62,7 +63,7 @@ var useNotifications = (props) => {
62
63
  setIsFetching(false);
63
64
  };
64
65
  const refetch = () => {
65
- notifications.clearCache({ filter: { tags, read, archived, snoozed } });
66
+ notifications.clearCache({ filter: { tags, read, archived, snoozed, data: dataFilter } });
66
67
  return fetchNotifications({ refetch: true });
67
68
  };
68
69
  const fetchMore = async () => {
@@ -70,13 +71,13 @@ var useNotifications = (props) => {
70
71
  return fetchNotifications();
71
72
  };
72
73
  const readAll = async () => {
73
- return await notifications.readAll({ tags });
74
+ return await notifications.readAll({ tags, data: dataFilter });
74
75
  };
75
76
  const archiveAll = async () => {
76
- return await notifications.archiveAll({ tags });
77
+ return await notifications.archiveAll({ tags, data: dataFilter });
77
78
  };
78
79
  const archiveAllRead = async () => {
79
- return await notifications.archiveAllRead({ tags });
80
+ return await notifications.archiveAllRead({ tags, data: dataFilter });
80
81
  };
81
82
  return {
82
83
  readAll,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/hooks/useNotifications.ts"],"sourcesContent":["import { useState, useEffect, useRef } from 'react';\nimport { ListNotificationsResponse, Notification, NovuError, isSameFilter, NotificationFilter } from '@novu/js';\nimport { useNovu } from './NovuProvider';\n\nexport type UseNotificationsProps = {\n tags?: string[];\n read?: boolean;\n archived?: boolean;\n snoozed?: boolean;\n limit?: number;\n onSuccess?: (data: Notification[]) => void;\n onError?: (error: NovuError) => void;\n};\n\nexport type UseNotificationsResult = {\n notifications?: Notification[];\n error?: NovuError;\n isLoading: boolean;\n isFetching: boolean;\n hasMore: boolean;\n readAll: () => Promise<{\n data?: void | undefined;\n error?: NovuError | undefined;\n }>;\n archiveAll: () => Promise<{\n data?: void | undefined;\n error?: NovuError | undefined;\n }>;\n archiveAllRead: () => Promise<{\n data?: void | undefined;\n error?: NovuError | undefined;\n }>;\n refetch: () => Promise<void>;\n fetchMore: () => Promise<void>;\n};\n\nexport const useNotifications = (props?: UseNotificationsProps): UseNotificationsResult => {\n const { tags, read, archived = false, snoozed = false, limit, onSuccess, onError } = props || {};\n const filterRef = useRef<NotificationFilter | undefined>(undefined);\n const { notifications, on } = useNovu();\n const [data, setData] = useState<Array<Notification>>();\n const [error, setError] = useState<NovuError>();\n const [isLoading, setIsLoading] = useState(true);\n const [isFetching, setIsFetching] = useState(false);\n const [hasMore, setHasMore] = useState(false);\n const length = data?.length;\n const after = length ? data[length - 1].id : undefined;\n\n const sync = (event: { data?: ListNotificationsResponse }) => {\n if (!event.data || (filterRef.current && !isSameFilter(filterRef.current, event.data.filter))) {\n return;\n }\n setData(event.data.notifications);\n setHasMore(event.data.hasMore);\n };\n\n useEffect(() => {\n const cleanup = on('notifications.list.updated', sync);\n\n return () => {\n cleanup();\n };\n }, []);\n\n useEffect(() => {\n const newFilter = { tags, read, archived, snoozed };\n if (filterRef.current && isSameFilter(filterRef.current, newFilter)) {\n return;\n }\n notifications.clearCache({ filter: filterRef.current });\n filterRef.current = newFilter;\n\n fetchNotifications({ refetch: true });\n }, [tags, read, archived, snoozed]);\n\n const fetchNotifications = async (options?: { refetch: boolean }) => {\n if (options?.refetch) {\n setError(undefined);\n setIsLoading(true);\n setIsFetching(false);\n }\n setIsFetching(true);\n const response = await notifications.list({\n tags,\n read,\n archived,\n snoozed,\n limit,\n after: options?.refetch ? undefined : after,\n });\n if (response.error) {\n setError(response.error);\n onError?.(response.error);\n } else {\n onSuccess?.(response.data!.notifications);\n setData(response.data!.notifications);\n setHasMore(response.data!.hasMore);\n }\n setIsLoading(false);\n setIsFetching(false);\n };\n\n const refetch = () => {\n notifications.clearCache({ filter: { tags, read, archived, snoozed } });\n\n return fetchNotifications({ refetch: true });\n };\n\n const fetchMore = async () => {\n if (!hasMore || isFetching) return;\n\n return fetchNotifications();\n };\n\n const readAll = async () => {\n return await notifications.readAll({ tags });\n };\n\n const archiveAll = async () => {\n return await notifications.archiveAll({ tags });\n };\n\n const archiveAllRead = async () => {\n return await notifications.archiveAllRead({ tags });\n };\n\n return {\n readAll,\n archiveAll,\n archiveAllRead,\n notifications: data,\n error,\n isLoading,\n isFetching,\n refetch,\n fetchMore,\n hasMore,\n };\n};\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/hooks/useNotifications.ts"],"sourcesContent":["import { useState, useEffect, useRef } from 'react';\nimport { ListNotificationsResponse, Notification, NovuError, isSameFilter, NotificationFilter } from '@novu/js';\nimport { useNovu } from './NovuProvider';\n\nexport type UseNotificationsProps = {\n tags?: string[];\n data?: Record<string, unknown>;\n read?: boolean;\n archived?: boolean;\n snoozed?: boolean;\n limit?: number;\n onSuccess?: (data: Notification[]) => void;\n onError?: (error: NovuError) => void;\n};\n\nexport type UseNotificationsResult = {\n notifications?: Notification[];\n error?: NovuError;\n isLoading: boolean;\n isFetching: boolean;\n hasMore: boolean;\n readAll: () => Promise<{\n data?: void | undefined;\n error?: NovuError | undefined;\n }>;\n archiveAll: () => Promise<{\n data?: void | undefined;\n error?: NovuError | undefined;\n }>;\n archiveAllRead: () => Promise<{\n data?: void | undefined;\n error?: NovuError | undefined;\n }>;\n refetch: () => Promise<void>;\n fetchMore: () => Promise<void>;\n};\n\nexport const useNotifications = (props?: UseNotificationsProps): UseNotificationsResult => {\n const { tags, data: dataFilter, read, archived = false, snoozed = false, limit, onSuccess, onError } = props || {};\n const filterRef = useRef<NotificationFilter | undefined>(undefined);\n const { notifications, on } = useNovu();\n const [data, setData] = useState<Array<Notification>>();\n const [error, setError] = useState<NovuError>();\n const [isLoading, setIsLoading] = useState(true);\n const [isFetching, setIsFetching] = useState(false);\n const [hasMore, setHasMore] = useState(false);\n const length = data?.length;\n const after = length ? data[length - 1].id : undefined;\n\n const sync = (event: { data?: ListNotificationsResponse }) => {\n if (!event.data || (filterRef.current && !isSameFilter(filterRef.current, event.data.filter))) {\n return;\n }\n setData(event.data.notifications);\n setHasMore(event.data.hasMore);\n };\n\n useEffect(() => {\n const cleanup = on('notifications.list.updated', sync);\n\n return () => {\n cleanup();\n };\n }, []);\n\n useEffect(() => {\n const newFilter = { tags, data: dataFilter, read, archived, snoozed };\n if (filterRef.current && isSameFilter(filterRef.current, newFilter)) {\n return;\n }\n notifications.clearCache({ filter: filterRef.current });\n filterRef.current = newFilter;\n\n fetchNotifications({ refetch: true });\n }, [tags, dataFilter, read, archived, snoozed]);\n\n const fetchNotifications = async (options?: { refetch: boolean }) => {\n if (options?.refetch) {\n setError(undefined);\n setIsLoading(true);\n setIsFetching(false);\n }\n setIsFetching(true);\n const response = await notifications.list({\n tags,\n data: dataFilter,\n read,\n archived,\n snoozed,\n limit,\n after: options?.refetch ? undefined : after,\n });\n if (response.error) {\n setError(response.error);\n onError?.(response.error);\n } else {\n onSuccess?.(response.data!.notifications);\n setData(response.data!.notifications);\n setHasMore(response.data!.hasMore);\n }\n setIsLoading(false);\n setIsFetching(false);\n };\n\n const refetch = () => {\n notifications.clearCache({ filter: { tags, read, archived, snoozed, data: dataFilter } });\n\n return fetchNotifications({ refetch: true });\n };\n\n const fetchMore = async () => {\n if (!hasMore || isFetching) return;\n\n return fetchNotifications();\n };\n\n const readAll = async () => {\n return await notifications.readAll({ tags, data: dataFilter });\n };\n\n const archiveAll = async () => {\n return await notifications.archiveAll({ tags, data: dataFilter });\n };\n\n const archiveAllRead = async () => {\n return await notifications.archiveAllRead({ tags, data: dataFilter });\n };\n\n return {\n readAll,\n archiveAll,\n archiveAllRead,\n notifications: data,\n error,\n isLoading,\n isFetching,\n refetch,\n fetchMore,\n hasMore,\n };\n};\n"],"mappings":"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","names":[]}
@@ -1,5 +1,5 @@
1
1
  export { ChannelPreference, ChannelType, EventHandler, Events, FiltersCountResponse, InboxNotification, ListNotificationsResponse, Notification, NotificationFilter, NotificationStatus, NovuError, NovuOptions, Preference, PreferenceLevel, PreferencesResponse, SocketEventNames, WebSocketEvent } from '@novu/js';
2
- export { Appearance, AppearanceKey, ElementStyles, Elements, Localization, LocalizationKey, NotificationActionClickHandler, NotificationClickHandler, NotificationRenderer, PreferencesFilter, RouterPush, Tab, Variables } from '@novu/js/ui';
2
+ export { Appearance, AppearanceKey, ElementStyles, Elements, Localization, LocalizationKey, NotificationActionClickHandler, NotificationClickHandler, NotificationRenderer, PreferenceGroups, PreferencesFilter, RouterPush, Tab, Variables } from '@novu/js/ui';
3
3
  export { Bell, BellProps } from './components/Bell.js';
4
4
  export { Inbox, InboxProps } from './components/Inbox.js';
5
5
  export { Preferences } from './components/Preferences.js';