@novu/react 2.3.0 → 2.3.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.
@@ -0,0 +1,34 @@
1
+ import React from 'react';
2
+ import { InboxNotification } from '@novu/js';
3
+ import { BaseNovuUIOptions } from '@novu/js/ui';
4
+
5
+ type BellRenderProps = ({ unreadCount }: {
6
+ unreadCount: number;
7
+ }) => React.ReactNode;
8
+ type BellProps$1 = {
9
+ children?: never | BellRenderProps;
10
+ };
11
+ declare const Bell: (props: BellProps$1) => React.JSX.Element;
12
+
13
+ type InboxDefaultProps = {
14
+ renderNotification?: (notification: InboxNotification) => React.ReactNode;
15
+ renderBell?: ({ unreadCount }: {
16
+ unreadCount: number;
17
+ }) => React.ReactNode;
18
+ };
19
+ type InboxProps = BaseNovuUIOptions & (({
20
+ children?: never;
21
+ } & InboxDefaultProps) | {
22
+ children: React.ReactNode;
23
+ });
24
+ declare const Inbox: (props: InboxProps) => React.JSX.Element;
25
+
26
+ declare const Settings: () => React.JSX.Element;
27
+
28
+ type NotificationsRenderProps = (notification: InboxNotification) => React.ReactNode;
29
+ type BellProps = {
30
+ children?: never | NotificationsRenderProps;
31
+ };
32
+ declare const Notifications: (props: BellProps) => React.JSX.Element;
33
+
34
+ export { Bell, Inbox, Notifications, Settings };
@@ -0,0 +1,34 @@
1
+ import React from 'react';
2
+ import { InboxNotification } from '@novu/js';
3
+ import { BaseNovuUIOptions } from '@novu/js/ui';
4
+
5
+ type BellRenderProps = ({ unreadCount }: {
6
+ unreadCount: number;
7
+ }) => React.ReactNode;
8
+ type BellProps$1 = {
9
+ children?: never | BellRenderProps;
10
+ };
11
+ declare const Bell: (props: BellProps$1) => React.JSX.Element;
12
+
13
+ type InboxDefaultProps = {
14
+ renderNotification?: (notification: InboxNotification) => React.ReactNode;
15
+ renderBell?: ({ unreadCount }: {
16
+ unreadCount: number;
17
+ }) => React.ReactNode;
18
+ };
19
+ type InboxProps = BaseNovuUIOptions & (({
20
+ children?: never;
21
+ } & InboxDefaultProps) | {
22
+ children: React.ReactNode;
23
+ });
24
+ declare const Inbox: (props: InboxProps) => React.JSX.Element;
25
+
26
+ declare const Settings: () => React.JSX.Element;
27
+
28
+ type NotificationsRenderProps = (notification: InboxNotification) => React.ReactNode;
29
+ type BellProps = {
30
+ children?: never | NotificationsRenderProps;
31
+ };
32
+ declare const Notifications: (props: BellProps) => React.JSX.Element;
33
+
34
+ export { Bell, Inbox, Notifications, Settings };
package/dist/index.js ADDED
@@ -0,0 +1,167 @@
1
+ 'use strict';
2
+
3
+ var React5 = require('react');
4
+ var ReactDOM = require('react-dom');
5
+
6
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
7
+
8
+ var React5__default = /*#__PURE__*/_interopDefault(React5);
9
+ var ReactDOM__default = /*#__PURE__*/_interopDefault(ReactDOM);
10
+
11
+ // src/components/Bell.tsx
12
+ function assertContextExists(contextVal, msgOrCtx) {
13
+ if (!contextVal) {
14
+ throw typeof msgOrCtx === "string" ? new Error(msgOrCtx) : new Error(`${msgOrCtx.displayName} not found`);
15
+ }
16
+ }
17
+ var createContextAndHook = (displayName, options) => {
18
+ const { assertCtxFn = assertContextExists } = {};
19
+ const Ctx = React5__default.default.createContext(void 0);
20
+ Ctx.displayName = displayName;
21
+ const useCtx = () => {
22
+ const ctx = React5__default.default.useContext(Ctx);
23
+ assertCtxFn(ctx, `${displayName} not found`);
24
+ return ctx.value;
25
+ };
26
+ const useCtxWithoutGuarantee = () => {
27
+ const ctx = React5__default.default.useContext(Ctx);
28
+ return ctx ? ctx.value : {};
29
+ };
30
+ return [Ctx, useCtx, useCtxWithoutGuarantee];
31
+ };
32
+
33
+ // src/context/RenderContext.tsx
34
+ var [RendererContext, useRendererContext] = createContextAndHook("RendererContext");
35
+ var RendererProvider = (props) => {
36
+ return /* @__PURE__ */ React5__default.default.createElement(RendererContext.Provider, { value: { value: props.value } }, props.children);
37
+ };
38
+ function Mounter({ mount }) {
39
+ const ref = React5__default.default.useRef(null);
40
+ React5__default.default.useEffect(() => {
41
+ let unmount;
42
+ const element = ref.current;
43
+ if (element && mount) {
44
+ const possibleUnmount = mount(element);
45
+ if (possibleUnmount) {
46
+ unmount = possibleUnmount;
47
+ }
48
+ }
49
+ return () => {
50
+ if (element && unmount) {
51
+ unmount(element);
52
+ }
53
+ };
54
+ }, [ref, mount]);
55
+ return /* @__PURE__ */ React5__default.default.createElement("div", { ref });
56
+ }
57
+
58
+ // src/components/Bell.tsx
59
+ var Bell = (props) => {
60
+ const { novuUI, mountElement } = useRendererContext();
61
+ const mount = React5__default.default.useCallback((element) => {
62
+ return novuUI.mountComponent({
63
+ name: "Bell",
64
+ element,
65
+ props: props.children ? { mountBell: (el, { unreadCount }) => mountElement(el, props.children?.({ unreadCount })) } : void 0
66
+ });
67
+ }, []);
68
+ return /* @__PURE__ */ React5__default.default.createElement(Mounter, { mount });
69
+ };
70
+ var Renderer = (props) => {
71
+ const { options, children } = props;
72
+ const [novuUI, setNovuUI] = React5__default.default.useState();
73
+ const [mountedElements, setMountedElements] = React5__default.default.useState(/* @__PURE__ */ new Map());
74
+ const mountElement = React5__default.default.useCallback(
75
+ (el, mountedElement) => {
76
+ setMountedElements((prev) => {
77
+ const newMountedElements = new Map(prev);
78
+ newMountedElements.set(el, mountedElement);
79
+ return newMountedElements;
80
+ });
81
+ return () => {
82
+ setMountedElements((prev) => {
83
+ const newMountedElements = new Map(prev);
84
+ newMountedElements.delete(el);
85
+ return newMountedElements;
86
+ });
87
+ };
88
+ },
89
+ [setMountedElements]
90
+ );
91
+ React5__default.default.useEffect(() => {
92
+ const loadNovuUI = async () => {
93
+ const { NovuUI } = await import('@novu/js/ui');
94
+ const ui = new NovuUI(options);
95
+ setNovuUI(ui);
96
+ };
97
+ loadNovuUI();
98
+ }, [options]);
99
+ if (!novuUI) {
100
+ return null;
101
+ }
102
+ return /* @__PURE__ */ React5__default.default.createElement(RendererProvider, { value: { mountElement, novuUI } }, [...mountedElements].map(([element, mountedElement]) => {
103
+ return ReactDOM__default.default.createPortal(mountedElement, element);
104
+ }), children);
105
+ };
106
+
107
+ // src/components/Inbox.tsx
108
+ var InboxDefault = (props) => {
109
+ const { renderNotification, renderBell, ...rest } = props;
110
+ const { novuUI, mountElement } = useRendererContext();
111
+ const mount = React5__default.default.useCallback(
112
+ (element) => {
113
+ return novuUI.mountComponent({
114
+ name: "Inbox",
115
+ props: {
116
+ ...rest,
117
+ mountNotification: renderNotification ? (el, { notification }) => {
118
+ return mountElement(el, renderNotification(notification));
119
+ } : void 0,
120
+ mountBell: renderBell ? (el, { unreadCount }) => {
121
+ return mountElement(el, renderBell({ unreadCount }));
122
+ } : void 0
123
+ },
124
+ element
125
+ });
126
+ },
127
+ [renderNotification]
128
+ );
129
+ return /* @__PURE__ */ React5__default.default.createElement(Mounter, { mount });
130
+ };
131
+ var Inbox = (props) => {
132
+ if ("children" in props) {
133
+ const { children, ...options2 } = props;
134
+ return /* @__PURE__ */ React5__default.default.createElement(Renderer, { options: options2 }, children);
135
+ }
136
+ const { renderNotification, renderBell, ...options } = props;
137
+ return /* @__PURE__ */ React5__default.default.createElement(Renderer, { options }, /* @__PURE__ */ React5__default.default.createElement(InboxDefault, { renderNotification, renderBell }));
138
+ };
139
+ var SettingsDefault = () => {
140
+ const { novuUI } = useRendererContext();
141
+ const mount = React5__default.default.useCallback((element) => {
142
+ return novuUI.mountComponent({
143
+ name: "Settings",
144
+ element
145
+ });
146
+ }, []);
147
+ return /* @__PURE__ */ React5__default.default.createElement(Mounter, { mount });
148
+ };
149
+ var Settings = () => {
150
+ return /* @__PURE__ */ React5__default.default.createElement(SettingsDefault, null);
151
+ };
152
+ var Notifications = (props) => {
153
+ const { novuUI, mountElement } = useRendererContext();
154
+ const mount = React5__default.default.useCallback((element) => {
155
+ return novuUI.mountComponent({
156
+ name: "NotificationList",
157
+ element,
158
+ props: props.children ? { mountNotification: (el, { notification }) => mountElement(el, props.children?.(notification)) } : void 0
159
+ });
160
+ }, []);
161
+ return /* @__PURE__ */ React5__default.default.createElement(Mounter, { mount });
162
+ };
163
+
164
+ exports.Bell = Bell;
165
+ exports.Inbox = Inbox;
166
+ exports.Notifications = Notifications;
167
+ exports.Settings = Settings;
package/dist/index.mjs ADDED
@@ -0,0 +1,157 @@
1
+ import React5 from 'react';
2
+ import ReactDOM from 'react-dom';
3
+
4
+ // src/components/Bell.tsx
5
+ function assertContextExists(contextVal, msgOrCtx) {
6
+ if (!contextVal) {
7
+ throw typeof msgOrCtx === "string" ? new Error(msgOrCtx) : new Error(`${msgOrCtx.displayName} not found`);
8
+ }
9
+ }
10
+ var createContextAndHook = (displayName, options) => {
11
+ const { assertCtxFn = assertContextExists } = {};
12
+ const Ctx = React5.createContext(void 0);
13
+ Ctx.displayName = displayName;
14
+ const useCtx = () => {
15
+ const ctx = React5.useContext(Ctx);
16
+ assertCtxFn(ctx, `${displayName} not found`);
17
+ return ctx.value;
18
+ };
19
+ const useCtxWithoutGuarantee = () => {
20
+ const ctx = React5.useContext(Ctx);
21
+ return ctx ? ctx.value : {};
22
+ };
23
+ return [Ctx, useCtx, useCtxWithoutGuarantee];
24
+ };
25
+
26
+ // src/context/RenderContext.tsx
27
+ var [RendererContext, useRendererContext] = createContextAndHook("RendererContext");
28
+ var RendererProvider = (props) => {
29
+ return /* @__PURE__ */ React5.createElement(RendererContext.Provider, { value: { value: props.value } }, props.children);
30
+ };
31
+ function Mounter({ mount }) {
32
+ const ref = React5.useRef(null);
33
+ React5.useEffect(() => {
34
+ let unmount;
35
+ const element = ref.current;
36
+ if (element && mount) {
37
+ const possibleUnmount = mount(element);
38
+ if (possibleUnmount) {
39
+ unmount = possibleUnmount;
40
+ }
41
+ }
42
+ return () => {
43
+ if (element && unmount) {
44
+ unmount(element);
45
+ }
46
+ };
47
+ }, [ref, mount]);
48
+ return /* @__PURE__ */ React5.createElement("div", { ref });
49
+ }
50
+
51
+ // src/components/Bell.tsx
52
+ var Bell = (props) => {
53
+ const { novuUI, mountElement } = useRendererContext();
54
+ const mount = React5.useCallback((element) => {
55
+ return novuUI.mountComponent({
56
+ name: "Bell",
57
+ element,
58
+ props: props.children ? { mountBell: (el, { unreadCount }) => mountElement(el, props.children?.({ unreadCount })) } : void 0
59
+ });
60
+ }, []);
61
+ return /* @__PURE__ */ React5.createElement(Mounter, { mount });
62
+ };
63
+ var Renderer = (props) => {
64
+ const { options, children } = props;
65
+ const [novuUI, setNovuUI] = React5.useState();
66
+ const [mountedElements, setMountedElements] = React5.useState(/* @__PURE__ */ new Map());
67
+ const mountElement = React5.useCallback(
68
+ (el, mountedElement) => {
69
+ setMountedElements((prev) => {
70
+ const newMountedElements = new Map(prev);
71
+ newMountedElements.set(el, mountedElement);
72
+ return newMountedElements;
73
+ });
74
+ return () => {
75
+ setMountedElements((prev) => {
76
+ const newMountedElements = new Map(prev);
77
+ newMountedElements.delete(el);
78
+ return newMountedElements;
79
+ });
80
+ };
81
+ },
82
+ [setMountedElements]
83
+ );
84
+ React5.useEffect(() => {
85
+ const loadNovuUI = async () => {
86
+ const { NovuUI } = await import('@novu/js/ui');
87
+ const ui = new NovuUI(options);
88
+ setNovuUI(ui);
89
+ };
90
+ loadNovuUI();
91
+ }, [options]);
92
+ if (!novuUI) {
93
+ return null;
94
+ }
95
+ return /* @__PURE__ */ React5.createElement(RendererProvider, { value: { mountElement, novuUI } }, [...mountedElements].map(([element, mountedElement]) => {
96
+ return ReactDOM.createPortal(mountedElement, element);
97
+ }), children);
98
+ };
99
+
100
+ // src/components/Inbox.tsx
101
+ var InboxDefault = (props) => {
102
+ const { renderNotification, renderBell, ...rest } = props;
103
+ const { novuUI, mountElement } = useRendererContext();
104
+ const mount = React5.useCallback(
105
+ (element) => {
106
+ return novuUI.mountComponent({
107
+ name: "Inbox",
108
+ props: {
109
+ ...rest,
110
+ mountNotification: renderNotification ? (el, { notification }) => {
111
+ return mountElement(el, renderNotification(notification));
112
+ } : void 0,
113
+ mountBell: renderBell ? (el, { unreadCount }) => {
114
+ return mountElement(el, renderBell({ unreadCount }));
115
+ } : void 0
116
+ },
117
+ element
118
+ });
119
+ },
120
+ [renderNotification]
121
+ );
122
+ return /* @__PURE__ */ React5.createElement(Mounter, { mount });
123
+ };
124
+ var Inbox = (props) => {
125
+ if ("children" in props) {
126
+ const { children, ...options2 } = props;
127
+ return /* @__PURE__ */ React5.createElement(Renderer, { options: options2 }, children);
128
+ }
129
+ const { renderNotification, renderBell, ...options } = props;
130
+ return /* @__PURE__ */ React5.createElement(Renderer, { options }, /* @__PURE__ */ React5.createElement(InboxDefault, { renderNotification, renderBell }));
131
+ };
132
+ var SettingsDefault = () => {
133
+ const { novuUI } = useRendererContext();
134
+ const mount = React5.useCallback((element) => {
135
+ return novuUI.mountComponent({
136
+ name: "Settings",
137
+ element
138
+ });
139
+ }, []);
140
+ return /* @__PURE__ */ React5.createElement(Mounter, { mount });
141
+ };
142
+ var Settings = () => {
143
+ return /* @__PURE__ */ React5.createElement(SettingsDefault, null);
144
+ };
145
+ var Notifications = (props) => {
146
+ const { novuUI, mountElement } = useRendererContext();
147
+ const mount = React5.useCallback((element) => {
148
+ return novuUI.mountComponent({
149
+ name: "NotificationList",
150
+ element,
151
+ props: props.children ? { mountNotification: (el, { notification }) => mountElement(el, props.children?.(notification)) } : void 0
152
+ });
153
+ }, []);
154
+ return /* @__PURE__ */ React5.createElement(Mounter, { mount });
155
+ };
156
+
157
+ export { Bell, Inbox, Notifications, Settings };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@novu/react",
3
- "version": "2.3.0",
3
+ "version": "2.3.1",
4
4
  "repository": "https://github.com/novuhq/novu",
5
5
  "description": "Novu's React SDK for building custom inbox notification experiences",
6
6
  "author": "",
@@ -33,7 +33,7 @@
33
33
  "default": "./dist/hooks/index.js"
34
34
  }
35
35
  },
36
- "./themes": {
36
+ "./themes": {
37
37
  "import": {
38
38
  "types": "./dist/themes/index.d.mts",
39
39
  "default": "./dist/themes/index.mjs"
@@ -62,8 +62,7 @@
62
62
  "build:watch": "tsup --watch",
63
63
  "build": "tsup && pnpm run check-exports",
64
64
  "lint": "eslint src",
65
- "check-exports": "attw --pack .",
66
- "release:preview": "pnpx pkg-pr-new publish"
65
+ "check-exports": "attw --pack ."
67
66
  },
68
67
  "browserslist": {
69
68
  "production": [
@@ -95,6 +94,9 @@
95
94
  }
96
95
  },
97
96
  "dependencies": {
98
- "@novu/js": "^2.3.0"
97
+ "@novu/js": "^2.3.1"
98
+ },
99
+ "nx": {
100
+ "tags": ["package:public"]
99
101
  }
100
102
  }