no-frills-ui 0.0.14-alpha.1 → 0.0.14-alpha.11

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 (222) hide show
  1. package/README.md +28 -22
  2. package/dist/index.js +3418 -2772
  3. package/dist/index.js.map +1 -1
  4. package/lib-esm/components/Accordion/Accordion.d.ts +11 -16
  5. package/lib-esm/components/Accordion/Accordion.js +25 -29
  6. package/lib-esm/components/Accordion/Accordion.js.map +1 -1
  7. package/lib-esm/components/Accordion/AccordionStep.d.ts +22 -22
  8. package/lib-esm/components/Accordion/AccordionStep.js +111 -109
  9. package/lib-esm/components/Accordion/AccordionStep.js.map +1 -1
  10. package/lib-esm/components/Badge/Badge.d.ts +13 -16
  11. package/lib-esm/components/Badge/Badge.js +31 -51
  12. package/lib-esm/components/Badge/Badge.js.map +1 -1
  13. package/lib-esm/components/Button/ActionButton.d.ts +9 -5
  14. package/lib-esm/components/Button/ActionButton.js +18 -38
  15. package/lib-esm/components/Button/ActionButton.js.map +1 -1
  16. package/lib-esm/components/Button/Button.d.ts +9 -5
  17. package/lib-esm/components/Button/Button.js +18 -40
  18. package/lib-esm/components/Button/Button.js.map +1 -1
  19. package/lib-esm/components/Button/IconButton.d.ts +9 -5
  20. package/lib-esm/components/Button/IconButton.js +18 -42
  21. package/lib-esm/components/Button/IconButton.js.map +1 -1
  22. package/lib-esm/components/Button/LinkButton.d.ts +9 -5
  23. package/lib-esm/components/Button/LinkButton.js +18 -32
  24. package/lib-esm/components/Button/LinkButton.js.map +1 -1
  25. package/lib-esm/components/Button/RaisedButton.d.ts +9 -5
  26. package/lib-esm/components/Button/RaisedButton.js +18 -46
  27. package/lib-esm/components/Button/RaisedButton.js.map +1 -1
  28. package/lib-esm/components/Card/Card.d.ts +4 -6
  29. package/lib-esm/components/Card/Card.js +18 -13
  30. package/lib-esm/components/Card/Card.js.map +1 -1
  31. package/lib-esm/components/Chip/Chip.d.ts +6 -3
  32. package/lib-esm/components/Chip/Chip.js +44 -43
  33. package/lib-esm/components/Chip/Chip.js.map +1 -1
  34. package/lib-esm/components/ChipInput/ChipInput.d.ts +28 -30
  35. package/lib-esm/components/ChipInput/ChipInput.js +121 -139
  36. package/lib-esm/components/ChipInput/ChipInput.js.map +1 -1
  37. package/lib-esm/components/Dialog/AlertDialog.d.ts +11 -12
  38. package/lib-esm/components/Dialog/AlertDialog.js +44 -28
  39. package/lib-esm/components/Dialog/AlertDialog.js.map +1 -1
  40. package/lib-esm/components/Dialog/ConfirmDialog.d.ts +13 -14
  41. package/lib-esm/components/Dialog/ConfirmDialog.js +49 -33
  42. package/lib-esm/components/Dialog/ConfirmDialog.js.map +1 -1
  43. package/lib-esm/components/Dialog/Dialog.d.ts +40 -18
  44. package/lib-esm/components/Dialog/Dialog.js +125 -70
  45. package/lib-esm/components/Dialog/Dialog.js.map +1 -1
  46. package/lib-esm/components/Dialog/PromptDialog.d.ts +18 -19
  47. package/lib-esm/components/Dialog/PromptDialog.js +78 -49
  48. package/lib-esm/components/Dialog/PromptDialog.js.map +1 -1
  49. package/lib-esm/components/DragAndDrop/DragAndDrop.d.ts +43 -41
  50. package/lib-esm/components/DragAndDrop/DragAndDrop.js +104 -31
  51. package/lib-esm/components/DragAndDrop/DragAndDrop.js.map +1 -1
  52. package/lib-esm/components/DragAndDrop/DragItem.d.ts +5 -1
  53. package/lib-esm/components/DragAndDrop/DragItem.js +171 -92
  54. package/lib-esm/components/DragAndDrop/DragItem.js.map +1 -1
  55. package/lib-esm/components/DragAndDrop/types.d.ts +22 -3
  56. package/lib-esm/components/DragAndDrop/types.js +9 -6
  57. package/lib-esm/components/DragAndDrop/types.js.map +1 -1
  58. package/lib-esm/components/Drawer/Drawer.d.ts +86 -22
  59. package/lib-esm/components/Drawer/Drawer.js +176 -97
  60. package/lib-esm/components/Drawer/Drawer.js.map +1 -1
  61. package/lib-esm/components/Drawer/index.d.ts +1 -1
  62. package/lib-esm/components/Groups/Group.d.ts +5 -8
  63. package/lib-esm/components/Groups/Group.js +34 -79
  64. package/lib-esm/components/Groups/Group.js.map +1 -1
  65. package/lib-esm/components/Groups/GroupLabel.js +8 -17
  66. package/lib-esm/components/Groups/GroupLabel.js.map +1 -1
  67. package/lib-esm/components/Input/Checkbox.d.ts +12 -15
  68. package/lib-esm/components/Input/Checkbox.js +51 -118
  69. package/lib-esm/components/Input/Checkbox.js.map +1 -1
  70. package/lib-esm/components/Input/Dropdown.d.ts +11 -12
  71. package/lib-esm/components/Input/Dropdown.js +133 -52
  72. package/lib-esm/components/Input/Dropdown.js.map +1 -1
  73. package/lib-esm/components/Input/Input.d.ts +3 -3
  74. package/lib-esm/components/Input/Input.js +61 -109
  75. package/lib-esm/components/Input/Input.js.map +1 -1
  76. package/lib-esm/components/Input/Radio.d.ts +4 -8
  77. package/lib-esm/components/Input/Radio.js +35 -79
  78. package/lib-esm/components/Input/Radio.js.map +1 -1
  79. package/lib-esm/components/Input/RadioButton.d.ts +4 -8
  80. package/lib-esm/components/Input/RadioButton.js +34 -71
  81. package/lib-esm/components/Input/RadioButton.js.map +1 -1
  82. package/lib-esm/components/Input/Select.d.ts +6 -13
  83. package/lib-esm/components/Input/Select.js +75 -122
  84. package/lib-esm/components/Input/Select.js.map +1 -1
  85. package/lib-esm/components/Input/TextArea.d.ts +6 -13
  86. package/lib-esm/components/Input/TextArea.js +64 -108
  87. package/lib-esm/components/Input/TextArea.js.map +1 -1
  88. package/lib-esm/components/Input/Toggle.d.ts +4 -9
  89. package/lib-esm/components/Input/Toggle.js +31 -80
  90. package/lib-esm/components/Input/Toggle.js.map +1 -1
  91. package/lib-esm/components/Menu/Menu.d.ts +8 -6
  92. package/lib-esm/components/Menu/Menu.js +116 -31
  93. package/lib-esm/components/Menu/Menu.js.map +1 -1
  94. package/lib-esm/components/Menu/MenuContext.d.ts +11 -5
  95. package/lib-esm/components/Menu/MenuContext.js +6 -2
  96. package/lib-esm/components/Menu/MenuContext.js.map +1 -1
  97. package/lib-esm/components/Menu/MenuItem.d.ts +7 -4
  98. package/lib-esm/components/Menu/MenuItem.js +46 -47
  99. package/lib-esm/components/Menu/MenuItem.js.map +1 -1
  100. package/lib-esm/components/Modal/Modal.d.ts +75 -16
  101. package/lib-esm/components/Modal/Modal.js +146 -51
  102. package/lib-esm/components/Modal/Modal.js.map +1 -1
  103. package/lib-esm/components/Notification/Notification.d.ts +46 -39
  104. package/lib-esm/components/Notification/Notification.js +80 -87
  105. package/lib-esm/components/Notification/Notification.js.map +1 -1
  106. package/lib-esm/components/Notification/NotificationManager.d.ts +19 -5
  107. package/lib-esm/components/Notification/NotificationManager.js +177 -79
  108. package/lib-esm/components/Notification/NotificationManager.js.map +1 -1
  109. package/lib-esm/components/Notification/style.d.ts +6 -3
  110. package/lib-esm/components/Notification/style.js +64 -140
  111. package/lib-esm/components/Notification/style.js.map +1 -1
  112. package/lib-esm/components/Notification/types.d.ts +2 -0
  113. package/lib-esm/components/Notification/types.js +9 -10
  114. package/lib-esm/components/Notification/types.js.map +1 -1
  115. package/lib-esm/components/Popover/Popover.d.ts +21 -20
  116. package/lib-esm/components/Popover/Popover.js +159 -126
  117. package/lib-esm/components/Popover/Popover.js.map +1 -1
  118. package/lib-esm/components/Spinner/Spinner.d.ts +14 -12
  119. package/lib-esm/components/Spinner/Spinner.js +22 -27
  120. package/lib-esm/components/Spinner/Spinner.js.map +1 -1
  121. package/lib-esm/components/Stepper/Step.d.ts +15 -12
  122. package/lib-esm/components/Stepper/Step.js +18 -25
  123. package/lib-esm/components/Stepper/Step.js.map +1 -1
  124. package/lib-esm/components/Stepper/Stepper.d.ts +11 -17
  125. package/lib-esm/components/Stepper/Stepper.js +104 -102
  126. package/lib-esm/components/Stepper/Stepper.js.map +1 -1
  127. package/lib-esm/components/Tabs/Tab.d.ts +10 -16
  128. package/lib-esm/components/Tabs/Tab.js +9 -15
  129. package/lib-esm/components/Tabs/Tab.js.map +1 -1
  130. package/lib-esm/components/Tabs/Tabs.d.ts +11 -22
  131. package/lib-esm/components/Tabs/Tabs.js +96 -55
  132. package/lib-esm/components/Tabs/Tabs.js.map +1 -1
  133. package/lib-esm/components/Toast/Toast.d.ts +34 -7
  134. package/lib-esm/components/Toast/Toast.js +200 -109
  135. package/lib-esm/components/Toast/Toast.js.map +1 -1
  136. package/lib-esm/components/Toast/ToastStory.d.ts +21 -24
  137. package/lib-esm/components/Tooltip/Tooltip.d.ts +11 -14
  138. package/lib-esm/components/Tooltip/Tooltip.js +52 -67
  139. package/lib-esm/components/Tooltip/Tooltip.js.map +1 -1
  140. package/lib-esm/components/index.d.ts +1 -0
  141. package/lib-esm/icons/CheckCircle.d.ts +1 -1
  142. package/lib-esm/icons/CheckCircle.js +22 -4
  143. package/lib-esm/icons/CheckCircle.js.map +1 -1
  144. package/lib-esm/icons/Close.d.ts +1 -1
  145. package/lib-esm/icons/Close.js +22 -4
  146. package/lib-esm/icons/Close.js.map +1 -1
  147. package/lib-esm/icons/DragIndicator.d.ts +1 -1
  148. package/lib-esm/icons/DragIndicator.js +22 -4
  149. package/lib-esm/icons/DragIndicator.js.map +1 -1
  150. package/lib-esm/icons/ErrorOutline.d.ts +1 -1
  151. package/lib-esm/icons/ErrorOutline.js +16 -4
  152. package/lib-esm/icons/ErrorOutline.js.map +1 -1
  153. package/lib-esm/icons/ExpandMore.d.ts +1 -1
  154. package/lib-esm/icons/ExpandMore.js +22 -4
  155. package/lib-esm/icons/ExpandMore.js.map +1 -1
  156. package/lib-esm/icons/FiberManualRecord.d.ts +1 -1
  157. package/lib-esm/icons/FiberManualRecord.js +24 -4
  158. package/lib-esm/icons/FiberManualRecord.js.map +1 -1
  159. package/lib-esm/icons/Info.d.ts +1 -1
  160. package/lib-esm/icons/Info.js +22 -4
  161. package/lib-esm/icons/Info.js.map +1 -1
  162. package/lib-esm/icons/ReportProblem.d.ts +1 -1
  163. package/lib-esm/icons/ReportProblem.js +22 -4
  164. package/lib-esm/icons/ReportProblem.js.map +1 -1
  165. package/lib-esm/index.js +43 -2
  166. package/lib-esm/index.js.map +1 -1
  167. package/lib-esm/shared/LayerManager.d.ts +34 -4
  168. package/lib-esm/shared/LayerManager.js +248 -114
  169. package/lib-esm/shared/LayerManager.js.map +1 -1
  170. package/lib-esm/shared/constants.d.ts +58 -27
  171. package/lib-esm/shared/constants.js +62 -26
  172. package/lib-esm/shared/constants.js.map +1 -1
  173. package/lib-esm/shared/styles.d.ts +1 -1
  174. package/lib-esm/shared/styles.js +21 -24
  175. package/lib-esm/shared/styles.js.map +1 -1
  176. package/package.json +130 -74
  177. package/lib-esm/components/Accordion/index.js +0 -3
  178. package/lib-esm/components/Accordion/index.js.map +0 -1
  179. package/lib-esm/components/Badge/index.js +0 -2
  180. package/lib-esm/components/Badge/index.js.map +0 -1
  181. package/lib-esm/components/Button/index.js +0 -6
  182. package/lib-esm/components/Button/index.js.map +0 -1
  183. package/lib-esm/components/Card/index.js +0 -3
  184. package/lib-esm/components/Card/index.js.map +0 -1
  185. package/lib-esm/components/Chip/index.js +0 -2
  186. package/lib-esm/components/Chip/index.js.map +0 -1
  187. package/lib-esm/components/ChipInput/index.js +0 -2
  188. package/lib-esm/components/ChipInput/index.js.map +0 -1
  189. package/lib-esm/components/Dialog/index.js +0 -5
  190. package/lib-esm/components/Dialog/index.js.map +0 -1
  191. package/lib-esm/components/DragAndDrop/index.js +0 -3
  192. package/lib-esm/components/DragAndDrop/index.js.map +0 -1
  193. package/lib-esm/components/Drawer/index.js +0 -2
  194. package/lib-esm/components/Drawer/index.js.map +0 -1
  195. package/lib-esm/components/Groups/index.js +0 -3
  196. package/lib-esm/components/Groups/index.js.map +0 -1
  197. package/lib-esm/components/Input/index.js +0 -9
  198. package/lib-esm/components/Input/index.js.map +0 -1
  199. package/lib-esm/components/Menu/index.js +0 -3
  200. package/lib-esm/components/Menu/index.js.map +0 -1
  201. package/lib-esm/components/Modal/index.js +0 -2
  202. package/lib-esm/components/Modal/index.js.map +0 -1
  203. package/lib-esm/components/Notification/index.js +0 -3
  204. package/lib-esm/components/Notification/index.js.map +0 -1
  205. package/lib-esm/components/Popover/index.js +0 -2
  206. package/lib-esm/components/Popover/index.js.map +0 -1
  207. package/lib-esm/components/Spinner/index.js +0 -2
  208. package/lib-esm/components/Spinner/index.js.map +0 -1
  209. package/lib-esm/components/Stepper/index.js +0 -4
  210. package/lib-esm/components/Stepper/index.js.map +0 -1
  211. package/lib-esm/components/Tabs/index.js +0 -3
  212. package/lib-esm/components/Tabs/index.js.map +0 -1
  213. package/lib-esm/components/Toast/ToastStory.js +0 -35
  214. package/lib-esm/components/Toast/ToastStory.js.map +0 -1
  215. package/lib-esm/components/Toast/index.js +0 -2
  216. package/lib-esm/components/Toast/index.js.map +0 -1
  217. package/lib-esm/components/Tooltip/index.js +0 -2
  218. package/lib-esm/components/Tooltip/index.js.map +0 -1
  219. package/lib-esm/components/index.js +0 -20
  220. package/lib-esm/components/index.js.map +0 -1
  221. package/lib-esm/icons/index.js +0 -9
  222. package/lib-esm/icons/index.js.map +0 -1
@@ -1,111 +1,104 @@
1
- import { jsx as _jsx } from "@emotion/react/jsx-runtime";
2
- import React, { createRef } from 'react';
3
- import PropTypes from 'prop-types';
4
- import ReactDOM from 'react-dom';
5
- import LayerManager, { LAYER_POSITION } from '../../shared/LayerManager';
6
- import NotificationManager from './NotificationManager';
7
- import { NOTIFICATION_POSITION, NOTIFICATION_TYPE } from './types';
8
- /** This component is only used for storybook documentation */
9
- export class StoryProps extends React.Component {
10
- render() {
11
- return null;
12
- }
13
- }
14
- StoryProps.propTypes = {
15
- /** Title of the notification */
16
- title: PropTypes.string.isRequired,
17
- /** Body of the notification */
18
- description: PropTypes.string.isRequired,
19
- /** Id for the notification, helps in de-duplication. */
20
- id: PropTypes.string,
21
- /** Duration for the notification in milliseconds */
22
- duration: PropTypes.number,
23
- /** Creates sticky notification */
24
- sticky: PropTypes.bool,
25
- /** Type of notification */
26
- type: PropTypes.oneOf([
27
- NOTIFICATION_TYPE.INFO,
28
- NOTIFICATION_TYPE.SUCCESS,
29
- NOTIFICATION_TYPE.WARNING,
30
- NOTIFICATION_TYPE.DANGER,
31
- ]),
32
- /** Action button text */
33
- buttonText: PropTypes.string,
34
- /** Action button click callback */
35
- buttonClick: PropTypes.func,
36
- /** Notification close callback. */
37
- onClose: PropTypes.func,
38
- };
39
- StoryProps.defaultProps = {
40
- duration: 5000,
41
- sticky: false,
42
- type: NOTIFICATION_TYPE.INFO,
43
- };
44
- /** Maps notification position to layer position */
45
- const positionMap = {
1
+ import { jsx } from '@emotion/react/jsx-runtime';
2
+ import { flushSync } from 'react-dom';
3
+ import { createRoot } from 'react-dom/client';
4
+ import LayerManager, { LAYER_POSITION } from '../../shared/LayerManager.js';
5
+ import NotificationManager from './NotificationManager.js';
6
+ import { NOTIFICATION_POSITION } from './types.js';
7
+
8
+ /** Maps notification position to layer position */ const positionMap = {
46
9
  [NOTIFICATION_POSITION.TOP_LEFT]: LAYER_POSITION.TOP_LEFT,
47
10
  [NOTIFICATION_POSITION.TOP_RIGHT]: LAYER_POSITION.TOP_RIGHT,
48
11
  [NOTIFICATION_POSITION.BOTTOM_LEFT]: LAYER_POSITION.BOTTOM_LEFT,
49
- [NOTIFICATION_POSITION.BOTTOM_RIGHT]: LAYER_POSITION.BOTTOM_RIGHT,
12
+ [NOTIFICATION_POSITION.BOTTOM_RIGHT]: LAYER_POSITION.BOTTOM_RIGHT
50
13
  };
51
- /** Notification class */
52
- class Notification {
53
- constructor() {
54
- /** Helps in maintaining single instance for different positions. */
55
- this.containers = new Map();
14
+ /** Notification class */ class Notification {
15
+ constructor(){
16
+ /** Helps in maintaining single instance for different positions. */ this.containers = new Map();
56
17
  /**
57
- * Adds a notification
58
- *
59
- * @param position
60
- * @param options
61
- */
62
- this.add = (position, options) => {
63
- let notification;
18
+ * Adds a notification
19
+ *
20
+ * @param position - The position where the notification should appear
21
+ * @param options - Configuration options for the notification
22
+ * @returns The notification ID or a promise that resolves to the notification ID
23
+ */ this.add = (position, options, ariaLabel = 'Notifications')=>{
64
24
  if (!this.containers.has(position)) {
65
- const div = document === null || document === void 0 ? void 0 : document.createElement('div');
66
- const ref = createRef();
25
+ /** Callback ref to capture the NotificationManager instance when it mounts */ const refCallback = (instance)=>{
26
+ if (instance) {
27
+ const container = this.containers.get(position);
28
+ if (container) {
29
+ container.manager = instance;
30
+ }
31
+ }
32
+ };
67
33
  const [Component] = LayerManager.renderLayer({
68
34
  closeOnEsc: false,
69
35
  closeOnOverlayClick: false,
70
36
  position: positionMap[position],
71
37
  alwaysOnTop: true,
72
- component: (_jsx(NotificationManager, { ref: ref, position: position, onEmpty: () => this.destroy(position) }))
38
+ component: /*#__PURE__*/ jsx(NotificationManager, {
39
+ ref: refCallback,
40
+ position: position,
41
+ onEmpty: ()=>this.destroy(position),
42
+ ariaLabel: ariaLabel
43
+ })
73
44
  });
45
+ // Create a div to mount the Component
46
+ const div = document.createElement('div');
47
+ document.body.appendChild(div);
48
+ const root = createRoot(div);
74
49
  this.containers.set(position, {
75
- ref,
76
- element: div,
50
+ manager: null,
51
+ root,
52
+ div
53
+ });
54
+ // Render the Component which will trigger the LayerManager's useEffect
55
+ flushSync(()=>{
56
+ root.render(/*#__PURE__*/ jsx(Component, {}));
77
57
  });
78
- ReactDOM.render(_jsx(Component, {}), div);
79
- notification = ref;
80
58
  }
81
- else {
82
- notification = this.containers.get(position).ref;
59
+ const container = this.containers.get(position);
60
+ if (container && container.manager) {
61
+ return container.manager.add(options);
83
62
  }
84
- return notification.current.add(options);
63
+ // If manager is not ready yet, wait a bit and retry
64
+ return new Promise((resolve)=>{
65
+ setTimeout(()=>{
66
+ const container = this.containers.get(position);
67
+ if (container && container.manager) {
68
+ resolve(container.manager.add(options));
69
+ }
70
+ }, 10);
71
+ });
85
72
  };
86
73
  /**
87
- * Removes a notification
88
- *
89
- * @param position
90
- * @param id
91
- */
92
- this.remove = (position, id) => {
93
- if (this.containers.has(position)) {
94
- this.containers.get(position).ref.current.remove(id);
74
+ * Removes a notification
75
+ *
76
+ * @param position - The position of the notification container
77
+ * @param id - The unique ID of the notification to remove
78
+ */ this.remove = (position, id)=>{
79
+ const container = this.containers.get(position);
80
+ if (container && container.manager) {
81
+ container.manager.remove(id);
95
82
  }
96
83
  };
97
84
  /**
98
- * Destroys entire stack of notifications.
99
- *
100
- * @param position
101
- */
102
- this.destroy = (position) => {
103
- const notification = this.containers.get(position);
104
- ReactDOM.unmountComponentAtNode(notification.element);
105
- this.containers.delete(position);
85
+ * Destroys entire stack of notifications at a position.
86
+ * Unmounts the React root and cleans up DOM elements.
87
+ *
88
+ * @param position - The position of the notification container to destroy
89
+ */ this.destroy = (position)=>{
90
+ const container = this.containers.get(position);
91
+ if (container) {
92
+ container.root.unmount();
93
+ if (document.body.contains(container.div)) {
94
+ document.body.removeChild(container.div);
95
+ }
96
+ this.containers.delete(position);
97
+ }
106
98
  };
107
99
  }
108
100
  }
109
- /** Export a singleton instance */
110
- export default new Notification();
111
- //# sourceMappingURL=Notification.js.map
101
+ /** Export a singleton instance */ var Notification_default = new Notification();
102
+
103
+ export { Notification_default as default };
104
+ //# sourceMappingURL=Notification.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Notification.js","sourceRoot":"","sources":["../../../src/components/Notification/Notification.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Notification.js","sources":["../../../src/components/Notification/Notification.tsx"],"sourcesContent":["import { type RefCallback } from 'react';\nimport { flushSync } from 'react-dom';\nimport { createRoot, type Root } from 'react-dom/client';\nimport LayerManager, { LAYER_POSITION } from '../../shared/LayerManager';\nimport NotificationManager from './NotificationManager';\nimport { NOTIFICATION_POSITION, NOTIFICATION_TYPE, NotificationOptions } from './types';\n\ntype NotificationProps = {\n /** Title of the notification */\n title: string;\n /** Body of the notification */\n description: string;\n /** Id for the notification, helps in de-duplication. */\n id?: string;\n /**\n * Duration for the notification in milliseconds\n * @default 5000\n */\n duration?: number;\n /**\n * Creates sticky notification\n * @default false\n */\n sticky?: boolean;\n /**\n * Type of notification\n * @default NOTIFICATION_TYPE.INFO\n */\n type?: NOTIFICATION_TYPE;\n /** Action button text */\n buttonText?: string;\n /** Action button click callback */\n buttonClick?: () => void;\n /** Notification close callback. */\n onClose?: () => void;\n /** Aria label for the close button on the notification. Defaults to \"Close notification\" */\n closeButtonAriaLabel?: string;\n};\n\n/**\n * This dummy component is used to extract props for documentation in Storybook.\n * @param props\n * @returns\n */\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nexport function StoryProps(props: NotificationProps) {\n return null;\n}\n\n/** Maps notification position to layer position */\nconst positionMap = {\n [NOTIFICATION_POSITION.TOP_LEFT]: LAYER_POSITION.TOP_LEFT,\n [NOTIFICATION_POSITION.TOP_RIGHT]: LAYER_POSITION.TOP_RIGHT,\n [NOTIFICATION_POSITION.BOTTOM_LEFT]: LAYER_POSITION.BOTTOM_LEFT,\n [NOTIFICATION_POSITION.BOTTOM_RIGHT]: LAYER_POSITION.BOTTOM_RIGHT,\n};\n\n/** Notification class */\nclass Notification {\n /** Helps in maintaining single instance for different positions. */\n private containers: Map<\n NOTIFICATION_POSITION,\n {\n manager: NotificationManager | null;\n root: Root;\n div: HTMLDivElement;\n }\n > = new Map();\n\n /**\n * Adds a notification\n *\n * @param position - The position where the notification should appear\n * @param options - Configuration options for the notification\n * @returns The notification ID or a promise that resolves to the notification ID\n */\n public add = (\n position: NOTIFICATION_POSITION,\n options: NotificationOptions,\n ariaLabel: string = 'Notifications',\n ) => {\n if (!this.containers.has(position)) {\n /** Callback ref to capture the NotificationManager instance when it mounts */\n const refCallback: RefCallback<NotificationManager> = (instance) => {\n if (instance) {\n const container = this.containers.get(position);\n if (container) {\n container.manager = instance;\n }\n }\n };\n\n const [Component] = LayerManager.renderLayer({\n closeOnEsc: false,\n closeOnOverlayClick: false,\n position: positionMap[position],\n alwaysOnTop: true,\n component: (\n <NotificationManager\n ref={refCallback}\n position={position}\n onEmpty={() => this.destroy(position)}\n ariaLabel={ariaLabel}\n />\n ),\n });\n\n // Create a div to mount the Component\n const div = document.createElement('div');\n document.body.appendChild(div);\n const root = createRoot(div);\n\n this.containers.set(position, {\n manager: null,\n root,\n div,\n });\n\n // Render the Component which will trigger the LayerManager's useEffect\n flushSync(() => {\n root.render(<Component />);\n });\n }\n\n const container = this.containers.get(position);\n if (container && container.manager) {\n return container.manager.add(options);\n }\n\n // If manager is not ready yet, wait a bit and retry\n return new Promise<string>((resolve) => {\n setTimeout(() => {\n const container = this.containers.get(position);\n if (container && container.manager) {\n resolve(container.manager.add(options));\n }\n }, 10);\n });\n };\n\n /**\n * Removes a notification\n *\n * @param position - The position of the notification container\n * @param id - The unique ID of the notification to remove\n */\n public remove = (position: NOTIFICATION_POSITION, id: string) => {\n const container = this.containers.get(position);\n if (container && container.manager) {\n container.manager.remove(id);\n }\n };\n\n /**\n * Destroys entire stack of notifications at a position.\n * Unmounts the React root and cleans up DOM elements.\n *\n * @param position - The position of the notification container to destroy\n */\n public destroy = (position: NOTIFICATION_POSITION) => {\n const container = this.containers.get(position);\n if (container) {\n container.root.unmount();\n if (document.body.contains(container.div)) {\n document.body.removeChild(container.div);\n }\n this.containers.delete(position);\n }\n };\n}\n\n/** Export a singleton instance */\nexport default new Notification();\n"],"names":["positionMap","NOTIFICATION_POSITION","TOP_LEFT","LAYER_POSITION","TOP_RIGHT","BOTTOM_LEFT","BOTTOM_RIGHT","Notification","containers","Map","add","position","options","ariaLabel","has","refCallback","instance","container","get","manager","Component","LayerManager","renderLayer","closeOnEsc","closeOnOverlayClick","alwaysOnTop","component","_jsx","NotificationManager","ref","onEmpty","destroy","div","document","createElement","body","appendChild","root","createRoot","set","flushSync","render","Promise","resolve","setTimeout","remove","id","unmount","contains","removeChild","delete"],"mappings":"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"}
@@ -3,6 +3,7 @@ import { NOTIFICATION_POSITION, NotificationOptions } from './types';
3
3
  interface NotificationManagerProps {
4
4
  position: NOTIFICATION_POSITION;
5
5
  onEmpty: () => void;
6
+ ariaLabel?: string;
6
7
  }
7
8
  interface NoticeProp extends NotificationOptions {
8
9
  leaving?: boolean;
@@ -17,36 +18,49 @@ declare class NotificationManager extends React.Component<NotificationManagerPro
17
18
  state: NotificationManagerState;
18
19
  private timeouts;
19
20
  private set;
21
+ private politeRegionRef;
22
+ private assertiveRegionRef;
20
23
  /**
21
24
  * Removes a notification from stack if the notification with the given id is found.
22
25
  *
23
26
  * @param id
24
27
  */
25
- remove: (id: string) => void;
28
+ remove: (id?: string) => void;
26
29
  /**
27
30
  * Adds a notification to stack.
28
31
  *
29
32
  * @param notice
30
33
  */
31
- add: (notice: NotificationOptions) => string;
34
+ add: (notice: NotificationOptions) => Promise<string>;
35
+ /**
36
+ * Update live region content with clear-then-set pattern for reliable VoiceOver announcements.
37
+ *
38
+ * @param content - The text content to announce
39
+ * @param isAssertive - Whether to use assertive (alert) or polite (log) live region
40
+ */
41
+ private updateLiveRegion;
32
42
  /**
33
43
  * Handler for close button click.
34
44
  *
35
45
  * @param id
36
46
  */
37
- closeClickHandler: (id: string) => () => void;
47
+ closeClickHandler: (id?: string) => () => void;
38
48
  /**
39
49
  * Pause notification when user is hovering over it.
40
50
  *
41
51
  * @param id
42
52
  */
43
- pause: (id: string) => () => void;
53
+ pause: (id?: string) => () => void;
44
54
  /**
45
55
  * Restart the removal of notification.
46
56
  *
47
57
  * @param id
48
58
  */
49
- resume: (id: string) => () => void;
59
+ resume: (id?: string) => () => void;
60
+ /**
61
+ * Clean up all pending timeouts when component unmounts
62
+ */
63
+ componentWillUnmount(): void;
50
64
  render(): import("@emotion/react/jsx-runtime").JSX.Element;
51
65
  }
52
66
  export default NotificationManager;
@@ -1,52 +1,137 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
1
+ import { jsxs, jsx } from '@emotion/react/jsx-runtime';
2
2
  import React from 'react';
3
- import { NOTIFICATION_TYPE } from './types';
4
- import { Close, Info, ReportProblem, ErrorOutline, CheckCircle } from '../../icons';
5
- import { Container, Notice, Title, IconContainer, FillParent, Body, CloseButton, Footer } from './style';
6
- import { ActionButton } from '../Button';
7
- const DEFAULT_DURATION = 5000;
3
+ import { Container, VisuallyHidden, Notice, IconContainer, FillParent, Title, Body, Footer, CloseButton } from './style.js';
4
+ import { NOTIFICATION_TYPE } from './types.js';
5
+ import CheckCircle from '../../icons/Info.js';
6
+ import CheckCircle$1 from '../../icons/CheckCircle.js';
7
+ import CheckCircle$2 from '../../icons/ReportProblem.js';
8
+ import CheckCircle$3 from '../../icons/ErrorOutline.js';
9
+ import ActionButton from '../Button/ActionButton.js';
10
+ import Close from '../../icons/Close.js';
11
+
12
+ const DEFAULT_DURATION$1 = 5000;
8
13
  /**
9
14
  * Notification Manager class
10
- */
11
- class NotificationManager extends React.Component {
12
- constructor() {
13
- super(...arguments);
14
- this.state = {
15
- notices: [],
16
- };
17
- // bookkeeping for timeouts
15
+ */ class NotificationManager extends React.Component {
16
+ /**
17
+ * Clean up all pending timeouts when component unmounts
18
+ */ componentWillUnmount() {
19
+ // Clear all pending timeouts
20
+ Object.keys(this.timeouts).forEach((id)=>{
21
+ clearTimeout(this.timeouts[id]);
22
+ });
18
23
  this.timeouts = {};
19
- // Set of notification ids
20
- this.set = new Set();
21
- /**
22
- * Removes a notification from stack if the notification with the given id is found.
23
- *
24
- * @param id
25
- */
26
- this.remove = (id) => {
24
+ this.set.clear();
25
+ }
26
+ render() {
27
+ return /*#__PURE__*/ jsxs(Container, {
28
+ position: this.props.position,
29
+ children: [
30
+ /*#__PURE__*/ jsx(VisuallyHidden, {
31
+ ref: this.politeRegionRef,
32
+ role: "log",
33
+ "aria-live": "polite",
34
+ "aria-atomic": "false",
35
+ "aria-relevant": "additions text"
36
+ }),
37
+ /*#__PURE__*/ jsx(VisuallyHidden, {
38
+ ref: this.assertiveRegionRef,
39
+ role: "alert",
40
+ "aria-live": "assertive",
41
+ "aria-atomic": "true"
42
+ }),
43
+ /*#__PURE__*/ jsx("div", {
44
+ role: "list",
45
+ "aria-label": this.props.ariaLabel,
46
+ children: this.state.notices.map((notice)=>{
47
+ const { id, title, description, leaving, type = NOTIFICATION_TYPE.INFO, buttonText, buttonClick, closeButtonAriaLabel } = notice;
48
+ return /*#__PURE__*/ jsxs(Notice, {
49
+ ...notice,
50
+ position: this.props.position,
51
+ className: leaving ? 'leave' : '',
52
+ onMouseEnter: this.pause(id),
53
+ onMouseLeave: this.resume(id),
54
+ role: "listitem",
55
+ children: [
56
+ /*#__PURE__*/ jsxs(IconContainer, {
57
+ type: type,
58
+ "aria-hidden": "true",
59
+ children: [
60
+ type === NOTIFICATION_TYPE.INFO && /*#__PURE__*/ jsx(CheckCircle, {}),
61
+ type === NOTIFICATION_TYPE.SUCCESS && /*#__PURE__*/ jsx(CheckCircle$1, {}),
62
+ type === NOTIFICATION_TYPE.WARNING && /*#__PURE__*/ jsx(CheckCircle$2, {}),
63
+ type === NOTIFICATION_TYPE.DANGER && /*#__PURE__*/ jsx(CheckCircle$3, {})
64
+ ]
65
+ }),
66
+ /*#__PURE__*/ jsxs(FillParent, {
67
+ children: [
68
+ /*#__PURE__*/ jsx(Title, {
69
+ type: type,
70
+ children: title
71
+ }),
72
+ /*#__PURE__*/ jsx(Body, {
73
+ children: description
74
+ }),
75
+ buttonText && /*#__PURE__*/ jsx(Footer, {
76
+ children: /*#__PURE__*/ jsx(ActionButton, {
77
+ onClick: ()=>{
78
+ buttonClick?.();
79
+ },
80
+ children: buttonText
81
+ })
82
+ })
83
+ ]
84
+ }),
85
+ /*#__PURE__*/ jsx(CloseButton, {
86
+ onClick: this.closeClickHandler(id),
87
+ "aria-label": closeButtonAriaLabel || 'Close notification',
88
+ tabIndex: 0,
89
+ children: /*#__PURE__*/ jsx(Close, {})
90
+ })
91
+ ]
92
+ }, id);
93
+ })
94
+ })
95
+ ]
96
+ });
97
+ }
98
+ constructor(...args){
99
+ super(...args), this.state = {
100
+ notices: []
101
+ }, // bookkeeping for timeouts
102
+ this.timeouts = {}, // Set of notification ids
103
+ this.set = new Set(), // Refs for live regions to ensure they exist before updates
104
+ this.politeRegionRef = /*#__PURE__*/ React.createRef(), this.assertiveRegionRef = /*#__PURE__*/ React.createRef(), /**
105
+ * Removes a notification from stack if the notification with the given id is found.
106
+ *
107
+ * @param id
108
+ */ this.remove = (id)=>{
109
+ if (!id) return;
27
110
  // Trigger leaving animation.
28
111
  this.setState({
29
- notices: this.state.notices.map(notice => (Object.assign(Object.assign({}, notice), { leaving: notice.id === id ? true : notice.leaving })))
112
+ notices: this.state.notices.map((notice)=>({
113
+ ...notice,
114
+ leaving: notice.id === id ? true : notice.leaving
115
+ }))
30
116
  });
31
117
  this.set.delete(id);
32
118
  // Remove notification on animation completion.
33
- setTimeout(() => {
34
- const notice = this.state.notices.find(notice => notice.id === id);
119
+ setTimeout(()=>{
120
+ const notice = this.state.notices.find((notice)=>notice.id === id);
35
121
  if (notice) {
36
122
  // call close callback, ignore any errors in callback.
37
123
  if (notice.onClose) {
38
124
  try {
39
125
  notice.onClose();
40
- }
41
- catch (e) {
126
+ } catch (e) {
42
127
  console.warn('Error in notification close callback', e.message);
43
128
  }
44
129
  }
45
130
  // Remove the notification
46
131
  this.setState({
47
- notices: this.state.notices.filter(notice => notice.id !== id),
48
- }, () => {
49
- // Check if the stack is empty and then call the
132
+ notices: this.state.notices.filter((notice)=>notice.id !== id)
133
+ }, ()=>{
134
+ // Check if the stack is empty and then call the
50
135
  // empty callback function.
51
136
  if (this.state.notices.length === 0) {
52
137
  this.props.onEmpty();
@@ -54,67 +139,80 @@ class NotificationManager extends React.Component {
54
139
  });
55
140
  }
56
141
  }, 550);
57
- };
58
- /**
59
- * Adds a notification to stack.
60
- *
61
- * @param notice
62
- */
63
- this.add = (notice) => {
142
+ }, /**
143
+ * Adds a notification to stack.
144
+ *
145
+ * @param notice
146
+ */ this.add = async (notice)=>{
64
147
  // Generate unique id if not provided.
65
- const id = notice.id || (Math.random() * Math.pow(10, 7)).toFixed(0);
148
+ const id = notice.id || (Math.random() * 10 ** 7).toFixed(0);
66
149
  // De-dupe on id
67
150
  if (!this.set.has(id)) {
151
+ const type = notice.type || NOTIFICATION_TYPE.INFO;
152
+ const isUrgent = type === NOTIFICATION_TYPE.WARNING || type === NOTIFICATION_TYPE.DANGER;
68
153
  // Add notice to the top of stack.
69
- this.setState({
70
- notices: [
71
- Object.assign(Object.assign({}, notice), { id }),
72
- ...this.state.notices,
73
- ],
154
+ this.setState((prevState)=>({
155
+ notices: [
156
+ {
157
+ ...notice,
158
+ id
159
+ },
160
+ ...prevState.notices
161
+ ]
162
+ }), ()=>{
163
+ // Update live region after state update
164
+ const announcement = `${notice.title} ${notice.description}`;
165
+ this.updateLiveRegion(announcement, isUrgent);
74
166
  });
75
167
  // set timeout for closing the notification.
76
168
  if (!notice.sticky) {
77
- this.timeouts[id] = setTimeout(() => this.remove(id), notice.duration || DEFAULT_DURATION);
169
+ this.timeouts[id] = setTimeout(()=>this.remove(id), notice.duration || DEFAULT_DURATION$1);
78
170
  }
79
171
  // Add id to the set.
80
172
  this.set.add(id);
81
173
  }
82
174
  return id;
83
- };
84
- /**
85
- * Handler for close button click.
86
- *
87
- * @param id
88
- */
89
- this.closeClickHandler = (id) => () => {
90
- this.remove(id);
91
- };
92
- /**
93
- * Pause notification when user is hovering over it.
94
- *
95
- * @param id
96
- */
97
- this.pause = (id) => () => {
98
- clearTimeout(this.timeouts[id]);
99
- };
100
- /**
101
- * Restart the removal of notification.
102
- *
103
- * @param id
104
- */
105
- this.resume = (id) => () => {
106
- const notice = this.state.notices.find(notice => notice.id === id);
107
- if (!notice.sticky) {
108
- this.timeouts[id] = setTimeout(() => this.remove(id), DEFAULT_DURATION);
175
+ }, /**
176
+ * Update live region content with clear-then-set pattern for reliable VoiceOver announcements.
177
+ *
178
+ * @param content - The text content to announce
179
+ * @param isAssertive - Whether to use assertive (alert) or polite (log) live region
180
+ */ this.updateLiveRegion = (content, isAssertive)=>{
181
+ const region = isAssertive ? this.assertiveRegionRef.current : this.politeRegionRef.current;
182
+ if (region) {
183
+ // Add content after delay
184
+ setTimeout(()=>{
185
+ if (region) {
186
+ region.textContent = content;
187
+ }
188
+ }, 150);
109
189
  }
110
- };
111
- }
112
- render() {
113
- return (_jsx(Container, { position: this.props.position, children: this.state.notices.map(notice => {
114
- const { id, title, description, leaving, type = NOTIFICATION_TYPE.INFO, buttonText, buttonClick, } = notice;
115
- return (_jsxs(Notice, Object.assign({}, notice, { position: this.props.position, className: leaving ? 'leave' : '', onMouseEnter: this.pause(id), onMouseLeave: this.resume(id), children: [_jsxs(IconContainer, { type: type, children: [type === NOTIFICATION_TYPE.INFO && _jsx(Info, {}), type === NOTIFICATION_TYPE.SUCCESS && _jsx(CheckCircle, {}), type === NOTIFICATION_TYPE.WARNING && _jsx(ReportProblem, {}), type === NOTIFICATION_TYPE.DANGER && _jsx(ErrorOutline, {})] }), _jsxs(FillParent, { children: [_jsxs(Title, { type: type, children: [_jsx(FillParent, { children: title }), _jsx(CloseButton, { onClick: this.closeClickHandler(id), children: _jsx(Close, {}) })] }), _jsx(Body, { children: description }), buttonText && (_jsx(Footer, { children: _jsx(ActionButton, { onClick: () => { buttonClick === null || buttonClick === void 0 ? void 0 : buttonClick(); }, children: buttonText }) }))] })] }), id));
116
- }) }));
190
+ }, /**
191
+ * Handler for close button click.
192
+ *
193
+ * @param id
194
+ */ this.closeClickHandler = (id)=>()=>{
195
+ this.remove(id);
196
+ }, /**
197
+ * Pause notification when user is hovering over it.
198
+ *
199
+ * @param id
200
+ */ this.pause = (id)=>()=>{
201
+ if (id && this.timeouts[id]) {
202
+ clearTimeout(this.timeouts[id]);
203
+ }
204
+ }, /**
205
+ * Restart the removal of notification.
206
+ *
207
+ * @param id
208
+ */ this.resume = (id)=>()=>{
209
+ const notice = this.state.notices.find((notice)=>notice.id === id);
210
+ if (!notice?.sticky && id && !this.timeouts[id]) {
211
+ this.timeouts[id] = setTimeout(()=>this.remove(id), DEFAULT_DURATION$1);
212
+ }
213
+ };
117
214
  }
118
215
  }
119
- export default NotificationManager;
120
- //# sourceMappingURL=NotificationManager.js.map
216
+
217
+ export { NotificationManager as default };
218
+ //# sourceMappingURL=NotificationManager.js.map