@vuu-ui/vuu-notifications 4.0.0-alpha.2 → 4.0.0-alpha.21

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/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "4.0.0-alpha.2",
2
+ "version": "4.0.0-alpha.21",
3
3
  "description": "VUU notifications - Toast, WorkspaceNotification etc",
4
4
  "main": "./src/index.js",
5
5
  "author": "heswell",
@@ -11,11 +11,11 @@
11
11
  "type-defs": "node ../../scripts/build-type-defs.mjs"
12
12
  },
13
13
  "dependencies": {
14
- "@salt-ds/core": "1.67.0",
15
- "@salt-ds/styles": "0.2.1",
16
- "@salt-ds/window": "0.1.1",
17
- "@vuu-ui/vuu-ui-controls": "4.0.0-alpha.2",
18
- "@vuu-ui/vuu-utils": "4.0.0-alpha.2"
14
+ "@salt-ds/core": "1.72.0",
15
+ "@salt-ds/styles": "0.4.1",
16
+ "@salt-ds/window": "0.1.2",
17
+ "@vuu-ui/vuu-ui-controls": "4.0.0-alpha.21",
18
+ "@vuu-ui/vuu-utils": "4.0.0-alpha.21"
19
19
  },
20
20
  "peerDependencies": {
21
21
  "clsx": "^2.0.0",
@@ -30,8 +30,9 @@
30
30
  ],
31
31
  "exports": {
32
32
  ".": {
33
+ "types": "./types/index.d.ts",
33
34
  "import": "./src/index.js",
34
- "types": "./types/index.d.ts"
35
+ "default": "./src/index.js"
35
36
  }
36
37
  },
37
38
  "module": "./src/index.js",
@@ -95,15 +95,9 @@ const NotificationsCenter = ({ notificationsContext, startupToastNotification })
95
95
  return newToast;
96
96
  }
97
97
  }));
98
- if (scheduledUpdate) {
99
- const updateNotifications = notificationsRef.current.map((n)=>{
100
- if (n.id === scheduledUpdate?.id) return scheduledUpdate;
101
- return n;
102
- });
103
- requestAnimationFrame(()=>{
104
- setNotifications(updateNotifications);
105
- });
106
- }
98
+ if (scheduledUpdate) requestAnimationFrame(()=>{
99
+ setNotifications(notificationsRef.current.map((n)=>n.id === scheduledUpdate?.id ? scheduledUpdate : n));
100
+ });
107
101
  }, [
108
102
  setNotifications
109
103
  ]);
@@ -1,26 +1,47 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
- import react, { useContext, useMemo } from "react";
3
- import { NotificationsCenter } from "./NotificationsCenter.js";
4
2
  import { getLocalEntity } from "@vuu-ui/vuu-utils";
3
+ import { createContext, useContext, useMemo, useState } from "react";
4
+ import { NotificationsCenter } from "./NotificationsCenter.js";
5
+ const globalContext = (name, defaultValue)=>{
6
+ const key = Symbol.for(name);
7
+ const contexts = globalThis;
8
+ let context = contexts[key];
9
+ if (void 0 === context) {
10
+ context = /*#__PURE__*/ createContext(defaultValue);
11
+ contexts[key] = context;
12
+ }
13
+ return context;
14
+ };
5
15
  class NotificationsContextObject {
6
16
  #showNotification = ()=>{
7
17
  console.log("have you forgotten to provide a NotificationsCenter?");
8
18
  };
9
19
  #hideNotification = ()=>console.log("have you forgotten to provide a NotificationsCenter?");
10
- showNotification = (notification)=>this.#showNotification(notification);
20
+ interceptor = void 0;
21
+ showNotification = (notification)=>this.interceptor?.(notification) === "suppress" ? void 0 : this.#showNotification(notification);
11
22
  hideNotification = (id)=>this.#hideNotification(id);
12
23
  setNotify = (showNotificationDispatcher, hideNotificationDispatcher)=>{
13
24
  this.#showNotification = showNotificationDispatcher;
14
25
  this.#hideNotification = hideNotificationDispatcher;
15
26
  };
16
27
  }
17
- const NotificationsContext = /*#__PURE__*/ react.createContext(new NotificationsContextObject());
18
- const NotificationsProvider = (props)=>{
19
- const context = useContext(NotificationsContext);
28
+ const NotificationsContext = globalContext("vuu.notifications.context", null);
29
+ const NotificationOriginContext = globalContext("vuu.notifications.origin", void 0);
30
+ const noProvider = new NotificationsContextObject();
31
+ const NotificationsProvider = ({ children, interceptor })=>{
32
+ const outerContext = useContext(NotificationsContext);
33
+ return outerContext ? children : /*#__PURE__*/ jsx(OutermostNotificationsProvider, {
34
+ interceptor: interceptor,
35
+ children: children
36
+ });
37
+ };
38
+ const OutermostNotificationsProvider = ({ children, interceptor })=>{
39
+ const [context] = useState(()=>new NotificationsContextObject());
40
+ context.interceptor = interceptor;
20
41
  const startupToastNotification = useMemo(()=>{
21
42
  const toast = getLocalEntity("startup-notification", true);
22
43
  if (toast && toast.expires >= +Date.now()) {
23
- const { expires, ...toastDescriptor } = toast;
44
+ const { expires: _expires, ...toastDescriptor } = toast;
24
45
  return toastDescriptor;
25
46
  }
26
47
  }, []);
@@ -31,15 +52,41 @@ const NotificationsProvider = (props)=>{
31
52
  startupToastNotification: startupToastNotification,
32
53
  notificationsContext: context
33
54
  }),
34
- props.children
55
+ children
35
56
  ]
36
57
  });
37
58
  };
59
+ const NotificationOriginProvider = ({ children, connectionId, moduleId })=>{
60
+ const outerOrigin = useContext(NotificationOriginContext);
61
+ const outerModuleId = outerOrigin?.moduleId ?? outerOrigin?.parentModuleId;
62
+ const parentModuleId = outerModuleId !== moduleId ? outerModuleId : outerOrigin?.parentModuleId;
63
+ const origin = useMemo(()=>({
64
+ connectionId,
65
+ moduleId,
66
+ parentModuleId
67
+ }), [
68
+ connectionId,
69
+ moduleId,
70
+ parentModuleId
71
+ ]);
72
+ return /*#__PURE__*/ jsx(NotificationOriginContext.Provider, {
73
+ value: origin,
74
+ children: children
75
+ });
76
+ };
77
+ const useNotificationOrigin = ()=>useContext(NotificationOriginContext);
38
78
  const useNotifications = ()=>{
39
- const { hideNotification, showNotification } = useContext(NotificationsContext);
40
- return {
41
- hideNotification,
42
- showNotification
43
- };
79
+ const context = useContext(NotificationsContext) ?? noProvider;
80
+ const origin = useContext(NotificationOriginContext);
81
+ return useMemo(()=>({
82
+ hideNotification: context.hideNotification,
83
+ showNotification: origin ? (notification)=>context.showNotification(notification.origin ? notification : {
84
+ ...notification,
85
+ origin
86
+ }) : context.showNotification
87
+ }), [
88
+ context,
89
+ origin
90
+ ]);
44
91
  };
45
- export { NotificationsProvider, useNotifications };
92
+ export { NotificationOriginProvider, NotificationsProvider, useNotificationOrigin, useNotifications };
package/src/index.js CHANGED
@@ -1,3 +1,3 @@
1
- export { NotificationType } from "./NotificationsContext.js";
2
- export { NotificationsProvider, useNotifications } from "./NotificationsProvider.js";
1
+ export { NotificationType, isToastNotification, isWorkspaceNotification } from "./NotificationsContext.js";
2
+ export { NotificationOriginProvider, NotificationsProvider, useNotificationOrigin, useNotifications } from "./NotificationsProvider.js";
3
3
  export { ToastNotification } from "./ToastNotification.js";
@@ -3,4 +3,4 @@ export interface NotificationsCenterProps {
3
3
  notificationsContext: NotificationsContextProps;
4
4
  startupToastNotification?: ToastNotificationDescriptor;
5
5
  }
6
- export declare const NotificationsCenter: ({ notificationsContext, startupToastNotification, }: NotificationsCenterProps) => import("react").JSX.Element;
6
+ export declare const NotificationsCenter: ({ notificationsContext, startupToastNotification, }: NotificationsCenterProps) => import("react/jsx-runtime").JSX.Element;
@@ -10,6 +10,18 @@ export declare const NotificationType: {
10
10
  export type NotificationType = ValueOf<typeof NotificationType>;
11
11
  export type DismissalStyle = "automatic" | "manual";
12
12
  export type NotificationAnimationType = "slide-in" | "slide-out" | "slide-in,slide-out";
13
+ /**
14
+ * Where a notification was raised. Filled in by `useNotifications` from the
15
+ * nearest `NotificationOriginProvider`, e.g. the portal module rendering the
16
+ * caller.
17
+ */
18
+ export interface NotificationOrigin {
19
+ moduleId?: string | number;
20
+ /** The Vuu server the module uses. */
21
+ connectionId?: string;
22
+ /** The module hosting the origin's module, for nested modules. */
23
+ parentModuleId?: string | number;
24
+ }
13
25
  interface NotificationDescriptorBase<T extends NotificationType> {
14
26
  animationType?: NotificationAnimationType;
15
27
  /**
@@ -23,6 +35,13 @@ interface NotificationDescriptorBase<T extends NotificationType> {
23
35
  * Default icons will be rendered for the different status values.
24
36
  */
25
37
  icon?: string | false;
38
+ /** Set automatically by `useNotifications`, when a provider gives one. */
39
+ origin?: NotificationOrigin;
40
+ /**
41
+ * Whether a host that keeps a notification history (e.g. a portal) should
42
+ * record this notification. Hosts choose the default.
43
+ */
44
+ record?: boolean;
26
45
  renderPostRefresh?: boolean;
27
46
  showCloseButton?: boolean;
28
47
  status: ValidationStatus;
@@ -39,6 +58,12 @@ export interface WorkspaceNotificationDescriptor extends NotificationDescriptorB
39
58
  export type Notification = ToastNotificationDescriptor | WorkspaceNotificationDescriptor;
40
59
  export declare const isToastNotification: (n: Notification) => n is ToastNotificationDescriptor;
41
60
  export declare const isWorkspaceNotification: (n: Notification) => n is WorkspaceNotificationDescriptor;
61
+ /**
62
+ * Decides whether a notification is shown. Given to the outermost
63
+ * `NotificationsProvider`, it sees every notification raised beneath it,
64
+ * including those raised inside nested providers.
65
+ */
66
+ export type NotificationInterceptor = (notification: Notification) => "present" | "suppress";
42
67
  export type NotificationsContextProps = {
43
68
  hideNotification: DispatchHideNotification;
44
69
  showNotification: DispatchShowNotification;
@@ -1,8 +1,29 @@
1
- import React, { type ReactElement } from "react";
2
- import type { DispatchHideNotification, DispatchShowNotification } from "./NotificationsContext";
3
- export declare const NotificationsProvider: (props: {
4
- children: ReactElement | ReactElement[];
5
- }) => React.JSX.Element;
1
+ import { type ReactNode } from "react";
2
+ import type { DispatchHideNotification, DispatchShowNotification, NotificationInterceptor, NotificationOrigin } from "./NotificationsContext";
3
+ export interface NotificationsProviderProps {
4
+ children?: ReactNode;
5
+ /**
6
+ * Sees every notification raised beneath the provider before it is shown.
7
+ * Only used by the outermost provider.
8
+ */
9
+ interceptor?: NotificationInterceptor;
10
+ }
11
+ /**
12
+ * Shows the notifications raised beneath it. Inside another
13
+ * `NotificationsProvider` it renders only its children, so notifications
14
+ * from nested applications are shown, once, by the outermost provider.
15
+ */
16
+ export declare const NotificationsProvider: ({ children, interceptor, }: NotificationsProviderProps) => string | number | bigint | boolean | import("react/jsx-runtime").JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | Iterable<ReactNode> | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | import("react").ReactPortal | null | undefined> | null | undefined;
17
+ /**
18
+ * Tags notifications raised beneath it with their origin. A nested provider
19
+ * records the enclosing origin's module as its `parentModuleId`.
20
+ */
21
+ export declare const NotificationOriginProvider: ({ children, connectionId, moduleId, }: {
22
+ children?: ReactNode;
23
+ connectionId?: string;
24
+ moduleId?: string | number;
25
+ }) => import("react/jsx-runtime").JSX.Element;
26
+ export declare const useNotificationOrigin: () => NotificationOrigin | undefined;
6
27
  export declare const useNotifications: () => {
7
28
  hideNotification: DispatchHideNotification;
8
29
  showNotification: DispatchShowNotification;
@@ -12,4 +12,4 @@ export type ToastNotificationProps = {
12
12
  opacity?: number;
13
13
  top?: number;
14
14
  };
15
- export declare const ToastNotification: ({ hidden, id, left, onDismiss, onMeasured, top, notification, onHoverEntry, onHoverExit, opacity, }: ToastNotificationProps) => import("react").JSX.Element;
15
+ export declare const ToastNotification: ({ hidden, id, left, onDismiss, onMeasured, top, notification, onHoverEntry, onHoverExit, opacity, }: ToastNotificationProps) => import("react/jsx-runtime").JSX.Element;
@@ -2,4 +2,4 @@ import { HTMLAttributes, ReactNode } from "react";
2
2
  export interface WorkspaceNotificationProps extends HTMLAttributes<HTMLDivElement> {
3
3
  children: ReactNode;
4
4
  }
5
- export declare const WorkspaceNotification: ({ children, className, style: styleProp, ...htmlAttributes }: WorkspaceNotificationProps) => import("react").JSX.Element;
5
+ export declare const WorkspaceNotification: ({ children, className, style: styleProp, ...htmlAttributes }: WorkspaceNotificationProps) => import("react/jsx-runtime").JSX.Element;
package/types/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export { NotificationType, type Notification, type NotificationAnimationType, } from "./NotificationsContext";
2
- export { NotificationsProvider, useNotifications, } from "./NotificationsProvider";
1
+ export { NotificationType, type Notification, type NotificationAnimationType, type NotificationInterceptor, type NotificationOrigin, type ToastNotificationDescriptor, type WorkspaceNotificationDescriptor, isToastNotification, isWorkspaceNotification, } from "./NotificationsContext";
2
+ export { NotificationOriginProvider, NotificationsProvider, type NotificationsProviderProps, useNotificationOrigin, useNotifications, } from "./NotificationsProvider";
3
3
  export { ToastNotification, type ToastNotificationProps, } from "./ToastNotification";